查看 Haskell 中的缩减步骤

Posted

技术标签:

【中文标题】查看 Haskell 中的缩减步骤【英文标题】:View Reduction Steps in Haskell 【发布时间】:2010-10-22 10:43:03 【问题描述】:

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

【问题讨论】:

与Scheme有很大的不同; Haskell 是惰性的,因此实际评估可能在调用之后很久才发生。 【参考方案1】:

您可以尝试在要跟踪的位置插入 Debug.Trace.trace,但这有 (a) 产生大量无序输出的趋势,因为您的跟踪语句可能属于一个 thunk,直到远离原始调用,并且 (b) 更改程序的运行时行为,如果跟踪需要评估本来不会被评估的事物(还)。

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


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

例如错误程序的计算

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

给出结果

(8, No match in pattern.

帽子查看工具可用于探索其行为如下:

帽子堆栈

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

使用与上面相同的示例程序,帽子堆栈显示

$ 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
$

如今,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 = []

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

【讨论】:

【参考方案2】:

拥抱的次数会减少,如果这有帮助吗? 或者,您是否可以使用像 hugs hood 之类的东西来包装您的代码,以便更详细地了解它在每个步骤中所做的事情?

【讨论】:

【参考方案3】:

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

我希望Helium 图形解释器能提供类似的东西,但是网页没有提及这个话题。

【讨论】:

【参考方案4】:

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

我看过一些折叠、扫描和其他的 gif 动画,但我现在找不到它们。我认为是 Cale Gibbard 制作了动画。

【讨论】:

以上是关于查看 Haskell 中的缩减步骤的主要内容,如果未能解决你的问题,请参考以下文章

学习惯用 Haskell 的资源(eta 缩减、符号中缀运算符、库等)[关闭]

Haskell 中的并行“任何”或“全部”

重写Haskell树会离开函数,以便它给出计算步骤及其结果

Haskell入门篇三:递归

Haskell GLUT 库中的 ($=)(美元等于)运算符有啥作用?

Haskell 总结了通过树的所有路径