了解Haskell中的折痕

时间:2018-08-27 17:12:35

标签: haskell functional-programming fold binary-operators associativity

根据我对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"呢?

在了解foldlfoldr之间的区别时我缺少什么吗?

3 个答案:

答案 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时,两种排序结果相同。