ラムダでウィザード 滅せよ手続き、とチャーチは言った (※言ってません)
DESCRIPTION
.NET基礎勉強会での発表資料です。TRANSCRIPT
ラムダでウィザード
滅せよ手続き、とチャーチは言った
(※言ってません)
bleis-tift
July 20, 2013
自己紹介
id:bleis-tift / @bleis
なごやではたらくゆるふわ.NETer
好きな関数型言語は F#
Microsoft MVP for Visual F#
.NETの基礎ということで・・・
IL・・・?そんなこわいことこわい人がいっぱい来ること確定な場所で話せません><。
.NETと言えば F#ですよねー (異論は認める
F#の基礎と言えばラムダ計算ですよねー
(.NET基礎ならなごやこわいは参加しないだろうし、これにしよう!)
どうしてこうなった・・・
今日やること
ラムダ計算って何?
ラムダ計算で計算してみる
ラムダ計算を拡張してみる
ラムダ計算を知らない人を対象に、ラムダ計算がナニモノなのかの感覚を掴んでもらうのが目的!こわい人がそこらじゅうにいるからgkbr
ラムダ計算って何?
その前に
関数型言語って何?
関数型言語とは
ある人曰く、「それぞれの人が色々な特徴から適当なサブセットを選んで関数型と呼ぶ」
ある人曰く、「永続的データ構造を扱う言語だ」
ある人曰く、「そんなものはない。あるのは関数プログラミングというスタイルだけだ」
「この言語は関数型言語だ!」という判断は各人に任せるとして、個人的には「ラムダ計算に基づく言語」は関数型言語でいいのでは?と思ってます。
よくある (かもしれない)誤解
「ラムダ計算に基づく言語」は関数型言語→ ラムダ式を持っていれば関数型言語だ?
今日はこの (ないかもしれない)誤解を解きに来ました!
ラムダ計算とは
すごくシンプルなプログラミング言語文法がシンプル
予約語は λ だけ
関数しかない真偽値も、数も、条件分岐も、ループも、全部関数で表す
色々な関数型言語の基礎になっている
ラムダ計算の文法
ラムダ計算のプログラムは一つの項 (式と思ってもらえれば)として表されます項の要素になれるのは、以下の 3つだけです
名前・・・・・・・・・・・変数
(項 項)・・・関数適用
(λ名前.項)・・・ラムダ抽象
名前には、英字一文字を使うことが多いです。
ラムダ計算の項として有効なもの
以下の文字列の並びは、ラムダ計算の項として有効です
x
(f x)
(λx.x)
(λf.(λx.(f x)))
カッコの省略
.
.(λf.(λx.(f x)))
の一番外側のカッコと一番内側のカッコは取り除いても曖昧になりません。..λf.(λx.f x)
以降では、曖昧性のないカッコは省略します。
文法のおさらい
.ラムダ計算の文法..
.
t ::= < name >
| (< t > < t >)
| (λ < name > . < t >)
数値はおろか、真偽値などもない
変数が導入されるのはラムダ式の引数のみ
値はラムダ抽象 (つまり関数)のみ!
ラムダ計算の意味
文法を定義しただけでは何の役にも立たないので、意味を与えてあげましょう!
ラムダ計算における計算
ラムダ計算における計算とは、引数に関数を適用することです。t1 t2という項があった時に、t1がラムダ抽象だった場合に、ラムダ抽象の中の項に現れる引数を t2で置き換えます。.例えばこんな..
.
(λx.x) (λy.λz.(y z))
↓下線を引いた項に引数を与えて簡約λy.λz.(y z)
簡約の方法
簡約の方法にはいろいろありますが、ここでは皆さんになじみの深い方法を採用します。t1 t2という項があった時、
t1から先に簡約する
t2の簡約を終えてから、全体を簡約する
という方法で、「値呼び戦略」と呼ばれます。
では・・・
文法が分かり、意味も与えたところで、実際にこれを使って計算してみましょう!
ラムダ計算で計算してみる
無理・・・
数も扱えないのにどうやって計算するんですか・・・ということで、まずは道具を揃えましょう!
カリー化関数
ラムダ計算では複数引数を受け取る関数はないので、関数を返す関数をよく使います。.カリー化関数 λx.λy.x に λa.a と λb.b を渡す..
.
(λx.λy.x) (λa.a) (λb.b)−→ (λy.(λa.a)) (λb.b)−→ λa.a
λx.(λy.x)自体は関数を返す関数だけど、2つの引数をとる関数と同じような働きをする!
カリー化関数の略記法
いちいちカリー化関数書くの面倒なので、略記法を導入します。.上と下の記述は交換可能..
.
λx.λy.tλxy.t
真偽値
関数で表しましょう。.真偽値を表す関数..
.
真:λtf.t偽:λtf.f
なんでこれが真偽値?
真偽値 (2)
真がλtf.t、偽がλtf.fだったとして、
if cond then x else yを、cond x yとするcondに真を入れてみる
((λtf.t) x) y(λf.x) yx
condに偽を入れてみる((λtf.f) x) y(λf.f) yy
真偽値として働いている!
自然数
真偽値同様、関数で表現します。.自然数を表す関数..
.
0:λsz.z1:λsz.s z2:λsz.s (s z)3:λsz.s (s (s z)))
zに sを何回適用するかで自然数を表します。指で数を数えるのに似てますね。
次の数を求める関数 succ
.succ関数...λn.λsz.s (n s z)
1. 自然数 n は λsz.t の形をしている
2. n に s と z を渡せば、t の部分が取り出せる
3. t にもう一回 s を適用すれば、次の数になる!
足し算してみる
.add関数...λmn.λsz.m s (n s z)
1. 自然数 m は λsz.s (s (. . . (s z) . . . )) の形をしている (s は m 個)
2. 自然数 n は λsz.t の形をしている(t には n 個の s が含まれる)
3. 自然数 m の z 部分を n の t 部分に入れ替えれば、足し算ができる!
2 + 3
1. (λmn.λsz.m s (n s z)) (λsz.s (s z)) (λsz.s (s (s z)))
2. (λn.λsz.(λsz.s (s z)) s (n s z)) (λsz.s (s (s z)))
3. λsz.(λsz.s (s z)) s ((λsz.s (s (s z))) s z)
4. λsz.(λz.s (s z)) ((λsz.s (s (s z))) s z)
5. λsz.(λz.s (s z)) ((λz.s (s (s z))) z)
6. λsz.(λz.s (s z)) ((s (s (s z))))
7. λsz.(λz.s (s z)) (s (s (s z)))
8. λsz.(s (s (s (s (s z)))))
sが 5個あるので、2 + 3できました!
掛け算してみる
.mul関数...λmn.λsz.m (n s) z
1. 自然数 n は λsz.s (s (. . . (s z) . . . )) の形をしている (s は n 個)
2. 自然数 n に s だけ適用したものは、引数に sを n 回適用する関数になる
3. それを自然数 m の s として渡すので、s をn 回適用したものが m 個作られる
4. それに z を渡してあげれば、m と n を掛け合わせた結果の自然数になる!
2× 3
1. (λmn.λsz.m (n s) z) (λsz.s (s z)) (λsz.s (s (s z)))
2. (λn.λsz.(λsz.s (s z)) (n s) z) (λsz.s (s (s z)))
3. λsz.(λsz.s (s z)) ((λsz.s (s (s z))) s) z
4. λsz.(λsz.s (s z)) (λz.s (s (s z))) z
5. λsz.(λz.(λz.s (s (s z))) ((λz.s (s (s z))) z)) z
6. λsz.(λz.(λz.s (s (s z))) (s (s (s z)))) z
7. λsz.(λz.(s (s (s (s (s (s z))))))) z
8. λsz.(s (s (s (s (s (s z))))))
sが 6個あるので、2× 3できました!
そのほかの計算
以下の話題は時間の関係上、省略します。
自然数の引き算、割り算
再帰
Church-Rosser性
ラムダ計算を拡張してみる
ラムダ計算の拡張
さすがに、生のラムダ計算を扱うのはつらい→拡張しましょう!
記法の拡張
2 + 3を計算するだけで、.2 + 3...(λmn.λsz.m s (n s z)) (λsz. s (s z)) (λsz.s (s (s z))))
つらい・・・
数値の導入
数詞 (0とか 1とかそういうやつ)と関数で作った自然数を対応付けることができる。2 に対して λsz.s (s z)) を対応付けるようにすれば、人間にとってよりわかりやすい!ついでに、+ も λmn.λsz.m s (n s z) に対応付けてしまえば、2 + 3 はそのまま、..2 + 3
と記述できる! n に 2 を足す関数なら、..λn.n+ 2
分かりやすい!
真偽値の導入
ついでに真偽値も導入しましょう。true と λtf.t を、false と λtf.fを対応付けます。if-then-elseも導入しましょう。とりあえず、if cond then x else yを、cond x yに対応付けましょう。.if-then-elseを使った例...λbmn.if b then m+ n else m ∗ nb が真なら m+ n を、偽なら m ∗ n を計算する関数
計算体系の拡張
記法だけじゃなくて、計算体系も拡張しましょう!
型の導入
本当はここからの話をしようかな、と思ってたんですが・・・色んな意味で時間がなかったので、ここからの拡張は各自の課題ということで。詳しくは、
をどうぞ!
宣伝!
この後の懇親会で、ちょうどその本の読書会があるそうですよ!興味のある人はオーム社のサイトからPDF版を購入して参加しましょう!