まずは Functor, fmap の構文を確認しておこう。
class Functor f where
fmap :: (a -> b) -> f a -> f b
この構文から分かることは、
- Functor は型クラスである
- fmap は Functor 型クラスのメソッドである
- Functor はデフォルト実装を提供していない
ということ。
もう少しよく見ると、
- fmap の型 (a -> b) -> f a -> f b から、f は型コンストラクタである必要がある(例:Maybe や [] など)
- つまり、f は「型を1つ取って新しい型を作る関数」のようなもの
- fmap は「通常の関数 a -> b を、f の文脈の中に持ち込む」ことができる、いわば「関数の持ち上げ(lifting)」を行う
- f の中身には手を触れず、構造だけを保ったまま、要素に対して関数を適用する
ことが分かる。
具体例いろいろ
ghci> fmap (+2) [1, 3, 9] -- これは完全に普通の map と同じ
[3,5,11]
ghci> map (+2) [1, 3, 9]
[3,5,11]
-- f に Maybe 型を取る例
ghci> fmap (+2) (Just 3)
Just 5
ghci> fmap (+2) (Nothing)
Nothing
-- (Int -> String) -> Maybe Int -> Maybe String
ghci> fmap show (Just 123)
Just "123"
-- (Int -> Bool) -> [Int] -> [Bool]
ghci> map even [1, 2, 3, 4]
[False,True,False,True]
-- (Int -> Bool) -> Either a Int -> Either a Bool
ghci> fmap (> 0) (Right 3)
Right True
-- Left は関数が適用されない
ghci> fmap (> 0) (Left "error")
Left "error"