【问题标题】:Why the foldr function gives me a negative result when the list contains a zero?当列表包含零时,为什么 foldr 函数会给我一个否定的结果?
【发布时间】:2021-12-09 15:14:38
【问题描述】:

这里有一个例子来说明我的意思

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 的工作原理,所以我很乐意解释一下 :)

【问题讨论】:

标签: haskell fold


【解决方案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 的类型为ainit 的类型为b

【讨论】:

    【解决方案2】:

    试试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

    【讨论】:

    • 非常感谢,我想我现在就去吧?
    【解决方案3】:

    foldr定义如下:

    foldr f b [] = b
    foldr f b (x:xs) = f x (foldr f b xs)
    

    您递归折叠列表的尾部,然后将f 应用于头部和递归结果。请注意,基值用于序列的结尾,而不是开头。

    仅当f 具有关联性时,将其视为简单地将函数应用于一个又一个值。例如,1 + (2 + (3 + 0)) == ((1+2) + 3) + 0

    但是,减法不是关联的。一般情况下,x - y - z 只等于(x - y) - z,而不是x - (y - z)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-26
      • 2013-02-22
      • 2013-10-01
      • 1970-01-01
      • 2020-08-22
      • 1970-01-01
      相关资源
      最近更新 更多