F#の基礎(嘘)
bleis-tift
December 7, 2013
自己紹介

id:bleis-tift / @bleis
なごやではたらくゆるふわ.NETer
好きな関数型言語は F#
Microsoft MVP for Visual F#
なんか話せって言われたので・
・
・

過去の基礎勉強会での発表を使い回しても問
題ないよねっ
.NET 基礎での資料ほぼそのまま
.NET と言えば F#(異論は認める
F#の基礎と言えばラムダ計算ですよねー
ということで (型無し) ラムダ計算の話です
聞いたことある人は休憩時間です!
ことりちゃんを愛でていればいいと思うよ!
今日やること

ラムダ計算って何?
ラムダ計算で計算してみる
最終的には階乗を計算してみます
ラムダ計算って何?
その前に

関数型言語って何?
関数型言語とは
ある人曰く、
「それぞれの人が色々な特徴か
ら適当なサブセットを選んで関数型と呼ぶ」
ある人曰く、
「永続的データ構造を扱う言
語だ」
ある人曰く、
「そんなものはない。あるのは
関数プログラミングというスタイルだけだ」
「この言語は関数型言語だ!」という判断は各人に
任せるとして、個人的には「ラムダ計算に基づく
言語」は関数型言語でいいのでは?と思ってます。
よくある (かもしれない) 誤解

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

今日はこの (ないかもしれない) 誤
解を解きに来ました!
ラムダ計算とは

すごくシンプルなプログラミング言語
文法がシンプル
予約語は λ だけ

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

色々な関数型言語の基礎になっている
ラムダ計算の文法

ラムダ計算のプログラムは一つの項 (式と思って
もらえれば) として表されます
項の要素になれるのは、以下の 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) y
x

cond に偽を入れてみる
((λtf.f ) x) y
(λf.f ) y
y

真偽値として働いている!
自然数
真偽値同様、関数で表現します。
.
自然数を表す関数
.
0:λsz.z
1:λsz.s z
2:λ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)
掛け算してみる
.
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 を掛け合わせた結果の自然数になる!
ぐるぐる∼

これを簡約してみましょう
.
(λx.x x) (λx.x x)
.
たのしい!
ラムダ計算を拡張してみる
ラムダ計算の拡張

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

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 を、f alse と λ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 ∗ n

b が真なら m + n を、偽なら m ∗ n を計算する
関数
ふぅ・
・
・

ここまでで準備したものを使って、階乗を計算し
てみましょう!
階乗!
.
準備
.
Y = λg.(λx.g (x x)) (λx.g (x x))
g = λf n.if n = 0 then 1 else n ∗ (f (n − 1))
.
これをつかって、
.
3!をけいさん!
.
g (Y g) 3
if 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
できました!
まぁ、ずるしてるんですけどね!

Yってなんだよ
等値演算子定義してない
減算演算子定義してない
これらの理解や定義は各自の課題とする
この先

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

F#の基礎(嘘)