3

我已经阅读了很多关于弱头正常形式和序列的内容。但是我仍然无法想象 Haskell 评估顺序背后的逻辑

演示何时以及如何使用的常见示例,但我仍然不明白常见示例如何

foldl (+) 0 [1..5000000]

可能导致堆栈溢出。而另一个折叠定义使用seq

foldl' _ a [] = a
foldl' f a (x:xs) = let a' = f a x in a' `seq` foldl' f a' xs
foldl' (+) 0 [0..5000000]

从我读过的对 seq 的解释中,作者非常小心地阐明了以下内容:

  • 的第一个参数seq不能保证在第二个参数之前被评估
  • 的第一个参数seq只会被评估为弱头范式
  • 的第一个参数的评估seq只会在第二个评估为 WHNF 时发生

那么,如果以上是正确的(是吗?)那么为什么不foldl'溢出foldl呢?

当我们减少一个步骤时,它不应该是这样的吧?

foldl' (+) 0 (1:xs) = let a' = (+) 0 1 in a' `seq` foldl' (+) a' xs

在上面,第二个参数seq不在 WHNF 中,因为需要完成一个函数应用程序。seq我们是否保证在到达第二个参数的 WHNF 之前评估这里的第一个参数?

4

1 回答 1

7
  • 的第一个参数seq不能保证在第二个参数之前被评估
    保证,但如果它防止 thunk 堆积,编译器会尝试并且通常会这样做。这不能很好地工作的场景是并行性,因此需要pseq- 但这foldl'并不相关。
  • 的第一个参数seq只会被评估为弱头范式
    是的,但是对于内置数字类型 WHNF = NF。
  • 的第一个参数的评估seq只会在第二个评估为 WHNF 时发生
    确实,这常常会引起混乱。但是in a' `seq` foldl' f a' xs意味着,如果您请求任何结果,它将触发seq.
    当我们减少一个步骤时,它不应该是这样的吧?... 的第二个参数seq 不在 WHNF 中
    正是这迫使seq,因为要评估结果,foldl' (+) 0 (1:xs)您需要foldl' (+) a' xsWHNF,并seq确保在 WHNF 之前不会发生这种情况a'
于 2014-04-26T16:20:36.393 回答