在Haskell中查看视图简化步骤

15

有没有办法在Haskell中查看缩减步骤,即跟踪递归函数调用?例如,Chez Scheme为我们提供了trace-lambda。 Haskell中是否有类似的形式?


Scheme和Haskell之间存在巨大的区别;Haskell是惰性的,因此实际评估可能会在调用之后很长时间才发生。 - bortzmeyer
4个回答

8
您可以尝试在想要跟踪的位置插入Debug.Trace.trace,但这会有以下倾向:(a)产生非常混乱的输出,因为您的跟踪语句可能属于一个thunk,直到远离原始调用才被评估; (b)如果跟踪需要评估本来不会被评估的内容,则会更改程序的运行时行为。

这是用于调试吗? 如果是...


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

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
$
近年来,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 = []

虽然不够优美,但它的好处是易于获取,并且可以在不重新编译代码的情况下使用。

1

在拥抱中有一个减少计数,这有帮助吗? 或者,您可以使用拥抱外壳来包装您的代码,以便在每个步骤中获得更多详细信息。


0

这种功能并未内置于Haskell标准中。

我希望Helium图形解释器能够提供类似的功能,但网页上对此话题保持沉默。


0

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

我看过一些关于fold、scan和其他的gif动画,但现在找不到它们了。我想这些动画是由Cale Gibbard制作的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接