Upload
kinebuchitomo
View
2.022
Download
0
Embed Size (px)
Citation preview
圏とHaskellの型
Kinebuchi Tomohiko
2016-07-02
Kinebuchi Tomohiko 圏とHaskellの型
目次
想定聴者
下準備
スライドの表記について圏論とはプログラムの型とは
Haskellの型全体を圏として見る
Hask圏tuple型Either型Functor自然変換
参考文献
宣伝
数学茶屋
Kinebuchi Tomohiko 圏とHaskellの型
想定聴者
プログラムの型は分かるが圏論を知らない人
圏論は知っているがプログラムの型を知らない人
→ プログラムの型が圏論を通してどう見えるかを解説していきます.
Kinebuchi Tomohiko 圏とHaskellの型
話すこと
Haskellの型の仕組みと圏論の対応Haskellの型システム 圏論の概念
型 対象
関数 射
tuple 直積
either 直和
Functor 関手
(ある種の関数) 自然変換
Haskellの型システムが圏論に支えられている実例を見ていきます.
Kinebuchi Tomohiko 圏とHaskellの型
話さないこと
圏論一般の説明前の発表を参照してください
プログラムの圏論的意味論
Haskellの文法
Haskellの良いプログラミング
この発表を聞いてもHaskellが書けるようになるわけではないです. 悪しからず.
Kinebuchi Tomohiko 圏とHaskellの型
下準備 - スライドの表記について
スライドのタイトルに目印を付け, どちら側の話なのかを表します.
プログラミング側の話→ [プ]
圏論側の話→ [圏]
Kinebuchi Tomohiko 圏とHaskellの型
スライドとソースコードの入手先
https://github.com/TomohikoK/math-cafe-20160702LaTeXファイルとHaskellソースコードを手に入れて嬉しい人向けです. 何かあれば私のTwitterアカウント(https://twitter.com/kinebuchitomo) に話し掛けるか,GitHubのissueに書いてください..hsという拡張子のファイルは, ghciで:loadコマンドで読み込めます.
Kinebuchi Tomohiko 圏とHaskellの型
[圏] 圏論とは
(あくまでこの発表での圏論の使い方ですが)「対象」と対象どうしをつなぐ「射」やそれらの「性質」という言葉で物事を記述する手法.対象について語るとき, 他の対象との関係の性質という外部からの視点だけを使い, 「何からできているか?」という内部からの視点を使わないという特徴がある.
Kinebuchi Tomohiko 圏とHaskellの型
[プ] プログラムの型とは
「型」とはプログラムに登場する値や式の種類のことで, その役割は
プログラムの間違いの検出整数が期待されているところに文字列が現れるなどの間違いを事前に見付ける.
抽象化, インターフェースの定義値や関数の重要な性質だけに着目する.
ソースコードを読みやすくする.「ソースコード」とはプログラムを人間が読める形で記述したもの.
プログラムの最適化型の情報を使って, より高速なプログラムを生成する.
ref.『Types and Programming Languages』(Benjamin C. Pierce)
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] Haskellの型がなす圏 (Hask圏)
対象: 型
射: 一変数関数
恒等射: id関数 (引数をそのまま返す関数)射の合成: f . g (Haskellの意味での関数の合成)
関数fの変数の型がA, 返り値の型がBのとき, fをAからBへの射とします.(https://en.wikibooks.org/wiki/Haskell/Category theory)
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] Haskellの型が圏をなすことの説明
恒等射についての条件:
任意の関数f, gに対してf . id == fとid . g == gが成り立ちます.
射の合成についての条件:
任意の関数f, g, hに対して(h . g) . f == h . (g . f)が成り立ちます.
→ Haskellの型が圏をなすことが分かりました.
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] 例. Hask圏の対象
Integer: 整数の型
String: 文字列の型
Maybe String: 文字列の値がある状態もしくは値が無い状態を表す型
[Integer]: 整数のリストの型
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] 例. Hask圏の射
Haskellの世界のdoubleと数学の世界のdoubleの見た目はなんだか似ている.
Haskellの関数double
double :: Integer -> Integer -- 関数の型宣言double x = 2 * x -- 関数の定義
数学の関数doubledouble : Z→ Zdouble(x) = 2x
double関数を射と見たときの始域はIntegerで終域もIntegerです. double関数の型宣言の情報のみを使っていて, 関数の定義の情報は使っていないことに注意してください.
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] ここまでの内容で質疑応答
「あのスライドをもう1回見せてほしい」
「あそこの解説を聞き逃した」
「あれってどういう意味?」
Kinebuchi Tomohiko 圏とHaskellの型
[プ] Haskellの直積型 (tuple型)
型a, bに対し, それらの直積と呼ばれるtuple型(a, b)が存在し,tupleの基本的な関数としてfst, sndがあります.
-- | Extract the first component of a pair.fst :: (a,b) -> afst (x,_) = x
-- | Extract the second component of a pair.snd :: (a,b) -> bsnd (_,y) = y
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/Data.Tuple.html#line-33)→ これに対応する圏論の概念は何でしょう?
Kinebuchi Tomohiko 圏とHaskellの型
[圏] 積の復習
圏Cの対象X, Yの積〈X × Y, p, q〉とは, 圏Cの対象X × Y ,射p : X × Y → X, 射q : X × Y → Yの組で, 次の条件を満たすものです.
W
k
}}
∃1h
��
l
!!X X × Ypoo
q// Y
(条件) 任意の圏Cの対象Wと射k :W → X, l :W → Yに対して, 射h :W → X × Yが1つだけあって
p ◦ h = k
q ◦ h = l
となる.Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] 直積型がHask圏の積であること
直積型がHask圏の積になるためには次の条件を満たす必要があります.(条件) a, b, cを任意の型とし, k :: c -> a, l :: c -> bを任意の関数としたとき, 関数h :: c -> (a, b)があって
fst . h == k
snd . h == l
とできる.
c
k
}}
∃1h
��
l
!!a (a, b)
fstoo
snd// b
→ h x = (k x, l x)と実装すれば条件を満たします.Kinebuchi Tomohiko 圏とHaskellの型
[プ] hの例
作為的な例ですが.
k :: (Integer, String, String) -> Integerk (x, _, _) = x
l :: (Integer, String, String) -> Stringl (_, y, _) = y
h :: (Integer, String, String) -> (Integer, String)h x = (k x, l x)
Kinebuchi Tomohiko 圏とHaskellの型
[プ] Haskellの直和型 (Either型)
型a, bに対し, それらの直和と呼ばれるEither型Either a bが存在し, EitherのコンストラクタとしてLeft, Rightがあります.
data Either a b = Left a | Right bderiving (Eq, Ord, Read, Show)
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/Data.Either.html#Either)→ これに対応する圏論の概念は何でしょう?
Kinebuchi Tomohiko 圏とHaskellの型
[圏] 余積の復習
圏Cの対象X, Yの余積〈X∐Y, i, j〉とは, 圏Cの対象X
∐Y ,
射i : X → X∐Y , 射j : Y → Y
∐Yの組で, 次の条件を満たす
ものです.
W
X
k
==
i// X
∐Y
∃1h
OO
Yj
oo
l
aa
(条件) 任意の圏Cの対象Wと射k : X →W , l : Y →Wに対して, 射h : X
∐Y →Wが1つだけあって
h ◦ i = k
h ◦ j = l
となる.Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] 直和型がHask圏の余積であること
直和型がHask圏の余積になるためには次の条件を満たす必要があります.(条件) a, b, cを任意の型とし, k :: a -> c, l :: b -> cを任意の関数としたとき, 関数h :: Either a b -> cがあって
h . Left == k
h . Right == l
とできる.
c
a
k
;;
Left// Either a b
∃1h
OO
bRightoo
l
cc
Kinebuchi Tomohiko 圏とHaskellの型
[プ] hの例
k :: Integer -> Integerk x = 2 * x
l :: Integer -> Integerl x = 3 * x
h :: Either Integer Integer -> Integerh (Left x) = 2 * xh (Right x) = 3 * x
Haskellのパターンマッチでhを定義しているので, 条件を満たすことが分かりやすくなっています.
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] ここまでの内容で質疑応答
「あのスライドをもう1回見せてほしい」
「あそこの解説を聞き逃した」
「あれってどういう意味?」
Kinebuchi Tomohiko 圏とHaskellの型
[プ] HaskellのFunctor
定義は以下の通りです.
class Functor f wherefmap :: (a -> b) -> f a -> f b
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#Functor)ある具体的なFunctorをfとして, fの射関数fmapの型を宣言しています.(「射関数」= 関手Fが写す対象と射のうち射の方だけを考えたもの. 射fを射Ffに写す関数のこと.)
Kinebuchi Tomohiko 圏とHaskellの型
[圏] 関手の復習
圏Cから圏Dへの関手F : C → Dとは, 対応の組F : Ob(C)→ Ob(D), F : HomC(X,Y )→ HomD(FX,FY )であって,
F1X = 1FX
F (g ◦ f) = Fg ◦ Ff
を満たすもの.
Kinebuchi Tomohiko 圏とHaskellの型
[プ] HaskellのFunctor則 (Functor law)
Functor則とはFunctorが満たすべき条件. これに反する実装自体はできるものの, そうするメリットはあまり無いです.
fmap id == idfmap (f . g) == fmap f . fmap g
(https://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor.html#t:Functor)このFunctor則の2つの条件が, 関手が満たすべき2つの条件に対応しています.→ HaskellのFunctorと圏論での関手に対応
Kinebuchi Tomohiko 圏とHaskellの型
[プ] Functorの例: Maybe
Maybeとは, ある型の値がある状態と値がない空の状態をいっぺんに表せる型です. 定義は以下の通りです.
data Maybe a = Nothing | Just aderiving (Eq, Ord)
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#Maybe)Nothingが「値が無いこと」に対応し,Just aが「aという型の値があること」に対応しています.
Kinebuchi Tomohiko 圏とHaskellの型
[プ] MaybeがFunctor則を満たすこと (1/2)
MaybeのFunctorとしての定義は以下の通りです.
instance Functor Maybe wherefmap _ Nothing = Nothingfmap f (Just a) = Just (f a)
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-652)Maybe aについてNothingの場合とJust aの場合のそれぞれでFunctor則を満たすことを確認すれば良いです.
Kinebuchi Tomohiko 圏とHaskellの型
[プ] MaybeがFunctor則を満たすこと (2/2)
fmap id Nothing == Nothingfmap id (Just a) == Just (id a) == Just a
fmap (g . f) Nothing == Nothing((fmap g) . (fmap f)) Nothing== fmap g (fmap f Nothing)== fmap g Nothing== Nothing
fmap (g . f) (Just a) == Just ((g . f) a)== Just (g (f a))
((fmap g) . (fmap f)) (Just a)== fmap g (fmap f (Just a))== fmap g (Just (f a))== Just (g (f a))
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] Maybeで関数を写してみよう
例: 整数の値を取って, その文字列表現を返す関数int2str.
int2str :: Integer -> Stringint2str i = show i
この関数をMaybeで写すと,
fmap int2str :: Maybe Integer -> Maybe String
という関数になります.
Hask圏 Hask圏
Integerint2str// String
Maybe +3 Maybe Integerfmap int2str// Maybe String
Kinebuchi Tomohiko 圏とHaskellの型
[プ] ghciで動かしてみる
$ ghciPrelude> :load int2str.hsPrelude> :t int2strint2str :: Integer -> String
Prelude> :t fmap int2strfmap int2str :: Functor f => f Integer -> f String
Prelude> int2str 1"1"Prelude> fmap int2str (Just 3)Just "3"Prelude> fmap int2str NothingNothing
Kinebuchi Tomohiko 圏とHaskellの型
[プ] Functorの例: List
Listとは, ある型の値を0個以上並べたものの型です. 定義は以下の通りです
data [] a = [] | a : [a]
(https://hackage.haskell.org/package/ghc-prim-0.4.0.0/candidate/docs/src/GHC-Types.html#line-33)右辺の[]が空のリストを表し,a : [a]がリストの前に要素を1つ追加したものを表します.リストの定義では再帰的な定義が使われています.
Kinebuchi Tomohiko 圏とHaskellの型
[プ] ListがFunctor則を満たすこと (1/3)
ListのFunctorとしての定義は以下の通りです.
-- The list type
instance Functor [] wherefmap = map
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-732)
Kinebuchi Tomohiko 圏とHaskellの型
[プ] ListがFunctor則を満たすこと (2/3)
FunctorとしてのListの定義に出てきた map関数の定義は以下の通りです.
map :: (a -> b) -> [a] -> [b]map _ [] = []map f (x:xs) = f x : map f xs
(https://hackage.haskell.org/package/base-4.9.0.0/docs/src/GHC.Base.html#line-868)Listについて[]の場合とa : [a]の場合のそれぞれで Functor則を満たすことを確認すれば良いです.
Kinebuchi Tomohiko 圏とHaskellの型
[プ] ListがFunctor則を満たすこと (3/3)
fmap id [] == []fmap id (x:xs) == id x : map id xs == x : map id xs
fmap (g . f) [] == []((fmap g) . (fmap f)) []== fmap g (fmap f [])== fmap g [] == []
fmap (g . f) (x:xs) == (g . f) x : map (g . f) xs== g (f x) : map (g . f) xs
((fmap g) . (fmap f)) (x:xs)== fmap g (fmap f (x:xs))== fmap g (f x : map f xs)== g (f x) : (map g) ((map f) xs)== g (f x) : ((map g) . (map f) xs)== g (f x) : map (g . f) xs
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] Listで関数を写してみよう
例: 整数の値を取って, その文字列表現を返す関数int2str.
int2str :: Integer -> Stringint2str i = show i
この関数をListで写すと,
fmap int2str :: [Integer] -> [String]
という関数になります.
Hask圏 Hask圏
Integerint2str// String
List +3 [Integer]fmap int2str// [String]
Kinebuchi Tomohiko 圏とHaskellの型
[プ] ghciで動かしてみる
$ ghciPrelude> :load int2str.hsPrelude> :t int2strint2str :: Integer -> String
Prelude> :t fmap int2strfmap int2str :: Functor f => f Integer -> f String
Prelude> int2str 1"1"Prelude> fmap int2str [1, 2, 3]["1","2","3"]Prelude> fmap int2str [][]
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] ここまでの内容で質疑応答
「あのスライドをもう1回見せてほしい」
「あそこの解説を聞き逃した」
「あれってどういう意味?」
Kinebuchi Tomohiko 圏とHaskellの型
[圏] 自然変換の復習
圏C, Dと関手F,G : C → Dがあったとき, 自然変換α : F → Gとは射の集まりαX : FX → GX (X ∈ Ob(C))であって,∀f : X → Yに対しαY ◦ Ff = Gf ◦ αXを満たすもの
Xf // Y FX
Ff //
αX
��
FY
αY
��GX
Gf // GY
→ さてHask圏で自然変換になるものは何があるでしょう?
Kinebuchi Tomohiko 圏とHaskellの型
[プ] 例. リストの先頭の要素を取り出す関数
リストの1つ目の要素を取り出す関数takeFirstを次のように定義します. リストが空だった場合はNothingを返しておきます.
takeFirst :: [a] -> Maybe atakeFirst [] = NothingtakeFirst (x:xs) = Just x
プログラミングに出てくる自然変換では, 型変数aが何かには依存しない場合が多いです. (むしろ依存されると気持ち悪いです.)
Kinebuchi Tomohiko 圏とHaskellの型
[プ] takeFirstは自然変換
takeFirstは自然変換なので,
整数のリストからそれぞれの要素の文字列表現のリストを作り, その先頭の要素を取り出す処理 (→↓のルート)
整数のリストの先頭の要素を取り出して, 整数をその文字列表現に変換する処理 (↓→のルート)
が同じ結果になります.
[Integer]fmap int2str //
takeFirst
��
[String]
takeFirst
��Maybe Integer
fmap int2str // Maybe String
Kinebuchi Tomohiko 圏とHaskellの型
[プ] 具体的な値でtakeFirstの動きを見ましょう
[1, 2, 3] � fmap int2str //_
takeFirst
��
["1","2","3"]_
takeFirst
��Just 1 � fmap int2str // Just "1"
[] � fmap int2str //_
takeFirst
��
[]_
takeFirst
��Nothing � fmap int2str // Nothing
Kinebuchi Tomohiko 圏とHaskellの型
参考文献
『すごいHaskellたのしく学ぼう!』(Miran Lipovaca・著/田中英行・村主崇行・共訳)
WikiBooks「Haskell/Category theory」 https://en.wikibooks.org/wiki/Haskell/Category theory
Hackage https://hackage.haskell.org/
『圏論の基礎』(S.マックレーン著, 三好博之/高木理訳)
『Types and Programming Languages』(Benjamin C. Pierce)
『型システム入門』(住井英二郎監訳, 遠藤侑介・酒井政裕・今井敬吾・黒木裕介・今井宜洋・才川隆文・今井健男共訳)
Kinebuchi Tomohiko 圏とHaskellの型
数学茶屋
「フリートーク中心の数学好きの集まり」
和コンセプト
時期は9月
場所は渋谷近辺
人数は20人くらい
Facebook → https://www.facebook.com/MathTeaHouse
Kinebuchi Tomohiko 圏とHaskellの型
[プ][圏] おしまい
Haskellの型と圏論の概念の対応 (再掲)Haskellの型システム 圏論の概念
型 対象
関数 射
tuple型 直積
Either型 直和
Functor 関手
Listのtakeなど 自然変換
Kinebuchi Tomohiko 圏とHaskellの型