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


97

无论我已经尝试使用mapfmap已工作过。Haskell的创建者为什么感到需要map功能?难道这就是目前已知的名称fmapfmap可以从该语言中删除吗?


11
我想您是在问“ Haskell中fmap的意义是什么?”?
zw324 2011年

11
我知道重点fmap是什么。它将功能映射到Functor实例上。我想知道专门针对的目的map
克拉克·加贝尔

Answers:


95

我想回答一个问题,以引起人们对八月的评论的关注:

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

Haskell 98被某些Haskeller(包括我)视为倒退,以前的版本定义了一个更加抽象和一致的库。那好吧。


16
这些落后的步骤是否在任何地方收集和记录?看看还有什么被认为是后退一步,以及是否还有更好的解决方案也将很有趣。
达沃拉克2011年

3
map and fmap已经存在了很长时间-2006年8月在Haskell-prime邮件列表中重新加热-haskell.org/pipermail/haskell-prime/2006-August/thread.html。作为对策,我更喜欢现状。在我看来,Haskell的一个子集与Miranda大致对应似乎很有价值。在英国,Miranda被用作数学系学生的教学语言,而不仅仅是计算机科学系的学生。如果那种利基尚未被非功能性语言(例如Mathematica)所迷失,那么我看不到Haskell具有统一的功能map
斯蒂芬·泰特利2011年

35
我还要进一步指出,对于尚未认识到的人,八月是Lennart Augustsson,从所有实际目的出发,从Haskell成立之前就加入Haskell社区。Haskell的历史,因此所涉及的评论绝不是二手传闻!
CA McCann

3
Haskell Wiki上现在有Nitpicks页面,其中提到了此问题。
Alexey 2015年

有趣的是,此决定是出于教学原因而做出的,因为在学习Haskell时,我总是将fmap与flatmap混淆。他们应该已经建立了一个n00b焦点小组。:)
Danny Andrews


25

它们在应用程序站点上看起来相同,但是它们是不同的。当您将这两个函数mapfmap应用于值列表时,它们将产生相同的结果,但这并不意味着它们具有相同的用途。

运行GHCI会话(Glasgow Haskell编译器交互式)以查询有关这两个函数的信息,然后查看它们的实现,您会发现很多差异。

地图

查询GHCI以获取有关的信息 map

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

并且您将看到它被定义为适用于任何类型的值列表的高阶函数,a从而产生任何类型的值的列表b。尽管多态(上面的定义中的ab表示任何类型),该map函数都旨在应用于值列表,这只是Haskell中众多其他类型中的一种可能的数据类型。该map函数不能应用于不是值列表的内容。

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

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

它利用模式匹配将列表的头部(x)从xs列表的尾部()上拉下,然后使用:(cons)值构造函数构造一个新列表,使其前置f x(将其读为“应用于x的f”))到map尾递归直到列表为空。值得注意的是,该map函数的实现不依赖于任何其他函数,而仅依赖于自身。

fmap

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

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

这次fmap被定义为必须由那些希望属于Functor类型类的数据类型提供其实现的功能之一。这意味着不仅可以使用“值列表”数据类型,而且可以提供一种以上fmap功能的实现。这使得它fmap适用于更大的数据类型集:函子确实!

正如您可以从GHC.Base源代码中读取的那样,该fmap功能的可能实现是由Maybe数据类型提供的:

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

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

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

另一种可能的实现是列表数据类型提供的实现(当然!):

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

这取决于map功能。

结论

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

map  (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)
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.