Haskell中的fmap和“flat map”

时间:2016-10-13 15:36:06

标签: haskell

所有这一次,当任何Haskell演讲谈到“平面地图”时,通常与Monads有关,我认为它被称为“平面”,原因是它平坦了容器。所以

[[1,2],[3,4]]

将被处理,就像它是

一样
[1,2,3,4]

但是现在我发现fmap和map基本上是一回事,唯一的区别是一个用于仿函数而另一个用于仅列表。最后,这只是在使用map时避免混淆错误消息。

这是真的吗?如果是这样,为什么fmap中的f意味着“平坦”,为什么不是“functor map”?

2 个答案:

答案 0 :(得分:27)

  

如果是这样,为什么ffmap的意思是“平坦的”,为什么不是“仿函数地图”呢?

你的直觉是正确的:f 中的fmap 代表“functor map”,而不是“flat map”。实际上,在较新的类似语言(如PureScript)中,名称只是map。 Haskell map首先是为列表定义的,所以提出一个新名称很困难。使用Functor中的F是一个简单的,即使不是特别有创意的选择。

讲师更可能是指monadic绑定函数>>=。由于x >>= fjoin (fmap f x)等效,因此在其他语言中,绑定有时也称为flatMap。它具有您在列表中所期望的行为,例如:

> [1,2,3] >>= \x -> [x,x]
[1,1,2,2,3,3]

重要的是要记住,这个“平面地图”不会递归地变平到任意深度。实际上,如果没有复杂的类型类技巧,在Haskell中编写这样的函数实际上是不可能的。自己尝试一下:flatten函数的类型签名是什么样的,即使是直接在列表上运行的呢?

flatten :: ??? -> [a]

>>=函数相比之下非常简单:它类似于fmap,但每个输出元素都必须包含在仿函数中,并且>>=将结果浅化“展平”为单包装。此操作是monad的本质,这就是>>=函数存在于Monad类型类中的原因,但fmap位于Functor中。

这个答案来自原始问题的一些评论,因此我将其标记为社区维基。欢迎编辑和改进。

答案 1 :(得分:1)

以下是一些如何在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 ,这没有名字,只是一个单位,然后是地图)。