圏論には「ファンクター」から入ろう
このページはマス旅の一部です。
「圏」は「集合」と「ベクトル」と「群」をゆる~くアレンジしてできた、
何かのつながりを俯瞰するときに使える数学のアイディアです。
知らないものを学ぶという感覚ではなく、
ぼんやり気づいていることの明確化だ、と思って付き合いましょう。
さて、「圏」は「集合」と「ベクトル」と「群」をゆる~くアレンジしてできたものとかきましたが、
ざっくり、「圏」(カテゴリー)というカタマリの共通ルールを確認しましょう。
そして、1つめキーワードである「ファンクター(関手)」に親しもう。
6の約数圏
1.圏の具体と抽象
圏の具体と抽象
<圏とは何か>
「圏」とは、対象と「射」という矢印を持っていて、1という矢印があり、
矢印の結合ができて、結合法則が成り立つ、そういうカタマリです。
たったこれだけのルールです。
対象があるところが「集合」と同じだけど、その中身は特に指定されてない。対象は数どころか、同種のものがあつまってれば何でもOK。
矢印があるのが「ベクトル」と同じだけれど、始点と終点はあっても位置はない、長さは自由。
1と結合法則については「群」と同じだけれど、逆は特になくてOK。
ここまで読んで、どう思いますか。
矢印中心で対象はあいまいです。これでいいのか?
と思いますよね。あえて、矢印中心にしたのです。
これが「圏」の物重視ではな関係重視の思想です。internalよりもexternal重視です。
矢印の位置も長さがどうでもよくて、つなげ方が大事です。
これが、同型なら同じとみなすという位相的な発想が基本にあります。
「射」中心の圏論では、対象を同型を除いて(up to isomorphism)区別するのが自然なのです。
<圏の具体>
人間の認知構造として、モデルがないと、わかった気にならないものです。
そこで、圏の具体を並べます。
ヒットするものがあるとうれしいです。
圏の名前={対象、射、結合、1}
の順に並べてみますね。
整数の整除圏={整数たち、整除、整除の連続、自身を割る}
半順序圏={半順序集合の要素、半順序 、半順序の合成、自身との半順序」
6の約数圏={[1,2,3,6]、xはyの約数、約数の約数、1}
先祖圏={[私、母、祖母]、xはy以上の先祖、先祖の先祖、自身}
Grps(群圏)={群たち、群準同型、群準同型の合成,恒等写像}
Sets(集合圏)={集合たち、写像、写像の合成、恒等写像}
Tops(位相空間圏)={位相空間たち、連続写像、写像の合成、恒等写像}
空圏={空、空、空、空}
1圏={1、1→1、1、1}
グラフ圏={ノード、矢、矢をつなぐ、自己ノードをさすループ}
データ型圏={データ型たち(数値、文字列、リスト)、型変換、変換の連続、無変換}
すごろく圏={すごろくの位置(振り出し、とちゅう、ゴール)、進む、進むを続ける、休み}
まだまだありそうですね。
半群の圏、環の圏、体の圏、.......
集合で対象を1つの集合の要素たちにして、射を部分集合にした「部分集合の圏」もできるでしょう。
集合たちでも2つの集合の共通部分を射にすると、「共通部分の圏」もできるでしょう。
いろいろできそうですね。
「圏」のアイディアが「普遍性」のあるものだということが感じられるでしょう。
さて、次はいよいよ、
圏と圏をつなぐ矢印であるファンクター(関手)
を見てみよう。
2.ファンクターはこわさず持ち上げる
<ファンクターはこわさず持ち上げる>
functorはfunctionと最初の4文字が同じです。
働きは似てますが、厳密には違うからこそ違う名前がついています。
見慣れないコトバだと思っている人には朗報です。
「ファンクターはセットメニュー化」
というブンゲン先生の「はじめての圏論」でのたとえが超わかりやすいです。
H=ハンバーグ圏
={[ハンバーグ、チーズハンバーグ、和風ハンバーグ、…]、
[和風にする、チーズをのせる、...]、
射を組み合わせる、素のまま}
fmap(H)=ハンバーグライスセット圏
={[ハンバーグライスセット、チーズハンバーグライスセット、和風ハンバーグライスセット、…]、[和風にする、チーズをのせる、...]、射を組み合わせる、素のまま}
ここで、Hの2つの対象a=ハンバーグ、 b=チーズハンバーグと、射cheeze:a→b(チーズをのせる)を
とりあげましょう。
f(a),f(b)の関係はcheezeなので、fmap(cheeze):f(a)→f(a)ですよね。
HaskellのFunctorの型クラスの定義は次のようになってます。
class Functor f where
fmap f :: (a->b) -> fa -> fb
(Haskellは関数の引数にかっこをつけないの上にかいたことと同じです。)
射をまるごと始点と終点もいっしょに移しますが、始点、終点はライスセットのfが効いてますが、
射のチーズをのせるのはそのまま保存されてますね。
Functorの型には、Maybeというインスタンスもあります。
Maybeはたぶんコケるかもというデータ型です。
こけても安全にデータとして渡されます。
「fmap」はmapだけどファンクターのマッピングですよという、
一般のmapと区別するためのワードですので深入りしないでいいです。
「where」はHaskellの条件句の開始部分で左カッコ程度の意味ですね。
instance Functor Maybe where
fmap f (Just x) = just (f x)
fmap f Nothing = Nothing
似たものにEitherというインスタンスもあります。
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
Haskellは型が厳密な言語なので、ファンクター型が種類わけされています。
Pythonとは現状真逆で型にうるさくないなのでFunctorはもっとゆるく使えましたね。
たとえば、PythonのFunctorのMaybeの使い方は、
from pymonad.maybe import Just, Nothing
def extract_addressM(X):
return Just(X["A"]) if "A" in X else Nothing
というように、
辞書型のデータのaddress項目を調べて、欠損してないとJustでくるみ、欠損してるとNothing
を返す。JustもNothingも予定された値だから欠損値でもエラーがおきずに動かせます。
Nothingじゃあさみしいと思ったら、
def extract_addressE(X):
return Right(X["address"]) if "address" in X and X["address"] is not None else Left("Address がありません")
Either型を使って、欠損値のときはLeftにメッセージをくるみ、データがあればRightにくるんで送ります。
これは、単独処理ではなく、複数の項目があればこのような関数をバケツリレーできます。
変なデータがまざっていても、エラーが起きずに情報収集ができます。
くわしくは、こちら「FP:モナドで現実データ世界を安全に過ごそう」をご覧ください。
<振り返り>
今の3つの例からわかることは何でしょう。
ブンゲン先生の例は
「ハンバーグ圏」の構造を持ち上げて「ライスセット圏」を作りました。
Maybeは
「データ圏」の構造を変えずに、「Maybe圏」を作りました。
Eitherは
「データ圏」の構造を変えずに、「Either圏」を作りました。
これって、圏を圏に移す射です、1対1で構造を壊さず全体を持ち上げてますね。
ということは
ファンクター={圏たち、ファンクター、合成、恒等射}という圏になっているということですね。
このしくみは、
2の約数圏={[1,2]、約数、合成、自分自身の約数}という超シンプルな圏と対応がつくね。
ファンクターを使うと、圏の同型写像の圏を作れそうですね。
だた、準同型ではなく、同型といえるためには逆戻りできないといけない。
厳密には、逆射としての逆ファンクターが構成できると、「圏同型」と言えそうだね。また、ファンクターは射の1つだから、
射の合成としてファンクターのバケツリレーができるということも言えるでしょう。
たとえば、「ライスセット圏」にビールをつけて「ビールライスセット圏」もできるでしょう。
<さらに俯瞰しよう>
圏たちが、対象でファンクターが射となる圏が作れるということは、
圏と圏をつなぐファンクターを複数用意することができるはずだ。
さっきの例では、
1つのデータ圏に対して、ファンクターを変えたために、Maybe圏とEiger圏ができた。
でも、圏Cに2つのファンクターF,Gをして同じ圏Dができることもありうるでしょう。
そうすると、F、Gは違ってみえても、
2つのファンクターFをGに翻訳する対応が自然にできるはずですね。
これを自然変換(natural transformation)という。
圏Cの中の射f:a→bに目をつけてみよう。
射がそれぞれ持ち上げられるとして、F(f): F(a)→F(b)とG(g):G(a)→G(b)とする。
そして、FモノからGモノへの翻訳をφとしたら、
F(a)からG(b)への射は
φaしてG(f)でも、F(f)してからφbしても同じはずだ。
これを「図式が可換」だという言い方をします。
圏論の証明の基本技です。
群論の証明でもよく出てきましたね。
グラフをかくと、四角形ABCDができてて、AからCへの矢印は
AB+BCでも、AD+DCでも射の合成は同じになりますよ
というものでしたね。
イメージとしたら、「ビールライスセット圏」は
ピールが先でもライスが先でも、
結局は、「ビールライスセット圏」ができるでしょということですね。
3.圏の視覚化
圏の視覚化をしてみる。
課題:自然変換φの図式が可換であることを視覚化しよう。
#Pythonを使わなくても、geogebraで図式がカンタンにかけます。
#オブジェクトの設定のラベルの変更によって、記述の自由度があがりますね。
#タイトル「自然変換φの図式が可換」
#四角形ABCDをかきます。
A=(-3,3)
B=(-3,-1)
C=(3,-1)
D=(3,3)
φa=Vector(A,B)
φb=Vector(D,C)
Ff=Vector(A,D
Gf=Vector(B,C)
4点A,B,C,Dの設定を順にひらいて
ラベルをF(a),G(a),G(b),F(b)に変更します。
ビューの格子と軸を設定で非表示にすると、図に見えますね。
自然変換φの図式が可換
課題:データ圏をMaybe圏やEither圏に持ち上げるようすを視覚化しよう。
Pythonを使わなくても、geogebraでカンタンに作れます。
#タイトル「データ圏をファンクターを使って、Maybe圏またはEither圏へ持ち上げる」
a=slider(-10,10,1) #アニメーションにする。
JorN={"Just " + a, "Nothing"}
Maybe=if(a>=0, JorN(1), JorN(2)) #太字で青で文字サイズを大にする。
RorL={"Right( " + a + " )","Left(負のデータです)")
Either= if(a>=0, RorL(1), RorL(2)) #太字で緑で文字サイズを大にする。
b=CheckBox(if(On),Maybe,Either) #Maybeに連動して作る。Eitherの設定で上級でb==falseとする。
ビューの格子と軸を設定で非表示にすると、図に見えますね。