foldl
和foldr
的区别只是循环方向吗?我认为它们所做的事情不仅仅是在不同方向上循环有区别吧?
foldr (-) 0 [1..10] = -5
但是 foldl (-) 0 [1..10] = -55
。1-(2-(3-(4-(5-(6-(7-(8-(9-(10 - 0)))))))))
,而后者是 (((((((((0-1)-2)-3)-4)-5)-6)-7)-8)-9)-10
。(+)
是可结合的(无论以哪种顺序添加子表达式都无所谓),foldr (+) 0 [1..10] = 55
并且 foldl (+) 0 [1..10] = 55
。 (++)
是另一个可结合的操作,因为 xs ++ (ys ++ zs)
的答案与 (xs ++ ys) ++ zs
相同(尽管第一个更快 - 不要使用 foldl (++)
)。foldr (:) :: [a] -> [a] -> [a]
,但 foldl (:)
则没有意义。f
使用真正不同的数据对进行调用:foldr
通常更适合惰性求值,因此可以与无限列表一起使用,只要f
在第二个参数中是非严格的(例如(:)
或(++)
)。 foldl
很少是更好的选择。如果您正在使用foldl
,通常值得使用foldl'
,因为它是严格的并防止生成大量的中间结果。(有关此主题的更多信息,请参见此问题的答案。)foldl
永远无法返回结果,而foldr
则可以(如果给定了第二个参数中非严格的函数,比如(:)
或 const
,...)。 - luquifoldr
相比,foldl
的参数顺序被颠倒。因此所有函数都可以双向工作:foldl (flip (:))
仍然可以通过类型检查。 - nponeccop(:) :: a->[a]->[a]
或 flip (:) :: [a]->a->[a]
的 不对称性,这决定了唯一可能的组合顺序。[2] scanl
介于 foldl
和 foldr
之间,将“从左侧循环”与尽早停止的可能性相结合。 - Will Nessfoldr (:) "!" "Hello"
的结果为 "Hello!"
,而 foldl (flip (:)) "!" "Hello"
的结果为 "olleH!"
。 - AndrewC
foldl
的函数将结果与列表元素类型组合,而适用于foldr
的函数将列表元素类型与结果组合。 - Will Nessfoldr f
不一定要是foldl (flip f)
。 - AndrewC