根据我对Haskell中的折痕的了解,foldl (-) 0 [1..5]
通过计算-15
得出0-1-2-3-4-5
的结果,而foldr (-) 0 [1..5]
得出-5
的结果为计算5-4-3-2-1-0
。那么为什么foldl (++) "" ["a", "b", "c"]
和foldr (++) "" ["a", "b", "c"]
都给出"abc"
的结果,而foldr
的结果却不是"cba"
呢?
在了解foldl
和foldr
之间的区别时我缺少什么吗?
答案 0 :(得分:12)
我认为this part from the docs更清晰:
对于列表,在应用于二进制运算符时,foldr,一个起始值(通常是该运算符的右标识)和一个列表,使用二进制运算符从右至左缩小列表:< / p>
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)
。 。
对于列表,在应用于二进制运算符时,foldl,一个起始值(通常是该运算符的左标识)和一个列表使用二进制运算符从左到右缩小列表:< / p>
foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn
如果您查看细分示例,则串联foldr
等效于:
"a" ++ ("b" ++ ("c" ++ ""))
对于foldl
,它等同于:
(("" ++ "a") ++ "b") ++ "c"
对于字符串连接,这些是相同的。
对于减法,
1 - (2 - (3 - 0))
给出与以下结果不同的结果:
((0 - 1) - 2) - 3
答案 1 :(得分:7)
实际上foldr (-) 0 [1..5]
等于3
,因为它是:
(1 - (2 - (3 - (4 - (5 - 0))))
这个问题的答案是foldr
函数的类型:
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
我们看到,(a -> b -> b)
函数的第一个参数是迭代元素,第二个参数是累加器。这就是使用foldr (++) "" ["a", "b", "c"]
的原因:
("a" ++ ("b" ++ ("c" ++ "")))
答案 2 :(得分:2)
0-1-2-3-4-5
本身被视为折叠的“翻译”,因此定义不明确。必须指定操作顺序 。
实际上,无论是哪个运营商,订单都是
foldl (-) 0 [1..5] = ((((0 - 1) - 2) - 3) - 4) - 5 -- = -15
foldr (-) 0 [1..5] = 1 - (2 - (3 - (4 - (5 - 0)))) -- = 3
对于(++)
,当使用""
代替0
时,两种排序结果相同。