查看 Haskell 中的缩减步骤

发布于 2024-07-18 08:25:54 字数 91 浏览 6 评论 0原文

有没有办法查看haskell中的减少步骤,即跟踪所做的递归函数调用? 例如,chez 方案为我们提供了trace-lambda。 Haskell 中有等效的形式吗?

Is there any way to view the reduction steps in haskell, i.e trace the recursive function calls made? For example, chez scheme provides us with trace-lambda. Is there an equivalent form in Haskell?

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

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

发布评论

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

评论(4

夜雨飘雪 2024-07-25 08:25:54

您可以尝试插入 Debug.Trace.trace 在你想要跟踪的地方,但这有(a)产生严重无序输出的趋势,因为你的跟踪语句可能属于一个不是“的thunk” t 评估直到远离原始调用,并且 (b) 更改程序的运行时行为,如果跟踪需要评估本来不会评估的事物(尚未)。

这是为了调试吗? 如果是这样...


Hat 修改您的源代码以输出跟踪,可以在运行后查看。 输出应该非常接近你想要的:他们主页上的示例是

例如错误程序的计算

main = let xs :: [Int] 
             xs = [4*2,5 `div` 0,5+6] 
         打印中(头xs,最后'xs) 

  最后' (x:xs) = 最后' xs 
  最后'[x] = x 
  

给出结果

(8,模式不匹配。 
  

并且可以使用 Hat 查看工具来探索其行为,如下所示:

  • 帽子堆

对于中止的计算,即因错误消息而终止或被中断的计算,帽子堆栈显示计算在哪个函数调用中中止。 它通过显示函数调用(redexe)的虚拟堆栈来实现这一点。 因此,堆栈上显示的每个函数调用都会导致其上方的函数调用。 对顶部堆栈元素的评估导致了错误(或者在评估期间计算被中断)。 显示的堆栈是虚拟的,因为它与实际的运行时堆栈不对应。 实际的运行时堆栈支持惰性求值,而虚拟堆栈对应于用于急切(严格)求值的堆栈。

使用与上面相同的示例程序,hat-stack 显示

$ hat-stack 示例 
  程序因错误而终止: 
          模式中没有匹配项。 
  虚拟堆栈跟踪: 
  (Last.hs:6) 最后' [] 
  (Last.hs:6) 最后'[_] 
  (Last.hs:6) 最后' [_,_] 
  (Last.hs:4) 最后' [8,_,_] 
  (未知)主要 
  $ 
  

现在,GHCi (≥6.8.1) 还附带了一个调试器:

$ ghci -fbreak-on-exception
GHCi, version 6.10.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> :l Example.hs
[1 of 1] Compiling Main             ( Example.hs, interpreted )

Example.hs:5:0:
    Warning: Pattern match(es) are overlapped
             In the definition of `last'': last' [x] = ...
Ok, modules loaded: Main.
*Main> :trace main
(8,Stopped at <exception thrown>
_exception :: e = _
[<exception thrown>] *Main> :back
Logged breakpoint at Example.hs:(5,0)-(6,12)
_result :: t
[-1: Example.hs:(5,0)-(6,12)] *Main> :hist
-1  : last' (Example.hs:(5,0)-(6,12))
-2  : last' (Example.hs:5:15-22)
-3  : last' (Example.hs:(5,0)-(6,12))
-4  : last' (Example.hs:5:15-22)
-5  : last' (Example.hs:(5,0)-(6,12))
-6  : last' (Example.hs:5:15-22)
-7  : last' (Example.hs:(5,0)-(6,12))
-8  : main (Example.hs:3:25-32)
-9  : main (Example.hs:2:17-19)
-10 : main (Example.hs:2:16-34)
-11 : main (Example.hs:3:17-23)
-12 : main (Example.hs:3:10-33)
<end of history>
[-1: Example.hs:(5,0)-(6,12)] *Main> :force _result
*** Exception: Example.hs:(5,0)-(6,12): Non-exhaustive patterns in function last'

[-1: Example.hs:(5,0)-(6,12)] *Main> :back
Logged breakpoint at Example.hs:5:15-22
_result :: t
xs :: [t]
[-2: Example.hs:5:15-22] *Main> :force xs
xs = []

虽然不是那么好,但它的优点是易于使用,并且无需重新编译代码即可使用。

You could try inserting Debug.Trace.trace in places you want to trace, but this has the tendency of (a) producing wildly out-of-order output, as your trace statement may belong to a thunk that isn't evaluated until far far away from the original call, and (b) changing the runtime behavior of your program, if tracing requires evaluating things that wouldn't otherwise have been evaluated (yet).

Is this for debugging? If so...


Hat modifies your source code to output tracing which can be viewed after running. The output should be pretty close to what you want: the example on their homepage is

For example, the computation of the faulty program

main = let xs :: [Int]
           xs = [4*2,5 `div` 0,5+6]
       in  print (head xs,last' xs)

last' (x:xs) = last' xs
last' [x] = x

gives the result

(8, No match in pattern.

and the Hat viewing tools can be used to explore its behaviour as follows:

  • Hat-stack

For aborted computations, that is computations that terminated with an error message or were interrupted, hat-stack shows in which function call the computation was aborted. It does so by showing a virtual stack of function calls (redexes). Thus, every function call shown on the stack caused the function call above it. The evaluation of the top stack element caused the error (or during its evaluation the computation was interrupted). The stack shown is virtual, because it does not correspond to the actual runtime stack. The actual runtime stack enables lazy evaluation whereas the virtual stack corresponds to a stack that would be used for eager (strict) evaluation.

Using the same example program as above, hat-stack shows

$ hat-stack Example
Program terminated with error:
        No match in pattern.
Virtual stack trace:
(Last.hs:6)     last' []
(Last.hs:6)     last' [_]
(Last.hs:6)     last' [_,_]
(Last.hs:4)     last' [8,_,_]
(unknown)       main
$

These days, GHCi (≥6.8.1) also comes with a debugger:

$ ghci -fbreak-on-exception
GHCi, version 6.10.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> :l Example.hs
[1 of 1] Compiling Main             ( Example.hs, interpreted )

Example.hs:5:0:
    Warning: Pattern match(es) are overlapped
             In the definition of `last'': last' [x] = ...
Ok, modules loaded: Main.
*Main> :trace main
(8,Stopped at <exception thrown>
_exception :: e = _
[<exception thrown>] *Main> :back
Logged breakpoint at Example.hs:(5,0)-(6,12)
_result :: t
[-1: Example.hs:(5,0)-(6,12)] *Main> :hist
-1  : last' (Example.hs:(5,0)-(6,12))
-2  : last' (Example.hs:5:15-22)
-3  : last' (Example.hs:(5,0)-(6,12))
-4  : last' (Example.hs:5:15-22)
-5  : last' (Example.hs:(5,0)-(6,12))
-6  : last' (Example.hs:5:15-22)
-7  : last' (Example.hs:(5,0)-(6,12))
-8  : main (Example.hs:3:25-32)
-9  : main (Example.hs:2:17-19)
-10 : main (Example.hs:2:16-34)
-11 : main (Example.hs:3:17-23)
-12 : main (Example.hs:3:10-33)
<end of history>
[-1: Example.hs:(5,0)-(6,12)] *Main> :force _result
*** Exception: Example.hs:(5,0)-(6,12): Non-exhaustive patterns in function last'

[-1: Example.hs:(5,0)-(6,12)] *Main> :back
Logged breakpoint at Example.hs:5:15-22
_result :: t
xs :: [t]
[-2: Example.hs:5:15-22] *Main> :force xs
xs = []

While not as nice, it has the benefit of being easily available, and being usable without recompiling your code.

っ〆星空下的拥抱 2024-07-25 08:25:54

拥抱次数减少了,有帮助吗?
或者,您可以使用类似“hugs hood”之类的东西来包装您的代码,以获取有关它在每个步骤中执行的操作的更多详细信息吗?

There's a reduction count in hugs, if that helps?
Alternatively, could you use something like the hugs hood to wrap your code, to get more detail around what it's doing at each step?

带上头具痛哭 2024-07-25 08:25:54

Haskell 标准中没有内置任何此类内容。

我希望 Helium 图形解释器能够提供类似的东西但网页上对此主题只字未提。

Nothing of the kind is built into the Haskell standard.

I would hope that the Helium graphical interpreter would offer something like this, but the web page is silent on the topic.

何以心动 2024-07-25 08:25:54

部分解决方案是使用 vacuum 来可视化数据结构。

我看过一些折叠、扫描等的gif动画,但目前找不到。 我认为动画是凯尔·吉巴德制作的。

A partial solution is to use vacuum to visualize data structures.

I've seen some gif animations of fold, scan and others, but I can't find them at the moment. I think Cale Gibbard made the animations.

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