class Functor f where
fmap :: (a -> b) -> f a -> f b
其中f
并不是一個具體類型,而是一個單參類型構造器(:k f = * -> *
)。
類型f a
的值稱為functor value。
<u></u>fmap
接受一個普通函數a -> b
,返回一個functor value上的函數f a -> f b
。
Functor Law
只是Functor類型類的實例,還不是一個數學意義上的Functor,需要滿足以下定律。
(1)fmap id = id
(2)fmap (f . g) = fmap f . fmap g
Examples
(1)[]是Functor類型類的實例
instance Functor [] where
fmap = map
列表類型上的map
就是fmap
。
map :: (a -> b) -> [a] -> [b]
注:
不能寫“instance Functor [a] where
”而要寫“[]
” (:k [] = * -> *
),因為Functor類型類的實例必須是一個單參類型構造器,而“[a]
”是一個具體類型。
(2)Maybe是Functor類型類的實例
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
其中,Maybe
類型的定義如下:
data Maybe a = Just a | Nothing
其中,fmap :: (a -> b) -> Maybe a -> Maybe b
(3)Tree是Functor類型類的實例
instance Functor Tree where
fmap f EmptyTree = EmptyTree
fmap f (Node x left right) = Node (f x) (fmap f left) (fmap f right)
其中,Tree
類型的定義如下:
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
(4)Either a是Functor類型類的實例
<u></u>Either a b
是一個具體類型,而Functor類型類的實例必須是單參類型構造器。
而Either是接受兩個參數的類型構造器(:k Either = * -> * -> *
),也不可以。
部分應用Either
的一個參數類型,得到Either a
,它是一個單參類型構造器了(:k Either a = * -> *
)。
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
其中,Either
類型的定義如下:
data Either a b = Left a | Right b
(5)(->) r是Functor類型類的實例
函數類型r -> a
可以改寫為:(->) r a
,則“->
”就是一個接受兩個參數的類型構造器了(:k (->) = * -> * -> *
)。
如果已提供一個類型參數,則“(->) r
”就是單參類型構造器了(:k (-> r) = * -> *
),可以作為Functor類型類的實例了。其中,(->) r = (r ->)
instance Functor ((->) r) where
fmap f g = (\x -> f (g x))
我們考慮一下fmap
的類型是如何實例化的
fmap :: (a -> b) -> f a -> f b
= (a -> b) -> ((->) r a) -> ((->) r b)
= (a -> b) -> (r -> a) -> (r -> b)
而這正好是函數復合“.
”的類型,所以fmap
還可以定義為:
instance Functor ((->) r) where
fmap = (.)
因此,fmap
作用在兩個函數上面,就相當于進行函數復合。
ghci> fmap (* 3) (+ 100) 1
303
還可以有不同的寫法:
fmap (* 3) (+ 100) 1
= (* 3) `fmap` (+ 100) $ 1
= (* 3) . (+ 100) $ 1