2016-09-29 37 views
3

我的理解是,map和fmap的区别在于后者可以返回一个函数吗?Fmap与地图区分的例子?

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

地图和FMAP相同的行为在以下几点:

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

什么是FMAP返回功能的一个很好的例子?

回答

10

不,区别在于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 = IOf = Maybe

+0

请问您是否可以进一步简化并区分函数与应用函数的区别? –

+1

如果你有'a-> b'和'f a',当'f'是一个函子时,你可以用'fmap'来得到'f b'。然而,如果你有'f(a-> b)'和'f a',你不能得到'f b':函数被包装在'f'下面,并且没有办法使它与它的参数交互。应用仿函数定义了一个额外的操作'<*>'允许。 – chi

+0

一个可用的函数是“阅读器”,它确实与函数有关,但现在可能不是最好的阶段了解它 – dfeuer

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。 Haskell并非如此!

现在让我们来看看fmap

fmap :: Functor f => (a -> b) -> f a -> f b 

此函数具有完全相同的形式,如上图所示的,但工程上的任何东西这是一个仿函数。

仿函数的定义如下:

class Functor f where 
    fmap  :: (a -> b) -> f a -> f b 
    (<$)  :: a -> f b -> f a 
    (<$)  = fmap . const 

希望这使得它显而易见的是一个仿函数是简单地一些支持映射过来。

因此fmap是通用的,而map是特定的。

+0

你应该澄清,你不能通过'文本'或'ByteString''fmap',因为它们不是仿函数 – chi

+0

@chi我只是用更好的例子替换它们 – TheInnerLight

+0

@TheInnerLight能给出一个应用这个类型数据的二叉树的例子树a =空|节点a(树a)(树一个)? –

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的回答。