我的理解是map和fmap之间的区别在于后者可以返回一个函数吗?
我正在研究这个http://learnyouahaskell.com的仿函数部分,其中一些解释有点不清楚。
Map和fmap的行为完全相同:
let exMap = map (+1) [1..5]
let exFMap = fmap (+1) [1..5]
返回函数的fmap的一个很好的例子是什么?
答案 0 :(得分:11)
不,不同之处在于fmap
适用于任何仿函数。例如:
readLine :: IO String -- read a line
fmap length readLine :: IO Int -- read a line and count its length
Just 4 :: Maybe Int
fmap (+10) (Just 4) :: Maybe Int -- apply (+10) underneath Just
-- returns (Just 14)
map
将a -> b
变为函数[] a -> [] b
(通常写为[a] -> [b]
)。
fmap
将a -> b
转换为任何仿函数f a -> f b
的函数f
,而不仅仅是f = []
。上面的示例选择了f = IO
和f = Maybe
。
答案 1 :(得分:3)
查看每个函数的类型签名会有所帮助,让我们从您正在查看的map
函数开始:
map :: (a -> b) -> [a] -> [b]
如您所见,此map
函数在列表上运行。然而,逻辑上,有许多数据结构可以映射。以下是其他一些可能的地图:
map :: (a -> b) -> Map k a -> Map k b
map :: (a -> b) -> Maybe a -> Maybe b
map :: (a -> b) -> IO a -> IO b
这只是冰山一角,很多事情都可以映射出来!
在不支持类型类的语言中,这可能是您所知道的世界。只有很多map
函数,您必须使用适当的模块类型对它们进行限定,以区分您实际意味着的map
。在哈斯克尔不是这样!
现在让我们看一下fmap
:
fmap :: Functor f => (a -> b) -> f a -> f b
此函数与上面显示的格式完全相同,但适用于任何函子。
Functor的定义如下:
class Functor f where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
(<$) = fmap . const
希望这很明显,仿函数只是支持映射的东西。
因此fmap
是一般性的,而map
是特定的。
答案 2 :(得分:2)
fmap
比map
更通用 - 实际上对于列表没有区别 - 这里有map == fmap
。
让我们从fmap
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
这基本上说你可以把一个简单的函数变成一个函数,将容器转换成相同形状但不同元素的容器。
instance Functor [] where
fmap = map
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just something) = Just (f something)
还有更多,我认为几乎每个具有单一类型参数的容器都可以是仿函数
作为练习,您可以尝试为
定义实例data Tree a = Tree a [a]
使用fmap
查看@ chi的答案。