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+ 中,foldl
和 foldl'
都是根据 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。
在深入学习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+ 中,foldl
和 foldl'
都是根据 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。