【问题标题】:Define functions with foldl foldr用 foldl foldr 定义函数
【发布时间】:2016-11-05 06:31:51
【问题描述】:

我了解 foldl、foldr 的定义,但我对它们定义的函数有疑问。

例如带有 foldr 的地图:

map f []       = []
map f l   = foldr (\x xs -> f x : xs) [] l

我不明白(\x xs -> f x : xs)。是map函数,foldr取哪个?但是不应该是(\x xs -> f x : f xs),因为map f (x:xs) = f x : map f xs吗?

以 foldl 为例:

concat (x:xs) = x ++ concat xs

concat' xs = foldl (++) [] xs
concat'' xs = foldl (\ys y -> ys ++ y) [] xs

我当然理解(++),但(\ys y -> ys ++ y) 背后的逻辑是什么?是ys = []y = xs 吗? 因此,该函数将[] 视为ys,而yxs 的第一个元素,并将[]y? 连接起来。 具体例子:

concat'' [1,2,3] = foldl (\ys y -> ys ++ y) [] [1,2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [] [1]) [2,3]
=> foldl (\ys y -> ys ++ y) [1] [2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1] [2]) [3]
=> foldl (\ys y -> ys ++ y) [1,2] [3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1,2] [3]) []
=> foldl (\ys y -> ys ++ y) [1,2,3] []
=> [1,2,3]

另一件事:concat 只需要 1 个列表 xs,所以如果我想连接 2 个列表?

concat (x:xs) ys = x ++ concat xs ys
concat [1,2,3] [4,5,6] with foldl?

反向:

reverse (x:xs) = reverse xs ++ [x]

reverse'  l = foldl (\xs x -> [x] : xs) [] l
reverse'' l = foldr (\x xs -> xs ++ [x]) [] l

foldr 很直观(上面有问题),但是 foldl (\xs x -> [x] : xs) 的相反顺序背后是什么?这个foldl (\x xs -> xs ++ [x]) [] l 是错误的,不是吗?

非常感谢!

【问题讨论】:

  • 这是几个问题 - 首先观察 xs 已经 f 映射(查看 foldr 的定义以了解原因) (f xs 也不会像 f :: a -> bf :: [a] -> b' 那样被很好地键入,所以你需要识别 a ~ [a]
  • 请注意foldr f z [x1, x2, x3] = f x1 (f x2 (f x3 z)) 所以xs 已经被f 映射。
  • 第二个:只需注意foldl 将从左侧循环通过xs(再次查看定义)
  • 最后:这只是从左折叠与从右折叠之间的区别 - 只需尝试不同的实现并自己看看!

标签: haskell dictionary functional-programming fold


【解决方案1】:

代码

foldr (\x xs -> ...) end list

大概可以这样解读

  • 扫描整个list
  • 如果为空,则返回 end end
  • 否则:
    • x 成为手头的元素
    • xs 成为列表的其余部分,经过处理
    • 应用... 操作

强调的部分很关键。 xs 不是列表的其余部分,而是对其进行“递归调用”的结果。

确实,xs 是个坏名字。在一般情况下,它甚至不是一个列表!例如。一个人永远不会写(愚蠢的例子)

foldr (\x xs -> x + xs) 0 [1..100]  -- sum 1..100

但更喜欢类似的东西

foldr (\x partialSum -> x + partialSum) 0 [1..100]  -- sum 1..100

(实际上,使用foldr 不会求和,但我们先把它放在一边。)

所以,就这样读吧:

map f l   = foldr (\x mappedTail -> f x : mappedTail) [] l

【讨论】:

  • 谢谢!我想我了解foldr。带有 foldl 的地图会是这样的吗? map f l = foldl (\x xs -> x : f xs) [] l 所以x 是映射的部分,xs 是映射的?
  • @user22709 在道德上是的,但请注意,在这种情况下,x 是一个(映射的)列表,xs 是一个元素,所以它应该是 foldl (\x xs -> x ++ [f xs]) [] list
  • 谢谢!你有什么更优雅的写法的建议吗,因为 xs 通常是列表的其余部分,这里不是这种情况......
  • @user22709 实际上,我会避免 foldl ,因为众所周知,在末尾追加 .. ++ [..] 效率低下。如果您仍然想要,只需为x,xs 选择一些合理的名称。
猜你喜欢
  • 2019-04-03
  • 2010-09-27
  • 2018-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-05
  • 2011-08-28
  • 2015-01-08
相关资源
最近更新 更多