関手とFunctor
HaskellのFunctor型クラスが、圏論で言う関手に対応する
関手の定義
\mathscr{A},\mathscr{B}を圏としたとき以下からなる
D1
:A\to F(A)
\mathrm{ob}(\mathscr{A})\rightarrow\mathrm{ob}(\mathscr{B})
D2
:f\to F(f)
\mathscr{A}(A,A')\rightarrow\mathscr{B}(F(A),F(A'))
以下を満たす
T1
: F(1_A)=1_{F(A)}
T2
: F(f\circ g)=F(f)\circ F(g)
後で参照しやすいように D1
, D2
, T1
, T2
と名前を振っておいた
Functor型クラスの定義
hsclass Functor f where
fmap :: (a -> b) -> f a -> f b
->
は右結合なので以下のように括弧を付与できる
fmap :: (a -> b) -> (f a -> f b)
関手は、定義からわかるように2つの圏を見たときに、
対象同士と
射同士の
2つの対応付けを同時に行うものである
HaskellにおけるFunctorについてもこの2つの対応があることを確認する
具体的な対応例を見るとこんな感じになる
Hask圏のことを考えているので、ドメインもコドメインもHask圏になる
その対象としての型 Char
, Int
, [Char]
, [Int]
射としての関数 ord :: Char->Int
関手としてのFunctor List
と fmap
がある
Functor :: Hask -> Hask
になるのでHaskellのFunctorは
関手の中でも特に
自己関手限定の話である
ここで
「 *->*
なFunctor(ここではList)」が「 *
の型同士」の対応付け、
「 (a -> b) -> f a -> f b
な関数 fmap
」が「関数同士」の対応付け
をしていることがわかる
なので、両方ともHask圏の対象同士、射同士を同時に対応付けている
圏論風に書くと
f :: Int -> Char
は、
List f :: List Int -> List Char
になっている
この List f
というのが、Haskellで言う fmap f
なのである
カインドが
*->*
な型コンストラクタだけを考えるだけではダメなんだな

Functorにするために、
そのただの型コンストラクタに、
fmap
の実装を強制することによって、
初めてその型コンストラクタが関手たりうる。
だから、ただの多相な型 Human a
のような型コンストラクタはFunctorではない
hsfmap id == id -- T1
fmap (f . g) == fmap f . fmap g -- T2
hsfmap id [1,2,3] == [1,2,3]
id [1,2,3] == [1,2,3]
f = (+ 1)
g = (* 2)
fmap (f . g) [1,2,3] == [3,5,7]
(fmap f . fmap g) [1,2,3] == [3,5,7]
↓これ書く意味あるのか?
T1.hsfmap id [] == []
fmap id (x:xs) == id x : map id xs == x : map id xs
T2.hsfmap (g . f) [] == []
fmap (g . f) (x:xs) == (g . f) x : map (g . f) xs
参考
Hask圏以外の圏のFunctorを作る