要与地图区分的Fmap示例?

时间:2016-09-29 08:52:58

标签: haskell functor

我的理解是map和fmap之间的区别在于后者可以返回一个函数吗?

我正在研究这个http://learnyouahaskell.com的仿函数部分,其中一些解释有点不清楚。

Map和fmap的行为完全相同:

let exMap = map (+1) [1..5]
let exFMap = fmap (+1) [1..5]

返回函数的fmap的一个很好的例子是什么?

3 个答案:

答案 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)

mapa -> b变为函数[] a -> [] b(通常写为[a] -> [b])。

fmapa -> b转换为任何仿函数f a -> f b的函数f,而不仅仅是f = []。上面的示例选择了f = IOf = 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)

fmapmap更通用 - 实际上对于列表没有区别 - 这里有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的答案。