Haskell - foldl' 在 foldr 和性能问题方面

Haskell - foldl' in terms of foldr and performance issues

在深入学习fold的同时关于fold的普遍性和表现力的教程 我使用 foldr:

找到了 foldl 的惊人定义
-- I used one lambda function inside another only to improve reading
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f z xs = foldr (\x g -> (\a -> g (f a x))) id xs z

明白是怎么回事后,我想我什至可以用foldr来定义foldl',这样就可以了:

foldl' :: (b -> a -> b) -> b -> [a] -> b
foldl' f z xs = foldr (\x g -> (\a -> let z' = a `f` x in z' `seq` g z')) id xs z

与此平行的是:

foldl' :: (b -> a -> b) -> b -> [a] -> b
foldl' f z (x:xs) = let z' = z `f` x 
                    in seq z' $ foldl' f z' xs 
foldl' _ z _     = z

在像这样的简单情况下,它们似乎都是 运行 常量 space(不创建 thunk):

*Main> foldl' (+) 0 [1..1000000]
500000500000

我可以认为 foldl' 的两个定义在性能方面是等价的吗?

在 GHC 7.10+ 中,foldlfoldl' 都是根据 foldr 定义的。以前没有的原因是 GHC 没有优化 foldr 定义,不足以参与 foldr/build 融合。但是 GHC 7.10 引入了一个新的优化,专门允许 foldr/build 融合在使用 foldl'foldl' 那样定义的情况下成功。

这里最大的好处是像 foldl' (+) 0 [1..10] 这样的表达式可以优化到根本不分配 (:) 构造函数。我们都知道,绝对最快的垃圾收集是在没有垃圾可收集的时候。

有关 GHC 7.10 中新优化的信息及其必要性,请参阅 http://www.joachim-breitner.de/publications/CallArity-TFP.pdf