Python的地图和Haskell的fmap有什么区别?

Pro*_*mer 4 python haskell

我知道它们都是不同的语言,但它们两者基本上不一样吗?fmap在Functor上应用函数,而Python的map在iterable上应用函数.因此,如果两者之间存在任何差异,您能提供一些我们可以用Python的地图而不是Haskell的fmap(反之亦然)的例子吗?

Ale*_*ing 12

他们是完全不同的.

这两个函数在类似列表的事情上做了非常类似的事情,但这确实是相似之处的结束.将Haskell map与Python 进行比较可能更有用map,但fmap它的含义更为通用,而且意义相当不同.


在Haskell中,fmap是一种"提升"或"穿孔"操作.它需要一个函数a -> b并将其"提升"到函数中f a -> f b.类似列表的容器是一种可以"穿孔"的东西,但是比列表更多的东西是仿函数!

通过a进行映射Maybe a是非常有用和常见的,尽管有人可能认为这Maybe就像一个零或一个元素的列表.但是,请考虑函数是Haskell中的函子.你可以fmap通过一个函数并接收一个新函数,但函数显然不是迭代的.类似地,解析器组合库(如parsec)中的解析器是仿函数,您可以通过fmapping它们来生成新的解析器,以将函数应用于它们的结果.

各种各样的东西都是仿函数,其中很多都与容纳价值的容器关系不大.所有的单子都是仿函数,包括像Writer,State和Cont,这是effectful计算,就不一一列举状的东西.其他的东西也是仿函数,Const它们可以结合起来Lift形成一个单独收集错误的应用函子.

每个事物所做和所做的具体细节超出了这个问题的范围,但重点是Haskell的一个仿函数概念比一个"可迭代的东西"更为普遍,而且它通常以不同的方式使用Python的map.


然而,从另一个角度来看,可以说Python map比Haskell更强大fmap.普遍性需要成本,这需要简单.具体而言,您可以选择做更多的事情!这与Python与Haskell的其他差异(如动态类型和可变函数)相比,使得Python map可以执行Haskell fmap无法做到的事情.

正如Daniel Sanchez所指出的那样,Python map是可变参数,因此zipWith当提供多个迭代时,它就像在Haskell中一样:

>>> map(lambda x,y: x+y, range(10), range(10))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Run Code Online (Sandbox Code Playgroud)

不过还有一点.Python map也可以在不同类型的东西上运行.在Haskell中,Functor类的通用性很有用,主要是因为它可以编写对任何操作的函数,Functor这意味着所有Functor需要以大致相同的方式操作.f a如果你想使用容器类比,元素"内部"a 必须是类型a.

考虑这对于哈希映射或字典这样的含义.在Haskell中,Functors必须具有类型* -> *,因此Map只能Functor部分应用.因此,Map k有一个Functor实例,所以fmap只能操作a 的值Map.

在Python中,类型系统的后果并没有如此严格地强制执行,因此在迭代时,字典实际上充当其键的序列:

>>> map(None, {'foo': 1, 'bar': 2})
['foo', 'bar']
Run Code Online (Sandbox Code Playgroud)

哦,这个例子还演示了另一个Python奇怪的映射None,比如映射身份函数,但将它映射到多个事物就像Haskell一样,zip并产生元组:

>>> map(None, [1, 2, 3], [4, 5, 6])
[(1, 4), (2, 5), (3, 6)]
Run Code Online (Sandbox Code Playgroud)

最后,请注意Haskell fmap不能映射集!为什么是这样?嗯,刚性类型系统要求fmap适用于任何值,但Sets必须由具有Ord实例的类型的值组成.Python不需要跳过任何这样的箍,所以它可以映射就好了:

>>> map(None, {1, 2, 3})
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

Python和Haskell是非常不同的语言.很多这些差异只是语言差异的工件,而不一定是功能设计的差异.

尽管如此,核心差异很容易总结:Python map用于映射类似列表的东西,但Haskell fmap用于提升函数以对任意数据结构进行操作.即使你看过语言差异,这两件事情也是截然不同的,所以不要认为它们只是因为它们在表面上具有相同的形状.


Net*_*ave 3

Pythonmap有一种 Haskell 没有的行为:

map(lambda x,y: x+y, range(10), range(10))
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
Run Code Online (Sandbox Code Playgroud)

它的作用是迭代 n 个可迭代对象对,从它们中解压缩值并将它们作为参数传递给函数。实际上 Haskellmap由于其类型签名而无法做到这一点 fmap :: Functor f => (a -> b) -> f a -> f b

python 的map用法与 Haskell 类似zipWith:

Prelude> zipWith (\x y -> x+y) [1..10] [1..10]
[2,4,6,8,10,12,14,16,18,20]
Run Code Online (Sandbox Code Playgroud)