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 is fmap?)。
你可能会问为什么我们需要一个单独的map函数。为什么不放弃当前仅列表映射函数,并将fmap重命名为map?嗯,这是一个很好的问题。通常的论点是,有人在学习Haskell时,如果错误地使用地图,则更倾向于看到关于列表的错误,而不是关于Functors的错误。
- Typeclassopedia,第20页
fmap
和liftM
之所以存在,是因为monads不是Haskell中的自动仿函数:
我们同时拥有fmap和liftM的事实是Monad类型类不需要Functor实例这一事实的不幸后果,即使从数学上讲,每个monad都是一个算子。但是,fmap和liftM本质上是可以互换的,因为它是一个bug(在社交而不是技术意义上),任何类型的Monad实例都不是Functor的实例。
- Typeclassopedia,第33页
编辑:agustuss的map
和fmap
的历史:
实际上并不是这样的。发生的事情是,地图的类型被概括为涵盖Haskell 1.3中的Functor。即,在Haskell 1.3中,fmap被称为map。然后在Haskell 1.4中恢复此更改并引入了fmap。这种变化的原因是教学法;在向初学者教授Haskell时,非常一般的地图类型使得错误消息更难以理解。在我看来,这不是解决问题的正确方法。