2013-11-22 50 views
10

是否可以编写一个Haskell函数,取决于值是已经计算好还是为thunk?例如。如果lazyShow :: [Int] -> String显示的thunk为?和计算值正常,在GHCI我们会看到观察Haskell的懒惰

> let nats = [0..] 

> lazyShow nats 
0 : ? 

> nats !! 5  
5 

> lazyShow nats 
0 : 1 : 2 : 3 : 4 : ? 

回答

15

显然,lazyShow不能有你的状态类型。如果字符串应该取决于当前的评估状态,那么IO String因此是您所期望的最好的。

如果你对此感兴趣的是使用它进行调试,那么我认为ghc-heap-view包(以及潜在的图形前端,例如ghc-vis)可用于此目的。它定义了一个GHCi命令:printHeap,它可以用来显示值在GHC堆中的外观。这或许有点多级低比你预期什么,但它可以更好地了解评估和共享工作如何偷懒非常有用:

Prelude> let nats = [0..] 
Prelude> :printHeap nats 
(_bco (D:Enum _fun _fun _fun _fun _fun _fun _fun _fun) _fun)() 
Prelude> null nats 
False 
Prelude> System.Mem.performGC 
Prelude> :printHeap nats 
let x1 = S# 0 
in x1 : _thunk x1 (S# 1) 
Prelude> nats !! 5 
5 
Prelude> System.Mem.performGC 
Prelude> :printHeap nats 
let x1 = S# 5 
in S# 0 : S# 1 : S# 2 : S# 3 : S# 4 : x1 : _thunk x1 (S# 1) 

我显式调用通过System.Mem.performGC(垃圾收集器的推荐ghc-heap-view的文档)来清理视图。

5

您可能会感兴趣挖执行“:冲刺”,在ghci中,其中有寻找到的thunk能力:

> let a = map (+1) [1..10] 
> :sprint a 
a = _ 

> length a 
10 

> :sprint a 
a = [_,_,_,_,_,_,_,_,_,_] 

> take 5 a 
[2,3,4,5,6] 

> :sprint a 
a = [2,3,4,5,6,_,_,_,_,_]