foldl
和foldr
只是循环的方向之间的区别?我认为他们所做的事情有所不同,而不仅仅是方向?
1 回答
如果您的函数不是关联的(即,括号表达式的方式很重要),例如,
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 (:)
是无稽之谈。
看看 Cale Gibbard 的图表(来自维基百科文章);你可以看到f
被真正不同的数据对调用:
另一个区别是,因为它匹配列表的结构,foldr
对于惰性求值通常更有效,因此可以与无限列表一起使用,只要f
它的第二个参数是非严格的(如(:)
or (++)
)。foldl
很少是更好的选择。如果您正在使用foldl
它通常值得使用foldl'
,因为它很严格并且阻止您建立一长串中间结果。(有关此主题的更多信息,请参阅此问题的答案。)