map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
liftM :: Monad m => (a -> b) -> m a -> m b
为什么我们有三个不同的功能做同样的事情?
map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
liftM :: Monad m => (a -> b) -> m a -> m b
为什么我们有三个不同的功能做同样的事情?
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 的历史map
and fmap
:
实际上并非如此。发生的事情是映射的类型被泛化为覆盖 Haskell 1.3 中的 Functor。即,在 Haskell 1.3 中 fmap 被称为 map。然后在 Haskell 1.4 中恢复了此更改并引入了 fmap。这种变化的原因是教学上的;在向初学者教授 Haskell 时,非常通用的 map 类型使错误消息更难理解。在我看来,这不是解决问题的正确方法。