【问题标题】:Is there any reason why foldr type signature differs from foldl one?foldr 类型签名与 foldl one 不同有什么原因吗?
【发布时间】:2018-10-02 17:10:32
【问题描述】:

与 foldr 相比,我对 foldl 的定义有点困惑。 Foldr 与 foldl 的区别不仅在于关联性,而且在于折叠函数参数顺序:

foldr :: (a -> b -> b) -> b -> [a] -> b
foldl :: (b -> a -> b) -> b -> [a] -> b

我看不出为什么不能这样定义 foldl:

foldl :: (a -> b -> b) -> b -> [a] -> b
foldl f acc [] = acc
foldl f acc (x:xs) = foldl f (f x acc) xs

因此 foldl 可以应用于非交换折叠函数以及 文件夹:

Prelude> foldr (:) [] [1..5]
[1,2,3,4,5]
Prelude> foldl (:) [] [1..5]
<interactive>:4:7: error:
<...>
Prelude> myfoldl (:) [] [1..5]
[5,4,3,2,1]

使用标准 foldl 定义,我们需要使用 flip 来获得与 foldr 相同的行为

【问题讨论】:

  • 参数的“翻转”实际上是合乎逻辑的:您可以将其视为折叠发生方式的“提示”。
  • 另外,如果你不小心使用了错误的版本,你会得到一个错误。

标签: haskell fold


【解决方案1】:

你会得到以下很好的等式属性:

foldl (+) z [a, b, c] = (((z + a) + b) + c)
foldr (+) z [a, b, c] = a + (b + (c + z))

【讨论】:

  • 在我看来并没有什么不同:myfoldl (+) z [a, b, c] = (c + (b + (a + z)))
  • @aryndin 这不是帖子中列出的任何东西。它可能看起来像,因为(+) 是可交换的,但大多数操作不是。
  • 你需要记住颠倒列表,这只是一点点知识,但仍然比现状多一点。
猜你喜欢
  • 2020-11-26
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 2015-01-08
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
相关资源
最近更新 更多