当列表包含零时,为什么 foldr 函数会给我一个否定的结果?
Why the foldr function gives me a negative result when the list contains a zero?
举个例子来说明我的意思
Prelude> foldr (-) 0 [0,1]
-1
我以为这里基本上可以0 - 0 = 0; 1 - 0 = 1;
但实际结果是-1
我用其他例子试过了
Prelude> foldr (-) 1 [1,3]
-1
Prelude> foldr (-) 1 [1,9]
-7
我可能误解了 foldr 的工作原理,所以我很乐意得到解释:)
尝试foldr (-) 0 [1, 2, 3, 4, 5]
。你应该得到 3
。那是因为折叠等同于 (1 - (2 - (3 - (4 - (5 - 0)))))
——它是从右边开始的。如果你尝试 foldl
,你应该得到 -15
。那是因为它是从左边开始的,相当于(((((0 - 1) - 2) - 3) - 4) - 5)
.
您的较短示例 foldr (-) 0 [0, 1]
等同于 0 - (1 - 0)
,后者缩减为 -1
。
考虑以下函数:
printfoldr f init xs = foldr (\el acc -> "(" ++ el ++ f ++ acc ++ ")") (show init) $ map show xs
此函数模拟 foldr
函数如何扩展和输出其字符串表示形式。
让我们运行进行一些测试:
λ> printfoldr "-" 0 [1,2,3,4]
"(1-(2-(3-(4-0))))"
-- the test cases you provided
λ> printfoldr "-" 0 [1,2]
"(1-(2-0))" -- This reduces to -1 which is the result you had
λ> printfoldr "-" 1 [1,3]
"(1-(3-1))" -- This reduces to -1 which is also the result you had
λ> printfoldr "-" 1 [1,9]
"(1-(9-1))" -- reduces -7 which is also correct
所以一般来说,foldr
类型 foldr :: (a -> b -> b) -> b -> t a -> b
的工作方式如下:
x0 `f` (x1 `f` ...(xn-2 `f` (xn-1 `f` (xn `f` init))))
其中 f
是 (a -> b -> b)
类型,x
是 a
类型,init
是 b
类型。
foldr
定义如下:
foldr f b [] = b
foldr f b (x:xs) = f x (foldr f b xs)
您递归地折叠列表的尾部,然后将 f
应用于头部和递归结果。请注意,基值用于序列的 end,而不是开头。
将其视为简单地将函数应用于一个接一个的值只有在 f
是关联的情况下才有效。例如,1 + (2 + (3 + 0)) == ((1+2) + 3) + 0
.
但是,减法 不 结合。一般来说,x - y - z
只等于(x - y) - z
,而不是x - (y - z)
。
举个例子来说明我的意思
Prelude> foldr (-) 0 [0,1]
-1
我以为这里基本上可以0 - 0 = 0; 1 - 0 = 1;
但实际结果是-1
我用其他例子试过了
Prelude> foldr (-) 1 [1,3]
-1
Prelude> foldr (-) 1 [1,9]
-7
我可能误解了 foldr 的工作原理,所以我很乐意得到解释:)
尝试foldr (-) 0 [1, 2, 3, 4, 5]
。你应该得到 3
。那是因为折叠等同于 (1 - (2 - (3 - (4 - (5 - 0)))))
——它是从右边开始的。如果你尝试 foldl
,你应该得到 -15
。那是因为它是从左边开始的,相当于(((((0 - 1) - 2) - 3) - 4) - 5)
.
您的较短示例 foldr (-) 0 [0, 1]
等同于 0 - (1 - 0)
,后者缩减为 -1
。
考虑以下函数:
printfoldr f init xs = foldr (\el acc -> "(" ++ el ++ f ++ acc ++ ")") (show init) $ map show xs
此函数模拟 foldr
函数如何扩展和输出其字符串表示形式。
让我们运行进行一些测试:
λ> printfoldr "-" 0 [1,2,3,4]
"(1-(2-(3-(4-0))))"
-- the test cases you provided
λ> printfoldr "-" 0 [1,2]
"(1-(2-0))" -- This reduces to -1 which is the result you had
λ> printfoldr "-" 1 [1,3]
"(1-(3-1))" -- This reduces to -1 which is also the result you had
λ> printfoldr "-" 1 [1,9]
"(1-(9-1))" -- reduces -7 which is also correct
所以一般来说,foldr
类型 foldr :: (a -> b -> b) -> b -> t a -> b
的工作方式如下:
x0 `f` (x1 `f` ...(xn-2 `f` (xn-1 `f` (xn `f` init))))
其中 f
是 (a -> b -> b)
类型,x
是 a
类型,init
是 b
类型。
foldr
定义如下:
foldr f b [] = b
foldr f b (x:xs) = f x (foldr f b xs)
您递归地折叠列表的尾部,然后将 f
应用于头部和递归结果。请注意,基值用于序列的 end,而不是开头。
将其视为简单地将函数应用于一个接一个的值只有在 f
是关联的情况下才有效。例如,1 + (2 + (3 + 0)) == ((1+2) + 3) + 0
.
减法 不 结合。一般来说,x - y - z
只等于(x - y) - z
,而不是x - (y - z)
。