为什么我们有 map、fmap 和 liftM?

Why do we have map, fmap and liftM?

提问人:fredoverflow 提问时间:9/19/2011 更新时间:4/25/2019 访问量:10829

问:

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

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

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

为什么我们有三个不同的函数来做本质上相同的事情?

列出 Haskell Monads 冗余 函子

评论

33赞 luqui 9/19/2011
历史,主要是。fmap 与 map 不同于教学原因,liftM 不同于 fmap 出于历史原因(即 Functor 不是 Monad 的超类)
13赞 C. A. McCann 9/19/2011
哦,只是为了清楚起见:他们“本质上”不会做同样的事情。两者,并且肯定应该做 完全相同的事情。mapliftMfmap
3赞 Thorsten 12/5/2017
虽然和做完全相同的事情,当然只是它们的一种特例,即不同的东西。 类型良好,而不是。fmapliftMmapfmap id getLinemap id getLine

答:

96赞 li.davidm 9/19/2011 #1

map存在是为了简化对列表的操作,并出于历史原因(请参阅 Haskell 中的 map 有什么意义,当有 fmap 时?

你可能会问为什么我们需要一个单独的地图功能。为什么不干脆消除电流 仅列表映射功能,并将 fmap 重命名为映射?嗯,这是个好问题。这 通常的论点是,刚刚学习 Haskell 的人,如果错误地使用 map,会很 宁愿看到关于列表的错误,而不是关于函子的错误。

-- Typeclassopedia,第 20 页

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

事实上,我们同时拥有 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 中的地图有什么意义?

评论

14赞 C. A. McCann 9/19/2011
而且,从我的角度来看,作为一个在@augustss所描述的改变十多年后第一次遇到Haskell的人,并且花了很多时间帮助现在正在学习这门语言的人,目前还不清楚它是否以任何方式帮助。当然不足以抵消无用的冗余(这本身就会导致人们提出这样的问题);这门课太常见了,不容忽视,反正初学者经常被错误消息弄糊涂!Functor
14赞 Tarrasch 9/19/2011
我们不能直接删除吗?让代码破解,谁在乎呢,代码通常需要不到 2 天的时间才能在 github 上修复,然后在 hackage 上上传。还是我疯了?liftM
4赞 ivanm 9/19/2011
@Tarrasch:不是每个人都使用 github,也不是所有的软件包都有按时更新的良好记录,我倾向于在 do-block 中使用,而不是因为它更适合我使用 等等。liftMfmapliftM2
1赞 li.davidm 6/10/2012
@L01man人为此付出了努力;参见 stackoverflow.com/questions/5730270/... 至少对于数值类,还有其他选择:hackage.haskell.org/packages/archive/numeric-prelude/0.3.0.2/...
1赞 recursion.ninja 8/22/2014
@L01man 是的,这很快就会得到解决。应用单子提案 (AMP) 看起来将传递到下一个版本的 Haskell 中。GHC 7.8.3 有一个新标志,可帮助更新过渡的现有代码。--fwarn-amp