F#の基礎(嘘)

39
F # の基礎(嘘) bleis-tift December 7, 2013

description

基礎勉強会忘年会で話せって言われたから過去の発表資料を改変してでっち上げたはいいが、結局時間がなくて発表できなかった資料です。せっかく作ったのであげておきます。

Transcript of F#の基礎(嘘)

Page 1: F#の基礎(嘘)

F#の基礎(嘘)

bleis-tift

December 7, 2013

Page 2: F#の基礎(嘘)

自己紹介

id:bleis-tift / @bleis

なごやではたらくゆるふわ.NETer

好きな関数型言語は F#

Microsoft MVP for Visual F#

Page 3: F#の基礎(嘘)

なんか話せって言われたので・・・

過去の基礎勉強会での発表を使い回しても問題ないよねっ

.NET基礎での資料ほぼそのまま

.NETと言えば F#(異論は認める

F#の基礎と言えばラムダ計算ですよねー

ということで (型無し)ラムダ計算の話です

Page 4: F#の基礎(嘘)

聞いたことある人は休憩時間です!ことりちゃんを愛でていればいいと思うよ!

Page 5: F#の基礎(嘘)

今日やること

ラムダ計算って何?

ラムダ計算で計算してみる

最終的には階乗を計算してみます

Page 6: F#の基礎(嘘)

ラムダ計算って何?

Page 7: F#の基礎(嘘)

その前に

関数型言語って何?

Page 8: F#の基礎(嘘)

関数型言語とは

ある人曰く、「それぞれの人が色々な特徴から適当なサブセットを選んで関数型と呼ぶ」

ある人曰く、「永続的データ構造を扱う言語だ」

ある人曰く、「そんなものはない。あるのは関数プログラミングというスタイルだけだ」

「この言語は関数型言語だ!」という判断は各人に任せるとして、個人的には「ラムダ計算に基づく言語」は関数型言語でいいのでは?と思ってます。

Page 9: F#の基礎(嘘)

よくある (かもしれない)誤解

「ラムダ計算に基づく言語」は関数型言語→ ラムダ式を持っていれば関数型言語だ?

今日はこの (ないかもしれない)誤解を解きに来ました!

Page 10: F#の基礎(嘘)

ラムダ計算とは

すごくシンプルなプログラミング言語文法がシンプル

予約語は λ だけ

関数しかない真偽値も、数も、条件分岐も、ループも、全部関数で表す

色々な関数型言語の基礎になっている

Page 11: F#の基礎(嘘)

ラムダ計算の文法

ラムダ計算のプログラムは一つの項 (式と思ってもらえれば)として表されます項の要素になれるのは、以下の 3つだけです

名前・・・・・・・・・・・変数

(項 項)・・・関数適用

(λ名前.項)・・・ラムダ抽象

名前には、英字一文字を使うことが多いです。

Page 12: F#の基礎(嘘)

ラムダ計算の項として有効なもの

以下の文字列の並びは、ラムダ計算の項として有効です

x

(f x)

(λx.x)

(λf.(λx.(f x)))

Page 13: F#の基礎(嘘)

カッコの省略

.

.(λf.(λx.(f x)))

の一番外側のカッコと一番内側のカッコは取り除いても曖昧になりません。..λf.(λx.f x)

以降では、曖昧性のないカッコは省略します。

Page 14: F#の基礎(嘘)

文法のおさらい

.ラムダ計算の文法..

.

t ::= < name >

| (< t > < t >)

| (λ < name > . < t >)

数値はおろか、真偽値などもない

変数が導入されるのはラムダ式の引数のみ

値はラムダ抽象 (つまり関数)のみ!

Page 15: F#の基礎(嘘)

ラムダ計算の意味

文法を定義しただけでは何の役にも立たないので、意味を与えてあげましょう!

Page 16: F#の基礎(嘘)

ラムダ計算における計算

ラムダ計算における計算とは、引数に関数を適用することです。t1 t2という項があった時に、t1がラムダ抽象だった場合に、ラムダ抽象の中の項に現れる引数を t2で置き換えます。.例えばこんな..

.

(λx.x) (λy.λz.(y z))

↓下線を引いた項に引数を与えて簡約λy.λz.(y z)

Page 17: F#の基礎(嘘)

簡約の方法

簡約の方法にはいろいろありますが、ここでは皆さんになじみの深い方法を採用します。t1 t2という項があった時、

t1から先に簡約する

t2の簡約を終えてから、全体を簡約する

