generated at
Hom関手と関数型(->)

Hom関手について、丁寧に見てみるHask圏の構造については知っている前提で進める


Hom関手の良い例として関数型 (->) が考えられる
これは型引数を2つ取る型コンストラクタであり、
2つのうちのいずれかを固定することで関手になることができる
Reader e a で考えても同じだが、関数型で考えたほうが直感的でわかりやすいと思うmrsekut


Hom関手について見る
まずはドメイン側を固定したものを見る
例によってHask圏を考える
対象としての型がいくつか考えられるが、今回は Int をドメインとしての対象として固定する
すると関手 (->) Int を考えられる
Int とは別の型 X を決めるごとに、新たな型 (->) Int X が得られる
(->) Int X はHaskellにおける型であるので、Hask圏の対象の一つである
(->) Int X Int -> X と表記することもでき、全く同じ意味であり、今回は前者を用いる
と、言いながら↓の図では後者で描いてるなmrsekut
ここで例として Bool Char を置いてみた
(->) Int を関手と見ることで、 (->) Int Bool (->) Int Char という対象への対応が取れる
(->) Int 関手はドメインもコドメインも同じHask圏であるので、これは自己関手の一種となる
対象についての対応はわかったので、射の対応についてみてみよう
射の対応は、ここでは
Int -> Bool という型の関数を一つ選択して、
f :: Bool -> Char と合成すると、
Int -> Char という型の関数となり
その対応が (->) f 、つまり fmap f になるのだった
どういうことか?具体的に見ていこう
Int -> Bool という型の関数もいくつも考えられる
odd
even
isNegativeZero
etc.
同様に Int -> Char という型の関数もいくつも考えられる
intToDigit
chr
etc.
ここで、 f を以下のように定義する
hs
f :: Bool -> Char f True = 't' f False = 'f'
例えば、 Int -> Bool という型の関数から、 even を選び、 f と合成する
この f . even Int -> Char という型の関数群の一つである
f . even と全く同じ挙動をする関数は関数合成を用いなくとも定義できる
hs
fev :: Int -> Char fev n = if odd n then 'f' else 't'
これが (->) f の対応である
つまり、Haskの写し先では
(.) f という関数を、 even に適用すると、 fev が出てくる
イメージ的には ((.) f) even == fev
関数型 (->) r のFunctorの定義は以下のようなものだった
hs
instance Functor ((->) r) where fmap = (.)
定義にもあるように fmap は、関数合成 . で定義されている
写し先のHask圏で成り立っているかを確認しよう
省略するが、残りの関手の定義である合成の保存と恒等射の保存も成り立つ
以上により、 (->) Int は、Hask圏におけるHom関手であることがわかった
以下ではコドメイン側を固定した関手 (->) _ Int を考える





反変Hom関手について見る





(->) (,) は1つ目、2つ目のどちらを固定するかで共変か反変かが変わる
「2つの型引数を取る型コンストラクタ」ではなく、↑これら2つに関しての話か。mrsekut
1つ目を固定した場合
例えば (->) Int という1つの型引数を取る関手を考える
これは、共変関手となる
これは上の普通の関手の議論と同じなので省略
2つ目を固定した場合
例えば (->) _ String という1つの型引数を取る関手を考える
これは、反変関手になる
なぜ #??
共変関手だと考えるとどういった不都合が生じるの?