関手とFunctor
HaskellのFunctor型クラスが、圏論で言う関手に対応する
関手の定義
https://gyazo.com/0ca185bf597176b4658726ab330d2519
$ \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型クラスの定義
code:hs
class Functor f where
fmap :: (a -> b) -> f a -> f b
->は右結合なので以下のように括弧を付与できる
fmap :: (a -> b) -> (f a -> f b)
関手は、定義からわかるように2つの圏を見たときに、
対象同士と
射同士の
2つの対応付けを同時に行うものである
HaskellにおけるFunctorについてもこの2つの対応があることを確認する
具体的な対応例を見るとこんな感じになる
https://gyazo.com/54ea9292aeda2f3d1eb3169c92eb83d5
Hask圏のことを考えているので、ドメインもコドメインもHask圏になる
その対象としての型Char,Int,[Char],[Int]
射としての関数ord :: Char->Int
関手としてのFunctorListと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なのである
カインドが*->*な型コンストラクタだけを考えるだけではダメなんだなmrsekut.icon
Functorにするために、
そのただの型コンストラクタに、
fmapの実装を強制することによって、
初めてその型コンストラクタが関手たりうる。
だから、ただの多相な型Human aのような型コンストラクタはFunctorではない
code:hs
fmap id == id -- T1
fmap (f . g) == fmap f . fmap g -- T2
code:hs
f = (+ 1)
g = (* 2)
↓これ書く意味あるのか?
code:T1.hs
fmap id [] == []
fmap id (x:xs) == id x : map id xs == x : map id xs
code:T2.hs
fmap (g . f) [] == []
fmap (g . f) (x:xs) == (g . f) x : map (g . f) xs
参考
Hask圏以外の圏のFunctorを作る