waf*_*cat 3 stack-overflow haskell lazy-evaluation strictness weak-head-normal-form
我读过很多关于弱头正常形式和seq的书.但是我仍然无法想象Haskell评估顺序背后的逻辑
一个常见的例子说明何时以及如何使用,但我仍然不明白常见的例子
foldl (+) 0 [1..5000000]
Run Code Online (Sandbox Code Playgroud)
可能导致堆栈溢出.而使用另一种折叠定义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]
Run Code Online (Sandbox Code Playgroud)
从我读过的seq的解释,作者非常谨慎地做出如下清楚:
seq不能保证在第二个参数之前进行求值seq只会被评估为弱头正常形式seq只有当第二个参数被评估为WHNF时才会对第一个参数进行评估那么,如果以上是正确的(是吗?)那么为什么不foldl'溢出foldl呢?
当我们减少一步时,不应该看起来像这样,对吧?
foldl' (+) 0 (1:xs) = let a' = (+) 0 1 in a' `seq` foldl' (+) a' xs
Run Code Online (Sandbox Code Playgroud)
在上面,seq由于存在需要完成的功能应用,因此第二个参数不在WHNF中.seq在我们达到第二个参数的WHNF之前,我们是否可以保证评估此处的第一个参数?
第一个参数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' xs成为WHNF 的结果,才能seq确保在a'WHNF 之前不会发生这种情况.