2016-09-29 42 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的回答。