弱头正常形式和评估顺序

时间:2014-04-26 15:59:59

标签: haskell stack-overflow lazy-evaluation strictness weak-head-normal-form

我读了很多关于弱头正常形式和seq的书。但我仍然难以想象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中,因为有一个需要完成的函数应用程序。在我们达到第二个参数的WHNF之前,我们是否可以保证在这里评估seq的第一个参数?

1 个答案:

答案 0 :(得分:7)

  • seq的第一个参数不能保证在第二个参数
    Not 保证之前进行评估,但是编译器会尝试并且通常会这样做防止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' xs为WHNF,而seq确保在a'为WHNF之前不会发生这种情况。