107
map :: (a -> b) -> [a] -> [b]

fmap :: Functor f => (a -> b) -> f a -> f b

liftM :: Monad m => (a -> b) -> m a -> m b

为什么我们有三个不同的功能做同样的事情?

4

1 回答 1

95

map存在是为了简化对列表的操作并且出于历史原因(请参阅What's the point of map in Haskell, when there are fmap?)。

你可能会问为什么我们需要一个单独的 map 函数。为什么不直接取消当前的仅列表映射函数,而是将 fmap 重命名为 map 呢?嗯,这是个好问题。通常的论点是,刚学习 Haskell 的人在错误地使用 map 时,宁愿看到有关列表的错误,也不愿看到有关 Functor 的错误。

——Typeclassopedia ,第 20

fmap并且liftM存在是因为 monad 在 Haskell 中不是自动函子:

我们同时拥有 fmap 和 liftM 的事实是 Monad 类型类不需要 Functor 实例这一事实的不幸结果,即使从数学上讲,每个 monad 都是一个 functor。然而,fmap 和 liftM 本质上是可以互换的,因为它是一个错误(在社会而不是技术意义上)任何类型成为 Monad 的实例而不是 Functor 的实例。

-- Typeclassopedia,第 33 页

编辑: agustuss 的历史mapand fmap

实际上并非如此。发生的事情是映射的类型被泛化为覆盖 Haskell 1.3 中的 Functor。即,在 Haskell 1.3 中 fmap 被称为 map。然后在 Haskell 1.4 中恢复了此更改并引入了 fmap。这种变化的原因是教学上的;在向初学者教授 Haskell 时,非常通用的 map 类型使错误消息更难理解。在我看来,这不是解决问题的正确方法。

--当有 fmap 时,Haskell 中的 map 有什么意义?

于 2011-09-18T18:40:39.510 回答