无论我已经尝试使用map,fmap已工作过.为什么Haskell的创建者觉得需要一个map函数?难道它不仅仅是目前已知的fmap并且fmap可以从语言中删除吗?
luq*_*qui 89
我想回答一下提请注意奥古斯都的评论:
实际上并不是这样的.发生的事情是,地图的类型被概括为涵盖Haskell 1.3中的Functor.即,在Haskell 1.3中,fmap被称为map.然后在Haskell 1.4中恢复此更改并引入了fmap.这种变化的原因是教学法; 在向初学者教授Haskell时,非常一般的地图类型使得错误消息更难以理解.在我看来,这不是解决问题的正确方法.
Haskell 98被一些Haskellers(包括我)看作是一个倒退,以前的版本定义了一个更抽象和一致的库.那好吧.
And*_*tan 27
引自https://wiki.haskell.org/Typeclassopedia#Functor的Functor文档
你可能会问为什么我们需要一个单独的
map功能.为什么不取消当前的仅列表map功能, 而是重命名fmap为map?嗯,这是一个很好的问题.通常的论点是,只是学习Haskell的人,在使用map不正确时,更愿意看到关于列表的错误而不是关于Functor.
Pao*_*tti 17
它们在应用程序站点上看起来一样,但它们当然是不同的.当您应用这两个函数中的任何一个时,map或者fmap,对于值列表,它们将产生相同的结果,但这并不意味着它们用于相同的目的.
运行GHCI会话(Glasgow Haskell Compiler Interactive)来查询有关这两个函数的信息,然后查看它们的实现,您将发现许多差异.
查询GHCI了解相关信息 map
Prelude> :info map
map :: (a -> b) -> [a] -> [b] -- Defined in ‘GHC.Base’
Run Code Online (Sandbox Code Playgroud)
并且您将看到它被定义为适用于任何类型的值列表的高阶函数,a从而产生任何类型的值列表b.虽然多晶型(在a与b在上面的定义代表任何类型)的map函数旨在被应用到的值的列表,其是在许多其他之中Haskell中只是一个可能的数据类型.该map函数无法应用于不是值列表的内容.
正如您可以从GHC.Base源代码中读取的那样,该map函数实现如下
map _ [] = []
map f (x:xs) = f x : map f xs
Run Code Online (Sandbox Code Playgroud)
它利用模式匹配将头部(the x)拉出xs列表的尾部(the ),然后使用:(cons)值构造函数构造一个新的列表,以便预先添加f x(将其读作"f applied to x")到map尾部的递归直到列表为空.值得注意的是,map函数的实现不依赖于任何其他函数,而只依赖于它自身.
现在尝试查询有关的信息fmap,你会看到一些完全不同的东西.
Prelude> :info fmap
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
...
-- Defined in ‘GHC.Base’
Run Code Online (Sandbox Code Playgroud)
此时间fmap被定义为其实现必须由希望属于Functor类型类的那些数据类型提供的函数之一.这意味着可以有多种数据类型,而不仅仅是"值列表"数据类型,能够为fmap函数提供实现.这fmap适用于更大的数据类型集:真正的函子!
您可以从GHC.Base源代码中读取,该fmap函数的可能实现是Maybe数据类型提供的实现:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
Run Code Online (Sandbox Code Playgroud)
另一种可能的实现是由2元组数据类型提供的实现
instance Functor ((,) a) where
fmap f (x,y) = (x, f y)
Run Code Online (Sandbox Code Playgroud)
另一种可能的实现是列表数据类型提供的(当然!):
instance Functor [] where
fmap f xs = map f xs
Run Code Online (Sandbox Code Playgroud)
它依赖于map函数(请注意那里的无点符号......但这超出了原始问题的范围).
该map函数只能应用于值列表(其中值是任何类型),而fmap函数可以应用更多的数据类型:所有属于仿函数类的函数(例如maybes,元组,列表等). ).由于"值列表"数据类型也是一个仿函数(因为它为它提供了一个实现),因此fmap可以应用于生成与之相同的结果map.
map (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)
Run Code Online (Sandbox Code Playgroud)