【问题标题】:Observing lazyness in Haskell在 Haskell 中观察惰性
【发布时间】:2013-11-22 08:23:50
【问题描述】:

是否可以编写一个 Haskell 函数,该函数取决于值是已经计算出来还是 thunk?例如。如果 lazyShow :: [Int] -> String 将 thunk 显示为 ? 并正常计算值,在 GHCi 中我们会看到

> let nats = [0..]

> lazyShow nats
0 : ?

> nats !! 5    
5

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

【问题讨论】:

    标签: haskell lazy-evaluation


    【解决方案1】:

    很明显,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 文档中的建议)明确调用垃圾收集器来清理视图。

    【讨论】:

      【解决方案2】:

      您可能有兴趣在 GHCi 中挖掘 ":sprint" 的实现,它具有查看 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,_,_,_,_,_]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-08-27
        • 2019-02-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多