Steve Awodey. Category Theory を読んで PureScript を書く[第1回(?)・2章]
はじめに
この記事は Steve Awodey の Category Theory を読みつつ出てきた概念を PureScript で実装していくものです.
"第 1 回(?)"というのは,本の途中から書こうと思い立ったので最初からではないからです.(ほぼ最初ですが)
あと現在読んでる最中なので知識はありません."わからないことはわからないと書く"精神でやりますが,間違ったことを書いてしまうかもしれません.
2.3
終対象
集合や半順序集合を対象とした圏の場合,射
☆ これは PureScript の圏(Haskell の場合
その前に
- 対象: kind
Type
を持つ型 - 射: 関数
で良いと思うが……
PureScript は正格評価なのでcall-by-need
の問題はないでしょうが,undefined
についてはわからないです.
でもFFI
を排除した PureScript にはundefined
は無いかもしれない.ここら辺はあとで考えたいです.
☆ に戻る.
f :: A -> B
と,g :: A -> B
があって,任意のa :: Unit -> A
について(f <<< a) unit == (g <<< a) unit
であるとき,任意のe :: A
について,f e == g e
.
となる
(関数f
とg
の同値をすべてのe
についてf e == g e
と定義した.)
証明)
任意のe :: A
について,a = const e
とすれば,f e == (f <<< a) unit == (g <<< a) unit === g e
2.4
対象
この
(考察)これは"一般化された要素"の考え方を使えば,
「
これは直積型と左右それぞれの値を取り出す関数に対応している.
data ProductT a b = Cons a b
p1 :: forall a b. ProductT a b -> a
p1 (Cons a _) = a
p2 :: forall a b. ProductT a b -> b
p2 (Cons _ b) = b
これが上の定義を満たすことは次のような感じで
genU :: forall x a b. (x -> a) -> (x -> b) -> x -> ProductT a b
genU x1 x2 x = Cons (x1 x) (x2 x)
これが容易に確かめられるように任意のx :: X
について
x1 x == (p1 <<< genU x1 x2) x
かつx2 x == (p2 <<< genU x1 x2) x
であることから言えるが,その前にこのような関数genU
が一意であることを言わなくてはいけない.
ここである関数genU' :: forall x a b. (x -> a) -> (x -> b) -> x -> ProductT a b
について,
x1 x == (p1 <<< genU' x1 x2) x
かつx2 x == (p2 <<< genU' x1 x2) x
が成り立つと,すなわち
x1 x == p1 (genU' x1 x2 x)
かつx2 x == p2 (genU' x1 x2 x)
だが,p1 と p2 の定義から
genU' x1 x2 x = Cons (x1 x) (x2 x)
となり,これはgenU
と等しいので,一意.
あと,クラス化してみる.
class ProductC product a b | product -> a b where
toProductT :: product -> ProductT a b
fromProductT :: ProductT a b -> product
2.6
圏
とすると
という関手ができる.(疑問点: 二値の関手(?)ってこの本で定義されてた?)
- 証明(関手則を満たす)
-
1_A\times 1_B=1_{A\times B}
とA の直積をB ,A\times B ,p_1:A\times B\rightarrow A とする.p_2:A\times B\rightarrow B
1_A\times 1_B=\langle 1_A\circ p_1, 1_A\circ p_2\rangle=\langle p_1, p_2\rangle
ここで, は,ある射\langle p_1, p_2\rangle であってu ,p_1=p_1\circ u を満たすものであり,p_2=p_2\circ u の一意性からu u=1_{A\times B} -
,f_1:A\rightarrow B ,f_2:B\rightarrow C ,g_1:P\rightarrow Q についてg_2:Q\rightarrow R (f_2\times g_2)\circ (f_1\times g_1)=(f_2\circ f_1)\times (g_2\circ g_1)
とA の直積をP ,A\times P ,p_A:A\times P\rightarrow A とする.p_P:A\times P\rightarrow P
とB の直積をQ ,B\times Q ,p_B:B\times Q\rightarrow B とする.p_Q:B\times Q\rightarrow Q
(一意性から)(f_2\times g_2)\circ (f_1\times g_1)=\langle f_2\circ p_B, g_2\circ p_Q\rangle\circ\langle f_1\circ p_A, g_1\circ p_P\rangle =\langle f_2\circ f_1\circ p_A, g_2\circ g_1\circ p_P\rangle = f_2\circ f_1\times g_2\circ g_1
-
後者はかなり端折ってしまった.図式を書けばわかりやすいんですが,書いて埋め込むための安定した手法がいまいちわからないので……
PureScript なら,ProductT
がBifunctor
のインスタンスになることに対応している.
class Bifunctor f where
bimap :: forall a b c d. (a -> b) -> (c -> d) -> f a c -> f b d
instance Bifunctor ProductT where
bimap f g (Cons a b) = Cons (f a) (g b)
もちろん関手則を満たすが,一応確かめる
bimap identity identity
== \(Cons a b) -> Cons a b
== identity
bimap f1 g1 <<< bimap f2 g2
== (\(Cons a b) -> Cons (f1 a) (g1 b)) <<< (\(Cons a b) -> Cons (f2 a) (g2 b))
== \(Cons a b) -> Cons (f1 <<< f2 $ a) (g1 <<< g2 $ b)
== bimap (f1 <<< f2) (g1 <<< g2)
2.7
- 定理
対象 ,A ,およびB ,射P ,p_1:P\rightarrow A を与え,任意のp_2:P\rightarrow B に対しX
\vartheta _X:\rm{Hom}(X,P)\rightarrow \rm{Hom}(X,A)\times\rm{Hom}(X,B)
を次のように定義する
\vartheta _X(x)=(p_1\circ x, p_2\circ x)
この時,「 がP とA の直積であること」は,「任意のB に対しX が(集合間の写像として)同型写像であること」と同値である\vartheta _X
X -> P
であり,
(と思ったが,型と集合は似て非なるものだと思っているので,そう考えるとX -> P
か?という気持ちになっている)
PureScript で言い換えると次のようになる(?)
まず Vartheta(
class Vartheta product a b | product -> a b where
vartheta
:: forall x
. (x -> product)
-> ProductT (x -> a) (x -> b) --Productは集合の意味での直積として使っている
varthetaInv
:: forall x
. ProductT (x -> a) (x -> b)
-> (x -> product)
-- 条件: 型xが同じなら,vartheta <<< varthetaInv == identityかつvarthetaInv <<< vartheta == identity
任意の型
またここでのproduct
型変数はa
とb
の直積である必要はない.
この上で,ある型product
が,任意の型x
に対して,Vartheta product a b
インスタンスを作るときProductC product a b
のインスタンスが存在する.さらに,その逆も成り立つ.
具体的な構成をする.
instance Vartheta product a b => ProductC product a b where
toProductT p = Cons (a unit) (b unit)
where
Cons a b = vartheta (const p)
fromProductT (Cons a b) = varthetaInv (Cons (const a) (const b)) unit
instance ProductC product a b => Vartheta product a b where
vartheta = f
where
f p = Cons a b
where
a x = p1 $ toProductT (p x)
b x = p2 $ toProductT (p x)
varthetaInv = fInv
where
fInv (Cons a b) x = fromProductT $ Cons (a x) (b x)
- 定理
関手 は直積を保存する.\rm{Hom}(X,-)
PureScript で言い換えると
型a
,b
,product
に対して,ProductC product a b
であるとき,任意の型x
に対してx -> product
とProductC product2 (x -> a) (x -> b)
なる型product2
の間に同型射がある.
ここでProductC product a b
なる任意のproduct
はProductT a b
の間には同型射が存在するので,任意の型a, b
とx
に対してx -> ProductT a b
とProductT (x -> a) (x -> b)
の間に同型射がある,と言い換えることができる.
具体的な構成をする.
testHomFunctor
:: forall a b x
. (x -> ProductT a b)
-> ProductT (x -> a) (x -> b)
testHomFunctor p = Cons a b
where
a x = p1 $ p x
b x = p2 $ p x
testHomFunctorInv
:: forall a b x
. ProductT (x -> a) (x -> b) -> (x -> ProductT a b)
testHomFunctorInv (Cons a b) x = Cons (a x) (b x)
testHomFunctor <<< testHomFunctorInv == identity
となる.
感想
意外と時間がかかってしまいました.コンスタントに書き続けられるか不安です.あと,色々な具体例が載っていた 2.5 章と練習問題は飛ばしています.PureScript で実装したい内容があったら別記事に書きたいと思います.
Discussion