Functor型クラス
fmapを実装
関数をf 値に作用する
Functor型クラスの定義
code:hs
class Functor f where
fmap :: (a -> b) -> f a -> f b
関数をf 値に作用する
インスタンスとなる型
型引数として具体型を唯一つとる型
List
fmapはmapと同じ
code:hs
instance Functor [] where
fmap = map
Maybe
code:hs
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
Either a
Either型コンストラクタは型引数を2つ取るので、そのうち1つを固定して部分適用した型がインスタンスになる code:hs
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
IO
code:hs
instance Functor IO where
fmap f action = do
result <- action
return (f result)
(->) r
fmapは関数合成を表す
fmapは(.)と同じ
code:hs
instance Functor ((->) r) where
fmap f g = (\x -> f (g x))
-- 以下のように書いても同じ
instance Functor ((->) r) where
fmap = (.)
モナド型クラスのインスタンスではないけどFunctorになる例
code:hs
fmapを使っている例
code:hs
fmap :: (a -> b) -> f a -> f b
-- List
-- Maybe
fmap (*3) (Just 3)
fmap (*3) Nothing
fmap (++ " world") (Just "hello")
-- Either
fmap (+ 12) (Right 12)
fmap (+ 12) (Left 12)
-- IO
fmap putStrLn getLine
fmap reverse getLine
fmap (++"!") getLine
-- ((->) r)
-- fmap (*3) (+100)
(fmap (*3) (+100)) 1
((*3) . (+100)) 1 -- これと同じ
最後の関数ファンクターの場合はfmap (*3) (+100)が、リストもなどで言うfmap (*3) [1,2,3]の形になっている
つまり、関数ファンクターの結果は関数である
なので、わかりやすく1を作用させて、fmap (*3) (+100) 1と書いている
リストやMaybeなどだけを見ると、Functorとは、「何かしらの値を包んだ文脈」のように捉えることが出来るが、IOや関数ファンクタを見てみるとそうでもないように見える
fの中身にa -> bの計算をし、その結果にfを修飾したもの、と考えると説明はつく
lifting
持ち上げ
fmapの型を以下のように捉える
fmap :: (a -> b) -> (f a -> f b)
a->bとf a -> f bという2つの関数を引数に取る2引数関数
containersライブラリにある(Tree, Map, Sequence, Streamのような)沢山の標準の型はFunctorのインスタンスです。注意すべき例外はSetで、(数学的には確かにファンクタなのですが)HaskellではFunctorにすることができません。これは、Setが要素に対してOrd制約を必要とするからです。fmapはあらゆる型aとbに対して適用できなくてはなりません。 ref fp-ts
fmapに加えてflapが用意されている
flap :: a -> f (a -> b) -> f b
Functorには2種類ある
fmapに現れる→が線形性を持っているかどうかで区別する
a→bと書いた時に、aが1度だけ使われる場合は線形性があると言う
そのとき、a ⊸ bと表記する
データのコンテナであるFuctor
複数の値を保持する
fmap :: (a ⊸ b) -> [a] ⊸ [b]
e.g. List
結果をeffectでラップするFunctor
単一の値を含む
Effectに関するものである
fmap :: (a ⊸ b) ⊸ m a ⊸ m b
e.g. State
参考