用最簡單的一句話來解釋 functor 就是指可以被 map 的東西像是 List
,而在 Haskell functor 就只是 typeclass
在 Haskell 是這麼定義的
class Functor f where
fmap :: (a -> b) -> f a -> f b
這邊會看到 Functor
只有定義一個 function fmap
,它接受一個 function (a → b)
作為參數,然後接受一個被 functor 包裝起來 f a
最後回傳被 functor 包裝的 f b
當然這樣解釋還是很模糊那我們先從 list 來看,我們 map list的方式就是使用 map
這個 function
:t map
-- map :: (a -> b) -> [a] -> [b]
,map
的定義是傳入一個 function (a → b)
及 [a]
最後會回傳 [b]
,乍看之下 fmap
跟 map
可以說一模一樣。而實際上的確 map
就是在 list 這個 type 的 fmap
,還記得前面所說的嗎 Functor
是一個 typeclass ,所以只是 list 在實作 Functor
的 instance 時將 fmap
定義為這種形式。
而實際上 Haskell 的原始碼也的確是如此定義
instance Functor [] where
fmap = map
這邊有一個值得關注的點是這裡是寫作 Functor []
而不是 Functor [a]
,instance Functor [] where
的定義表示 []
本身是一個 Functor,而不僅僅是某一個特定的 [a]
列表,這是因為 Functor
的定義是針對一個 type constructor 而不是特定的 type 。
我們可以再看看 Maybe
,一樣的其實我們不必在意是怎樣具體的 type ,而是只要是 Maybe
就好。
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
而這邊的定義是當我們匹配到 function f
以及 Just x
時就是將 x
丟進 f
最後再加上 Just
。
又或者我們可以說 fmap
不管是在 Maybe
還是 []
做的事情就是將一個容器打開執行完 function 再塞回容器。
所以 functor 到底是什麼?儘管我們用了 list、Maybe 等容器的概念輔助解釋,但 functor 終究不是一種「實際的容器」,而是在形容如果某些容器具有可以被 map 這個特性那它就是 functor 。
如果有讀者在之前有透過其他語言先認識到 functor 的話,相信應該會對它的定義有許多混亂的點。當初第一次聽到時我也會傾向用「容器」的想法在看待 functor ,但隨著對於 FP 有了進一步的認識,我感覺不應該把 functor 當作一個「實際存在的資料結構」,而是只是在描述一種抽象概念或者該說一種 typecalss 而已。