fmap和Haskell的“平面地图”
所有这一次,当Haskell演讲中谈到“平面地图”时,通常就Monad而言,我认为它被称为“平坦”是有原因的,即它将容器弄平。 所以
[[1,2],[3,4]]
将被处理,就像它一样
[1,2,3,4]
但是现在我发现fmap和map基本上是一样的,唯一的区别是一个用于函子,另一个用于列表。 最后,这只是为了避免在使用地图时混淆错误消息。
真的吗? 如果是的话为什么fmap中的f
来表示“平坦”,为什么不是“函数图”?
如果是这样,为什么fmap
f
来表示“平坦”,为什么不是“函数图”?
你的直觉是对的: fmap
中的f
确实代表“函数图”,而不是“平面图”。 事实上,在较新的相似语言中,例如PureScript,其名称就是map
。 虽然Haskell map
首先被定义为列表,但想出一个新名字很困难。 使用Functor的F是一个简单的,如果不是特别有创意的选择。
讲师更可能指的是一元绑定函数>>=
。 由于x >>= f
与join (fmap fx)
的等价性,bind在其他语言中有时也被称为flatMap
。 它具有您期望的列表行为,例如:
> [1,2,3] >>= x -> [x,x]
[1,1,2,2,3,3]
尽管如此,请记住这一点很重要,即这个“平面图”不会递归地变成任意深度。 事实上,编写这样一个函数在Haskell中是不可能的,没有一些复杂的类型特技。 自己尝试: flatten
函数的类型签名会是什么样子,即使是直接在列表上运行的类型签名也是如此?
flatten :: ??? -> [a]
>>=
函数的比较非常简单:它与fmap
类似,但每个输出元素都必须包含在函子中,而>>=
将结果浅显地“扁平化”成单个包装。 这个操作是monad的本质,这就是为什么>>=
函数存在于Monad
类型类中,但fmap
在Functor
。
这个答案取自一些关于原始问题的评论,所以我已经标记为社区维基。 欢迎编辑和改进。
下面是一些如何在Haskell中做flatMap
明确的等价例子。
Prelude> map (replicate 3) [1..4]
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]]
Prelude> fmap (replicate 3) [1..4]
[[1,1,1],[2,2,2],[3,3,3],[4,4,4]]
Prelude> concat [[1,2],[3,4]]
[1,2,3,4]
Prelude> concat (map (replicate 3) [1..4])
[1,1,1,2,2,2,3,3,3,4,4,4]
Prelude> concat $ map (replicate 3) [1..4]
[1,1,1,2,2,2,3,3,3,4,4,4]
Prelude> concatMap (replicate 3) [1..4]
[1,1,1,2,2,2,3,3,3,4,4,4]
Prelude> replicate 3 `concatMap` [1..4]
[1,1,1,2,2,2,3,3,3,4,4,4]
Prelude> [1..4] >>= replicate 3
[1,1,1,2,2,2,3,3,3,4,4,4]
应该清楚的是, flatMap
首先映射然后是平坦的,然后将地图的输出变平,而不是扁平化您要处理的输入列表(这不是flatMap
,它没有名称,它只是一个平面然后映射)。