我读了很多关于弱头正常形式和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
的第一个参数?
答案 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之前不会发生这种情况。