という方法で、「値呼び戦略」と呼ばれます。

Page 18: F#の基礎(嘘)

では・・・

文法が分かり、意味も与えたところで、実際にこれを使って計算してみましょう!

Page 19: F#の基礎(嘘)

ラムダ計算で計算してみる

Page 20: F#の基礎(嘘)

無理・・・

数も扱えないのにどうやって計算するんですか・・・ということで、まずは道具を揃えましょう!

Page 21: F#の基礎(嘘)

カリー化関数

ラムダ計算では複数引数を受け取る関数はないので、関数を返す関数をよく使います。.カリー化関数 λ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つの引数をとる関数と同じような働きをする!

Page 22: F#の基礎(嘘)

カリー化関数の略記法

いちいちカリー化関数書くの面倒なので、略記法を導入します。.上と下の記述は交換可能..

.

λx.λy.tλxy.t

Page 23: F#の基礎(嘘)

真偽値

関数で表しましょう。.真偽値を表す関数..

.

真:λtf.t偽:λtf.f

なんでこれが真偽値?

Page 24: 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

真偽値として働いている!

Page 25: F#の基礎(嘘)

自然数

真偽値同様、関数で表現します。.自然数を表す関数..

.

0:λsz.z1:λsz.s z2:λsz.s (s z)3:λsz.s (s (s z)))

zに sを何回適用するかで自然数を表します。指で数を数えるのに似てますね。

Page 26: F#の基礎(嘘)

次の数を求める関数 succ

.succ関数...λn.λsz.s (n s z)

1. 自然数 n は λsz.t の形をしている

2. n に s と z を渡せば、t の部分が取り出せる

3. t にもう一回 s を適用すれば、次の数になる!

Page 27: F#の基礎(嘘)

足し算してみる

.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 部分に入れ替えれば、足し算ができる!

Page 28: F#の基礎(嘘)

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)

Page 29: F#の基礎(嘘)

掛け算してみる

.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 を掛け合わせた結果の自然数になる!

Page 30: F#の基礎(嘘)

ぐるぐる~

これを簡約してみましょう..(λx.x x) (λx.x x)

たのしい!

Page 31: F#の基礎(嘘)

ラムダ計算を拡張してみる

Page 32: F#の基礎(嘘)

ラムダ計算の拡張

さすがに、生のラムダ計算を扱うのはつらい→拡張しましょう!

Page 33: F#の基礎(嘘)

記法の拡張

2 + 3を計算するだけで、.2 + 3...(λmn.λsz.m s (n s z)) (λsz. s (s z)) (λsz.s (s (s z))))

つらい・・・

Page 34: F#の基礎(嘘)

数値の導入

数詞 (0とか 1とかそういうやつ)と関数で作った自然数を対応付けることができる。2 に対して λsz.s (s z)) を対応付けるようにすれば、人間にとってよりわかりやすい!ついでに、+ も λmn.λsz.m s (n s z) に対応付けてしまえば、2 + 3 はそのまま、..2 + 3

と記述できる! n に 2 を足す関数なら、..λn.n+ 2

分かりやすい!

Page 35: F#の基礎(嘘)

真偽値の導入

ついでに真偽値も導入しましょう。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 を計算する関数

Page 36: F#の基礎(嘘)

ふぅ・・・

ここまでで準備したものを使って、階乗を計算してみましょう!

Page 37: F#の基礎(嘘)

階乗!.準備..

.

Y = λg.(λx.g (x x)) (λx.g (x x))g = λfn.if n = 0 then 1 else n ∗ (f (n− 1))

これをつかって、.3!をけいさん!..

.

g (Y g) 3if 3 = 0 then 1 else 3 ∗ ((Y g) (3− 1))3 ∗ (if 2 = 0 then 1 else 2 ∗ ((Y g) (2− 1)))3 ∗ 2 ∗ (if 1 = 0 then 1 else 1 ∗ ((Y g) (1− 1)))3 ∗ 2 ∗ 1 ∗ (if 0 = 0 then 1 else 0 ∗ ((Y g) (0− 1)))3 ∗ 2 ∗ 1 ∗ 1できました!

Page 38: F#の基礎(嘘)

まぁ、ずるしてるんですけどね!

Yってなんだよ

等値演算子定義してない

減算演算子定義してない

これらの理解や定義は各自の課題とする

Page 39: F#の基礎(嘘)

この先

を読みましょう!この発表は、第 5章 (全 32章)までをまとめた感じです