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

时间:2015-11-19 00:27:20

标签: performance haskell fold

在使用A tutorial on the universality and expressiveness of fold 深入研究fold时,我使用foldl找到了foldr的惊人定义:

-- 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

在这样的简单情况下,似乎它们都在恒定的空间中运行(而不是创建thunk):

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

我可以在性能方面考虑foldl'等效的两种定义吗?

1 个答案:

答案 0 :(得分:11)

在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