为什么会有map,fmap和liftM?


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

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

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

为什么我们有三个功能基本相同的功能?


32
历史大部分。fmap与map出于教学原因不同,liftM与fmap因历史原因而不同(即Functor不是Monad的超类)
luqui 2011年

12
哦,只是为了清楚起见:他们“根本上”没有做同样的事情。两者mapliftM肯定应该做与完全相同的事情fmap
CA McCann

2
虽然fmapliftM做完全相同的事情,但是map当然只是它们的特例,即有所不同。fmap id getLine类型正确,但map id getLine不是。
Thorsten

Answers:


91

map存在是为了简化列表操作以及出于历史原因(请参见Hasfell中map的作用,当有fmap时?)。

您可能会问为什么我们需要一个单独的地图功能。为什么不取消当前的仅列表映射功能,而是将fmap重命名为map呢?好吧,这是一个好问题。通常的论点是,在不正确使用map的情况下,刚刚学习Haskell的人宁愿看到有关列表的错误,而不是有关Functors的错误。

- Typeclassopedia,第20页

fmapliftM存在,因为单子是不会自动在Haskell仿函数:

我们同时拥有fmap和liftM的事实是不幸的结果,因为Monad类型类不需要Functor实例,即使从数学上来讲,每个monad都是函子。但是,fmap和liftM本质上是可以互换的,因为将任何类型作为Monad的实例而不同时作为Functor的实例是一个错误(从社会角度而非技术角度)。

- Typeclassopedia,第33页

编辑:奥古斯都的历史mapfmap

这实际上不是怎么回事。发生的事情是,在Haskell 1.3中,地图的类型被概括为涵盖Functor。即,在Haskell 1.3中,fmap被称为map。然后在Haskell 1.4中还原了此更改,并引入了fmap。发生这种变化的原因是教学上的;当向初学者教授Haskell时,非常通用的地图类型使错误消息更难以理解。我认为这不是解决问题的正确方法。

- 如果有fmap,在Haskell中map的意义是什么?


13
而且,从我的角度来看,作为@augustss所描述的变更发生后的十多年中首次遇到Haskell的人,并花了很多时间来帮助现在正在学习该语言的人们,这还不是很清楚任何方式。当然,不足以抵消无用的冗余(它本身导致人们提出这样的问题);该Functor班是太普遍忽视,而新手往往被错误信息混淆呢!
CA McCann

10
我们不能删除liftM吗?让代码中断,谁在乎,通常在不到2天的时间内就可以将代码固定在github上,然后通过hackage上传。还是我疯狂又疯狂?
塔拉施

1
@Tarrasch:并不是每个人都使用github,并不是所有的软件包都具有良好的跟踪记录,可以及时更新,我倾向于liftM在一个do-block中使用fmap它,而不是因为它更适合我使用liftM2等等。也一样
ivanm 2011年

1
@ L01man人们已经为此工作;看到stackoverflow.com/questions/5730270/...至少对于数字类,也可以选择:hackage.haskell.org/packages/archive/numeric-prelude/0.3.0.2/...
li.davidm

1
@ L01man是的,这将很快得到解决。该应用型Monad的议案(AMP)看起来将进入哈斯克尔的下一个版本。GHC 7.8.3具有一个新标记--fwarn-amp,可帮助更新现有代码以进行过渡。
recursion.ninja 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.