当有fmap的时候,Haskell的地图有什么意义呢?

到处都试过用mapfmap也起作用了。 为什么Haskell的创build者觉得需要一个map函数? 难道这不就是目前所知的fmapfmap可以从语言中删除吗?

我想作出回应,提请注意上面的8月份的评论:

实际上并不是这种情况。 发生了什么事情是,地图的types被推广到Haskell 1.3中的Functor。 也就是说,在Haskell 1.3 fmap被称为map。 然后在Haskell 1.4中恢复了这个变化,引入了fmap。 这种变化的原因是教学法; 在向初学者教授Haskell时,一般的地图types使错误信息更难以理解。 我认为这不是解决问题的正确方法。

Haskell 98被一些Haskellers(包括我)看作是一个倒退,以前的版本已经定义了一个更抽象和更一致的库。 好吧。

Functor文档引用https://wiki.haskell.org/Typeclassopedia#Functor

你可能会问为什么我们需要一个单独的mapfunction。 为什么不直接抛弃当前仅用于列表的map函数,而是将fmap重命名为map呢? 那么,这是一个很好的问题。 通常的观点是,有人刚刚学习Haskell时,错误地使用map ,而不是关于Functor看到关于列表的错误。

他们在应用程序网站上看起来是一样的,但是当然它们是不同的。 当你将这两个函数( mapfmap )应用到值列表中时,它们会产生相同的结果,但这并不意味着它们是为了相同的目的。

运行GHCI会话(格拉斯哥Haskell编译器交互)来查询有关这两个函数的信息,然后查看它们的实现,你会发现许多不同之处。

地图

查询GHCI以获取有关map信息

 Prelude> :info map map :: (a -> b) -> [a] -> [b] -- Defined in 'GHC.Base' 

你会看到它被定义为一个高阶函数,适用于任何types的值列表,产生任何types的值列表b 。 虽然多态(上述定义中的ab代表任何types),但是map函数是用来应用于Haskell中许多其他数据types的值列表map函数不能应用于不是值列表的东西。

正如您可以从GHC.Base源代码读取的那样 , map函数的实现如下

 map _ [] = [] map f (x:xs) = fx : map f xs 

它使用模式匹配将头部( x )从列表的尾部( xs )中拉出来,然后使用: (cons)值构造函数构造一个新列表,以便将fx前缀(读作“f应用到x“ )到尾部map的recursion,直到列表为空。 值得注意的是map函数的实现不依赖于任何其他函数,而仅仅依赖于它本身。

FMAP

现在尝试查询有关fmap信息,您将看到完全不同的内容。

 Prelude> :info fmap class Functor (f :: * -> *) where fmap :: (a -> b) -> fa -> fb ... -- Defined in 'GHC.Base' 

这一次, fmap被定义为其实现必须由那些希望属于Functortypes类的数据types提供的函数之一。 这意味着可以有多个数据types,不仅仅是“值列表”数据types,能够为fmap函数提供一个实现。 这使得fmap适用于更大的一组数据types: fmap

正如您可以从GHC.Base源代码读取的那样 , fmap函数的一个可能的实现是由Maybe数据types提供的:

 instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (fa) 

另一种可能的实现是2元组数据types提供的实现

 instance Functor ((,) a) where fmap f (x,y) = (x, fy) 

而另一个可能的实现是由列表数据types(当然!)提供的实现:

 instance Functor [] where fmap f xs = map f xs 

它依赖于map函数(注意那里没有点符号…但是这不在你原来的问题范围之内)。

结论

map函数可以应用于任何types的值列表(其中值是任何types),而fmap函数可以应用更多的数据types:属于函子类的所有属性(例如,maybes,元组,列表,等等。)。 由于“值列表”数据types也是一个函子(因为它为它提供了一个实现),所以fmap也可以应用于生成与map完全相同的结果。

 map (+3) [1..5] fmap (+3) (Just 15) fmap (+3) (5, 7)