看起来有很多功能可以做同样的事情,尤其是与Monads,Functors和Applicatives有关的功能.
示例(从大多数到最不通用):
fmap == liftA == liftM
(<*>) == ap
liftA[2345] == liftM[2345]
pure == return
(*>) == (>>)
Run Code Online (Sandbox Code Playgroud)
不直接基于FAM类树的示例:
fmap == map
Run Code Online (Sandbox Code Playgroud)
(我认为List,Foldable,Traversable还有很多,但看起来大部分时间都变得更通用了,因为我只看到旧堆栈溢出/留言板问题中旧的,不太通用的类型签名)
我个人觉得这很烦人,因为这意味着如果我需要做x,而某些函数如liftM允许我做x,那么我会使我的函数不那么通用,而且我只会去通过彻底推断类型之间的差异(例如FAM,或者可能是List,Foldable,Traversable组合)来注意那种事情,这对于初学者来说并不友好,因为简单地使用这些类型并不是那么难,关于他们的属性和法律的推理需要更多的心理努力.
我猜这些等价物很多都来自于申请Monad提案.如果这就是他们的原因(并且由于可用于混淆的通用功能较少而缺少其他原因),他们是否会被弃用/删除?由于破坏现有代码,我可以理解等待很长时间才能删除它们,但肯定会弃用是个好主意吗?
简短的答案是"历史"和"规律性".
最初"地图"是为列表定义的.然后引入类型类,使用Functor类型类,因此任何仿函数的"map"的通用版本必须被称为不同的东西,否则现有代码将被破坏.因此"fmap".
然后monad出现了.monads的实例不需要是仿函数,因此创建了"liftM",以及"liftM2","liftM3"等.当然,如果类型是Monad和Functor的实例,那么fmap = liftM.
Monads也有"ap",用于表达式f `ap` arg1 `ap` arg2.这非常方便,但随后添加了Applicative Functors.(<*>)为'app'做的应用函数做了同样的工作,但是因为许多应用函子不是monad所以它必须被称为不同的东西.同样,liftAx与liftMx相比,"pure"与"return"相同.