ghci 显示执行堆栈

发布于 2024-09-09 18:27:00 字数 232 浏览 8 评论 0原文

因此,我正在完成 Real World Haskell 的一些初始章节练习,我想知道 GHCi 中是否有一个选项可以使其在每个递归调用上显示带有参数的函数评估。例如,我编写了一个简单版本的“map”,当我应用它时,我希望 GHCi 显示带有实际参数的每个递归调用(希望还有表达式结果)。让我能够追踪幕后发生的事情的东西。

PS 当我写这篇文章时,我有一种感觉,它可能受到 haskell 执行模型的惰性的限制,如果我错了,请纠正我。

So I'm working through some initial chapter exercise of Real World Haskell and I wanted to know if there is an option in GHCi to make it show function evaluation with parameters on each recursive call. So for example I wrote a simple version of 'map', and when I apply it, I would like GHCi to display each recursive call with actual arguments (and hopefully expression results). Something which allows me to follow whats going on behind the scenes.

P.S. As I write this I have a feeling it may be limited by the laziness of haskell's execution model, correct me if I'm wrong.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

悲凉≈ 2024-09-16 18:27:01

您可以使用 hood 来实现此目的:

import Debug.Hood.Observe

map2 f [] = []
map2 f (x:xs) = f x : (observe "map2" $ map2) f xs

main = runO $ print $ map2 (+1) ([1..10] :: [Int])

当您运行它时,它将打印对 map2 的每个调用以及相应的参数和返回的结果。您会看到类似以下内容:

.
.
.
-- map2
{ \ { \ 10  -> 11
    , \ 9  -> 10
    } (9 : 10 : []) 
    -> 10 : 11 : []
}
-- map2
{ \ { \ 10  -> 11
    } (10 : []) 
    -> 11 : []
}
-- map2
{ \ _ []  -> []
}

有关更多信息,请查看示例

You can use hood for this:

import Debug.Hood.Observe

map2 f [] = []
map2 f (x:xs) = f x : (observe "map2" $ map2) f xs

main = runO $ print $ map2 (+1) ([1..10] :: [Int])

When you run it, it will print each call to map2 with the corresponding arguments and the result that was returned. You'll see something like:

.
.
.
-- map2
{ \ { \ 10  -> 11
    , \ 9  -> 10
    } (9 : 10 : []) 
    -> 10 : 11 : []
}
-- map2
{ \ { \ 10  -> 11
    } (10 : []) 
    -> 11 : []
}
-- map2
{ \ _ []  -> []
}

For more check the examples.

白衬杉格子梦 2024-09-16 18:27:01

我通常使用 调试.Trace

import Debug.Trace

buggy acc xs | traceShow (acc,xs) False = undefined
buggy acc []     = acc
buggy acc (x:xs) = buggy (acc + x) xs

main = print $ buggy 0 [1..10]

这让我看到了有缺陷的函数是如何工作的:

(0,[1,2,3,4,5,6,7,8,9,10])
(1,[2,3,4,5,6,7,8,9,10])
(3,[3,4,5,6,7,8,9,10])
(6,[4,5,6,7,8,9,10])
(10,[5,6,7,8,9,10])
(15,[6,7,8,9,10])
(21,[7,8,9,10])
(28,[8,9,10])
(36,[9,10])
(45,[10])
(55,[])
55

关键是有一个从不匹配的模式,但在不匹配时打印一些东西。这样它总是会被评估(并因此打印调试信息),并且很容易附加到任何函数。但是,如果您只想查看某些情况,也可以使其匹配,例如:

buggy acc [] = acc
buggy acc (x:xs) | traceShow (acc, x, xs) True = buggy (acc + x) xs

然后您只能在非基本情况下获得调试输出:

(0,1,[2,3,4,5,6,7,8,9,10])
(1,2,[3,4,5,6,7,8,9,10])
(3,3,[4,5,6,7,8,9,10])
(6,4,[5,6,7,8,9,10])
(10,5,[6,7,8,9,10])
(15,6,[7,8,9,10])
(21,7,[8,9,10])
(28,8,[9,10])
(36,9,[10])
(45,10,[])
55

YMMV。

I typically use Debug.Trace:

import Debug.Trace

buggy acc xs | traceShow (acc,xs) False = undefined
buggy acc []     = acc
buggy acc (x:xs) = buggy (acc + x) xs

main = print $ buggy 0 [1..10]

This lets me see how the buggy function works:

(0,[1,2,3,4,5,6,7,8,9,10])
(1,[2,3,4,5,6,7,8,9,10])
(3,[3,4,5,6,7,8,9,10])
(6,[4,5,6,7,8,9,10])
(10,[5,6,7,8,9,10])
(15,[6,7,8,9,10])
(21,[7,8,9,10])
(28,[8,9,10])
(36,[9,10])
(45,[10])
(55,[])
55

The key is having a pattern that never matches, but prints something while it's not matching. That way it always gets evaluated (and hence prints the debugging information), and it's easy to tack on to any function. But you can also make it match if you only want to see certain cases, like:

buggy acc [] = acc
buggy acc (x:xs) | traceShow (acc, x, xs) True = buggy (acc + x) xs

Then you only get debugging output at the non-base-case:

(0,1,[2,3,4,5,6,7,8,9,10])
(1,2,[3,4,5,6,7,8,9,10])
(3,3,[4,5,6,7,8,9,10])
(6,4,[5,6,7,8,9,10])
(10,5,[6,7,8,9,10])
(15,6,[7,8,9,10])
(21,7,[8,9,10])
(28,8,[9,10])
(36,9,[10])
(45,10,[])
55

YMMV.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文