66

foldlfoldr只是循环的方向之间的区别?我认为他们所做的事情有所不同,而不仅仅是方向?

4

1 回答 1

129

如果您的函数不是关联的(即,括号表达式的方式很重要),例如,
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',因为它很严格并且阻止您建立一长串中间结果。(有关此主题的更多信息,请参阅此问题的答案。)

于 2012-11-07T23:37:50.923 回答