Haskell有两个左侧折叠函数用于列表:foldl
和“严格”版本foldl'
。非严格foldl
的问题在于它构建了一个thunk的塔:
foldl (+) 0 [1..5]
--> ((((0 + 1) + 2) + 3) + 4) + 5
--> 15
这会浪费内存,如果列表中的项目太多,可能会导致堆栈溢出。另一方面,foldl'
强制累加器在每个项目上。
但是,据我所知,foldl'
在语义上等效于到foldl
。评估foldl (+) 0 [1..5]
以达到正常形式需要在某个时刻强制累加器。如果我们不需要头部正常形式,我们就不会开始评估foldl (+) 0 [1..5]
。
是否有任何令人信服的理由要求foldl
的行为超过foldl'
的行为?
答案 0 :(得分:25)
foldl
和foldl'
在语义上不相同。琐碎的反例:
Prelude Data.List> foldl (\x y -> y) 0 [undefined, 1]
1
Prelude Data.List> foldl' (\x y -> y) 0 [undefined, 1]
*** Exception: Prelude.undefined
但是,在实践中,由于您提到的原因,您通常需要严格的foldl'
。
答案 1 :(得分:13)
当foldl
和foldl'
不会产生相同的结果时,如在hammar的例子中,必须根据所需的结果做出决定。除此之外,如果折叠函数是构造函数,则使用foldl
而不是foldl'
(应用构造函数在WHNF中创建一个值,再次强制它到WHNF没有意义),并且foldl (.) id functions
迫使WHNF也没有获得任何收益。除了这些例外情况,foldl'
是首选方法。