圏論とプログラミング読書会#2 資料
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

圏論とプログラミング読書会#2 資料

  • 80 views
Uploaded on

圏論とプログラミング読書会#2 資料

圏論とプログラミング読書会#2 資料

More in: Engineering
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
80
On Slideshare
65
From Embeds
15
Number of Embeds
1

Actions

Shares
Downloads
0
Comments
0
Likes
1

Embeds 15

https://twitter.com 15

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. けんろんどくしょかい #2 (2014/12/11) 直和集合について / ラムダ計算のさわり / 型なしラムダ計算 数学的厳密性は放棄します @gomi_ningen
  • 2. #2-1 前回躓いた直和集合について ちゃんと定義に向き合うのが結局一番はやい気がした
  • 3. #2-1 前回躓いた直和集合について 直和集合(direct sum) 集合A, Bに属さない 要素 * を考える A* = (A, *) B* = (*, B) とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります
  • 4. #2-1 前回躓いた直和集合について 直和集合(direct sum) 集合A, Bに属さない 要素 * を考える A* = (A, *) B* = (*, B) とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります なぜこうするのか
  • 5. #2-1 前回躓いた直和集合について 直和集合(direct sum) 集合A, Bに属さない 要素 * を考える A* = (A, *) こうすると B* = (*, B) 集合 A の元と とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります Bの元 を 必ず分離できる
  • 6. #2-1 前回躓いた直和集合について 直和集合(direct sum) 集合A, Bに属さない 要素 * を考える A* = (A, *) 集合 Int と Int B* = (*, B) とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります でも常に (Int, *) != (*, Int) となる! ここの目的は とにかく 2つの集合の共通 部分をなくすこと
  • 7. #2-1 前回躓いた直和集合について 直和集合(direct sum) 集合A, Bに属さない 要素 * を考える A* = (A, *) 集合 Int と Int B* = (*, B) とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります で考えると 常に (Int, *) != (*, Int) となる! こうすると その元はもともと Aに属していたか, Bに属して いたか必ず分かる!
  • 8. #2-1 前回躓いた直和集合について 直和集合(direct sum) 集合A, Bに属さない 要素 * を考える A* = (A, *) B* = (*, B) とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります こうしてAに属していたという 文脈をつけた集合A*と Bに属していたという文脈を つけた集合B*のすべての元 を集めたものが直和集合
  • 9. #2-1 前回躓いた直和集合について 直和集合(direct sum) だからこうしてもよい 集合A, Bに対して A* = { (a1, 1), (a2, A* = A × {1} B* = B × {2} とすると 直和集合 A + B = A* ∪ B* つまり A* の各要素 と B* の 各要素すべてを 集めたものが直和集合になります 1), … } B* = { (b1, 2), (b2, 2), … } こうすると,たとえ共通部分 を持っていようと,必ずA, B どちらに所属していたか 区別できますよね?
  • 10. #2-1 前回躓いた直和集合について Scalaでの例: Eitherは直和型 def getIntOrStr(needToInt: Boolean): Either[Int, String] = { if(needToInt) Left(100) else Right("hoge") } Either[T,U] には Letf[T], Right[U] のどちらかのインスタンスが入る 集合 Either[T,U] の要素は 集合 Left T の要素すべてと, 集合 Right U の要素すべて
  • 11. #2-1 前回躓いた直和集合について Scalaでの例: Eitherは直和型 集合 Either[Int, Int] の要素は 集合 Left[Int] の要素すべてと 集合 Right[Int] の要素すべてを集めたもの Left[Int] => (Int, *) Right[Int] => (*, Int) 直感的にIntを 左側の世界のInt,右側の世界のInt というふうに分離すること はできますよね? A と B を完全に分離するような属性をそれぞれにつけた集合 A*, B* を考え, それらの要素すべてを集めたものが,A と B の直和集合だといえます. その定義のひとつとして (a:A, *) (*, b:B) といった形があるというふうに考 えるとわかりやすい気がします
  • 12. #2-1 前回躓いた直和集合について Scalaでの例: Eitherは直和型 Left, Right がそれぞれ Either を継承することにより直和型を実現している final case class Left[+A, +B](a: A) extends Either[A, B] { def isLeft = true def isRight = false } この方法ではすでに定義されている Int と String の直和型 IntOrString を作ることが出来ない.このような場合は,型クラスというものを用いる 詳細は http://nekogata.hatenablog.com/entry/2014/09/07/174814
  • 13. #2-1 前回躓いた直和集合について Scalaでの例: Optionは直和型 val str1: Option<String> = Some(“hoge”) val str2: Option<String> = None Option[T] には Some[T] か None が入る つまり 集合 Option[T] の要素は, 集合 Some[T] の全ての要素と 集合 None の全ての要素 ※Java8のOptionalは実装を見た感じ直和型ではない Optional<String> hoge; hoge = Optinal.of(“hoge”); // <= こいつはOptinalのインスタンス hoge = Optinal.empty(); // <= こいつもOptinalのインスタンス
  • 14. #2-1 前回躓いた直和集合について Haskellでの例: Maybeは直和型 let hoge = Just 10 :: Maybe Int let hoge = Nothing :: Maybe Int let hoge = Just “hoge” :: Maybe Int -- => Error! let hoge = Just 1.0 :: Maybe Int -- => Error!
  • 15. #2-1 前回躓いた直和集合について Swiftでの例: Optionalは直和型 Optional<T>型と ImplicitlyUnwrappedOptional<T>型 があるらしい enum Optional<T>: … { case None; case Some(T) } let foo: Int? = 1 //=> Now foo = { Some(1) } foo + 1 //=> Error if let foo = foo { foo + 1 // => 2 }
  • 16. #2-2 ラムダ計算のさわり
  • 17. #2-2 ラムダ計算のさわり いきなり形式的な議論に入る前に ラムダ計算のさわりの雰囲気を 理解をしておきたい
  • 18. #2-2 ラムダ計算のさわり そもそもの計算について考えてみる 計算とは何なのか?
  • 19. #2-2 ラムダ計算のさわり そもそもの計算について考えてみる 計算とは何なのか?   いろいろごちゃごちゃやってるけど   結局は入力から出力を得る関数だよね
  • 20. #2-2 ラムダ計算のさわり じゃあ関数とは何なのか
  • 21. #2-2 ラムダ計算のさわり じゃあ関数とは何なのか あっ、これ、進研ゼミでならったやつだ!   f(x) = x + 1
  • 22. #2-2 ラムダ計算のさわり じゃあ関数とは何なのか あっ、これ、進研ゼミでならったやつだ!   f(x) = x + 1 ん?ここにでてくる f ってなんやねん! おれはただ、 入力に1を足した出力を得たいだけなんや!!
  • 23. #2-2 ラムダ計算のさわり じゃあ関数とは何なのか あっ、これ、進研ゼミでならったやつだ!   f(x) = x + 1 ん?ここにでてくる f ってなんやねん! おれはただ、 入力に1を足した出力を得たいだけなんや!! →関数名は計算操作を考えたとき本質的でない
  • 24. #2-2 ラムダ計算のさわり ラムダ抽象の導入 f(x) = x + 1 の本質は、 x という入力を受け取り x + 1 という出力を返すということ この本質だけを抽出して λx. x + 1 と書くことにする(テストに出る) こいつをλ抽象(λ-abstraction)よぶ
  • 25. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~関数適用~ f(x) = x + 1 として f(2) を書きたいときどうすりゃいいねん → λx. x + 1 (2) と書く これを「λx. x + 1 を 2 に適用する」という
  • 26. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~関数適用~ → λx. x + 1 (2) こうしたときに 仮引数 x を 2 で置き換えて 計算を進めることができる → λx. x + 1 (2) = 2 + 1 = 3 これをβ簡約(β-reduction)とよぶ
  • 27. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~カリー化~ そういえば進研ゼミで  f(x, y) = x + y なんて関数も習ったぞ! たしか... 多変数関数とか呼ばれてた気がする... これどうすんねん
  • 28. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~カリー化~ f(x, y) = x + y は  λx. λy. x + y と本質的に計算は同じ!
  • 29. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~カリー化~ f(x, y) = x + y は  λx. (λy. x + y) と本質的に計算は同じ! ところで、これは x を引数にとり、 「1変数 関数を返す」関数にも見える!すごい! これをカリー化(Currying)とよぶ
  • 30. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~カリー化~ いくつか言葉の導入  λx. x + y について    x は束縛されているという  y は自由であるという
  • 31. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~練習問題~ (1) f(x) = 2x + 3 をλ抽象で書け (2) f(x, y) = 3x + y をλ抽象で書け (3) f(x, y) = 3x + y + xy をλ抽象で書け
  • 32. #2-2 ラムダ計算のさわり ラムダ抽象に慣れ親しむ ~練習問題~ (1) f(x) = 2x + 3 をλ抽象で書け λx. 2x + 3 (2) f(x, y) = 3x + y をλ抽象で書け λx. λy. 3x + y (3) f(x, y) = 3x + y + xy をλ抽象で書け λx. λy. 3x + y + xy
  • 33. #2-3 型なしラムダ計算 ここからお堅いはなし 参考書:プログラム意味論(共立出版)
  • 34. #2-3 型なしラムダ計算 λ式の定義 ラムダ計算が扱う式をλ式と呼び,次のように に定義する e(λ式) ::= x (変数) | λx.e (λ抽象) | e1 e2 (関数適用) λ式は変数・λ抽象・関数適用から構成される
  • 35. #2-3 型なしラムダ計算 「ラムダ計算の実行」を定義する #2-2 でやったようにラムダ計算は実行できる この実行の手順も形式的に定義する必要があり ますよね?
  • 36. #2-3 型なしラムダ計算 「ラムダ計算の実行」を定義する #2-2 でやったようにラムダ計算は実行できる この実行の手順も形式的に定義する必要があり ますよね? → 計算の実行を表す β-簡約(β-reduction) を導入
  • 37. #2-3 型なしラムダ計算 「ラムダ計算の実行」を定義する β-簡約(β-reduction) (λx.M) N →β M[x := N] 関数適用そのものを表している (左式) は, Mの中にある束縛されている x を N に置き換えた式 にできる
  • 38. #2-3 型なしラムダ計算 「ラムダ計算の実行」を定義する α-変換(α-conversion) λx.M →α λy. M[x := y] 変数の名前は本質的でなく 置き換えができることを表す変換 f(x) = x + 1 と f(y) = y + 1 は 計算の意味的にはおなじですよね?
  • 39. #2-3 型なしラムダ計算 「ラムダ計算の実行」を定義する η-変換(η-conversion) λx.M x →η M 関数の外延性を表す変換 平たく言えば (左辺) に対してどんな値を与えて も常に同じλ式 を返すとき,(左辺) 自体をそ のラムダ式に置き換えることが出来るってこと
  • 40. #2-3 型なしラムダ計算 ラムダ計算はチューリング完全 チューリングマシンについて詳しくないので 説明できる人よろしく なんかおおよそプログラミングによって実現で きるようなことを、ラムダ計算でも実現できる よということらしい
  • 41. #2-3 型なしラムダ計算 ラムダ計算はチューリング完全 チューリングマシンについて詳しくないので 説明できる人よろしく なんかおおよそプログラミングによって実現で きるようなことを、ラムダ計算でも実現できる よということらしい → マジで!?チョーウケルwwww   (おいおい、冗談もほどほどにしろよ...)
  • 42. #2-3 型なしラムダ計算 ラムダ計算による if ... else ... 例えば if ... else ... の機構 true は λt,λf.t false は λt.λf.f とすると if e1 then e2 else e3 を e1e2e3 として うまい具合に if ... else ... の構造を表せる
  • 43. #2-3 型なしラムダ計算 ラムダ計算による if ... else ... 例えば if ... else ... の機構 true は λt,λf.t false は λt.λf.f とすると if e1 then e2 else e3 を e1e2e3 として うまい具合に if ... else ... の構造を表せる 確認してみよう ←やってみて!!すごい!!
  • 44. #2-3 型なしラムダ計算 ラムダ計算による自然数とその演算の表現 以下のように自然数をλ式で表せる. これをチャーチ数とよぶ 0 = λs.λz.z 1 = λs.λz.sz 2 = λs.λz.s(sz) ファッ?!
  • 45. #2-3 型なしラムダ計算 ラムダ計算による自然数とその演算の表現 0 = λs.λz.z 1 = λs.λz.sz 2 = λs.λz.s(sz) 足し算を plus =λg1.λg2.λs.λz.g2sg1z と定義てやればこの定義に納得できる 計算してみよう!マジすごい!
  • 46. #2-3 型なしラムダ計算 ラムダ計算による自然数とその演算の表現 0 = λs.λz.z 1 = λs.λz.sz 2 = λs.λz.s(sz) 足し算を plus =λg1.λg2.λs.λz.g2sg1z と定義てやればこの定義に納得できる 計算してみよう!マジすごい! ところで自然数は 0, 1, 2 じゃだめなのか?
  • 47. #2-3 型なしラムダ計算 λ式の定義(復習) ラムダ計算が扱う式をλ式と呼び,次のように に定義する e(λ式) ::= x (変数)  | 実はλ式ではそもそも数字すら 定義されていないので 自分で定義していく必要がある  λx.e (λ抽象) | e1 e2 (関数適用) λ式は変数・λ抽象・関数適用から構成される
  • 48. #2-3 型なしラムダ計算 λ式の定義(復習) ラムダ計算が扱う式をλ式と呼び,次のように に定義する e(λ式) ::= x (変数)  | 実はλ式ではそもそも数字すら 定義されていないので 自分で定義していく必要がある  λx.e (λ抽象) | e1 e2 (関数適用) λ式は変数・λ抽象・関数適用から構成される 実は数字そのものから 構成していく必要があった!!!!