ギリシャ🇬🇷文字のλを用いることに由来する
型付きの (typed) ラムダ計算もあるが、ここでは型無しの (untyped) ラムダ計算を紹介する
次の言葉の意味を調べてみよう
変数を表す記号が \(x\), \(y\), \(x'\), \(y'\), \(x_1\), \(x_2\), … のように定められているとする
以下の形はラムダ式である
変数 — 任意の変数記号 \(x\), \(y\), …
関数適用 — \(M\), \(N\) をラムダ式とするとき \((MN)\)
関数抽象 — \(M\) をラムダ式、\(x\) を変数とするとき \((\lambda x.M)\)
直観的には、関数 \(M\) を引数 \(N\) に適用したもの (関数 \(M\) を引数 \(N\) で呼び出した結果)
プログラミング言語では関数適用は f(a) のように書くことが多い
直観的には、引数 \(x\) を受け取り、\(M\) を返す関数
JavaScript などでは
function(x) { return M; }
あるいは
x => M
のように書く
BNF で表現すると以下の \(M\) がラムダ式を表す
| \(M\) | \(::=\) | \(V\) | \(\texttt{(} M M \texttt{)}\) | \(\texttt{(} \lambda V \texttt{.} M \texttt{)}\) |
| \(V\) | \(::=\) | \(x\) | \(y\) | \(z\) | \(\cdots\) |
1, 2, 3, … や +, - などの定数を導入する場合もある
しかし以降は変数・関数適用・関数抽象の 3 つのみからなる純ラムダ計算を紹介する
\((\lambda x. x)\) — \(x\) という引数を受け取り、\(x\) をそのまま返す関数
C ならば
int id(int x) { return x; }
という関数 id に相当する
ラムダ式では \(x\) が
int 型に限らないが、C では便宜上 int 型にしている
\((\lambda x. (\lambda y. x))\) — \(x\) という引数を受け取り、\((\lambda y. x)\) という関数を返す関数
つまり式全体は関数を返す関数である
ラムダ記法では“関数を返す関数”で、多引数関数の代用とする
つまり \((\lambda x. (\lambda y. x))\) は C の記法では、
int foo(int x, int y) { return x; }
と表す 2 引数の関数である
このように、多引数関数を“関数を返す関数”として表現することを、 カリー化 (currying)と言う
\((\lambda f. (\lambda x. (f (f x))))\)
—
関数 \(f\) とデータ \(x\) を受け取って、\(f\) を \(x\) に 2 回適用する関数
\((\lambda x. M)\) という部分式があるとき \(x\) はこの部分式で束縛されているという
なお \(\lambda\) のすぐあとに書かれている下線部の箇所:
\((\lambda \underline{x}. (x
y))\),
\(((\lambda \underline{z}. z) z)\) は、そもそも変数の出現と言わない
(束縛とも自由とも言わない)
以下のラムダ式の変数の出現のうち、どれが自由変数で、どれが束縛変数か?
\((\lambda x. (y x))\)
\((a (\lambda b. b))\)
\(((\lambda w. w) w)\)
\((\lambda x. (\lambda y. ((x y) (z y))))\)
int f(int x, int y) { return x + y; } int f(int dog, int cat) { return dog + cat; }
このような関数の仮引数の名前の付け替えを
α変換
(alpha conversion) と呼ぶ
ただし、以下の 2 つの式は同じではない
名前が衝突する場合は α変換 は許されない
以下のうち α変換によって同等となるラムダ式を選べ
\((\lambda x. (x y))\) と \((\lambda z. (z y))\)
\((\lambda x. (\lambda y. (x y)))\) と \((\lambda y. (\lambda x. (y x)))\)
\((\lambda x. (\lambda y. y))\) と \((\lambda z. (\lambda y. y))\)
\((\lambda a. (\lambda b. b))\) と \((\lambda b. (\lambda a. b))\)
ラムダ式 \(M\), \(N\) と変数 \(x\) があるとき
\[M[x:=N]\]
は\(M\) の中の自由な \(x\) の出現をすべて \(N\) で置き換えて得られるラムダ式を表す
(この \(\_[\_:=\_]\) という記法自体はラムダ式の枠外の、 “メタ”な記法である)
例1: \((\lambda y. (x y))[x := (\lambda z.z)] = (\lambda y. (\textcolor{#d64557}{(\lambda z.z)} y))\)
例2:
\((\lambda y. (x y))[y := (\lambda z.z)] = (\lambda y. (x y))\)
(変わらない)
ラムダ式の中の
\(((\lambda \textcolor{#009c56}{x}. \textcolor{#5076ea}{M}) \textcolor{#d64557}{N})\)
という形をした部分式を
\(\textcolor{#5076ea}{M}[\textcolor{#009c56}{x} := \textcolor{#d64557}{N}]\)
に書き換える変換をβ簡約 (beta reduction) と呼ぶ
β簡約できるカタチのラムダ式の部分式
\[((\lambda \textcolor{#009c56}{x}. \textcolor{#5076ea}{M}) \textcolor{#d64557}{N})\]をβ基 (\(\beta\) redex) と呼ぶ
例1: \((((\lambda \textcolor{#009c56}{f}. \textcolor{#5076ea}{(\lambda x. (f (f x)))}) \textcolor{#d64557}{(\lambda y. y)}) z)\) \(\ \ \stackrel{\beta}{\rightarrow} ((\lambda \textcolor{#009c56}{x}. \textcolor{#5076ea}{((\lambda y. y) ((\lambda y. y) x))}) \textcolor{#d64557}{z})\) \(\ \ \stackrel{\beta}{\rightarrow} ((\lambda y. y) ((\lambda \textcolor{#009c56}{y}. \textcolor{#5076ea}{y}) \textcolor{#d64557}{z}))\) \(\stackrel{\beta}{\rightarrow} ((\lambda \textcolor{#009c56}{y}. \textcolor{#5076ea}{y}) \textcolor{#d64557}{z})\) \(\stackrel{\beta}{\rightarrow} z\)
例2:
\(((\lambda \textcolor{#009c56}{x}. \textcolor{#5076ea}{(x x)})\textcolor{#d64557}{(\lambda x.
(x x))})\)
\(\ \ \stackrel{\beta}{\rightarrow} ((\lambda x. (x x))(\lambda x. (x
x)))\)
\(\ \ \stackrel{\beta}{\rightarrow} \ldots\)
次のラムダ式を(1 ステップ)\(\beta\) 簡約せよ。
\(((\lambda x. (x y)) (\lambda z. (z y)))\)
\(((\lambda x. (\lambda y. x)) (\lambda z. z))\)
\(((\lambda x. (x y)) (\lambda w. w))\)
\(((\lambda y. (x y)) (\lambda w. w))\)
ここまで説明したラムダ式の文法は、
β 簡約の説明のためには都合がよい
括弧をつけたり外したりする必要がない
しかし、括弧が多くなりすぎる
そこで、略記法を導入する
\((\lambda x. M_1) M_2\)
は括弧を省略してしまうと、
\(\lambda x. M_1 M_2\)
となってしまい、
\(\lambda x. (M_1 M_2)\)
と区別がつかないので、括弧は省略できない
BNF で表現すると以下のようになる。
| \(M\) | \(::=\) | \(F\) | \(\lambda\ W\ \texttt{.}\ M\) |
| \(F\) | \(::=\) | \(A\) | \(F\ A\) |
| \(A\) | \(::=\) | \(V\) | \(\texttt{(}\ M\ \texttt{)}\) |
| \(W\) | \(::=\) | \(V\) | \(V\ W\) |
| \(V\) | \(::=\) | \(x\) | \(y\) | \(z\) | \(\cdots\) |
\(\beta\) 簡約をするときには、略記法をいちど(頭の中で)正式な記法に戻して \(\beta\) 簡約し、 再度略記法にする必要がある
次のラムダ記法の正式記法を、できるだけ括弧を少なくした略記法に変換せよ
\((\lambda x. (\lambda y. ((x y) (x y))))\)
\((\lambda x. (((\lambda y. x) (\lambda z. z)) x))\)
次のラムダ記法の略記法を正式記法に変換せよ。
\(\lambda x . (\lambda y. y) x\)
\(\lambda x y. x x y\)
有名なラムダ計算の性質を証明なしで紹介する
一つのラムダ式に幾通りもの \(\beta\) 簡約が可能なとき、 別の\(\beta\) 基を選ぶと別の形に枝分かれする
しかし、うまく何回か \(\beta\) 簡約すると再び合流させることができる
特に、ラムダ式に正規形が存在するならば、それは一つしかない
正規形を持つラムダ式でも、下手に \(\beta\) 基を選べば、 無限に \(\beta\) 簡約をし続けうる
\((\lambda x y. y) \underline{((\lambda x. x x) (\lambda x. x x))}
\rightarrow (\lambda x y. y) \underline{((\lambda x. x x) (\lambda x. x x))}\)
\( \rightarrow \cdots\)
しかし、最も左から始まる \(\beta\) 基を選べば、 正規形を持つラムダ式ならば、必ず正規形に到達する
\(\underline{(\lambda x y. y) ((\lambda x. x x) (\lambda x. x x))} \rightarrow (\lambda y. y) \)
| \((\lambda x . f x x)((\lambda y z. z) w)\) | ||
| 最左 \(\beta\) 基 🡗 | 🡖 右側の \(\beta\) 基 | |
| \(f ((\lambda y z. z) w) ((\lambda y z. z) w)\) | \((\lambda x . f x x)(\lambda z. z)\) | |
| \(\beta\) × 2🡖 | 🡗\(\beta\) | |
| \(f (\lambda z. z) (\lambda z. z)\) | ||
以下のラムダ式を(1 ステップ)最左簡約せよ。
\(((\lambda x. ((\lambda y. x) x)) (\lambda z. z))\)
\(((\lambda x. (x x))((\lambda y. y) z))\)
真偽値・整数・組などのデータ型は純ラムダ計算の中で表現できる
以下のように定義する、
\(\begin{align*} \textit{true} & \stackrel{\textrm{def}}{\equiv} \lambda t f. t \\ \textit{false} & \stackrel{\textrm{def}}{\equiv} \lambda t f. f \\ \textit{if} & \stackrel{\textrm{def}}{\equiv} \lambda c t e. c t e \end{align*}\)
すると
\(\textit{if}\:\textit{true}\: M_1\:M_2 \stackrel{\beta}{\twoheadrightarrow} M_1\) であり、
すると\(\textit{if}\:\textit{false}\: M_1\:M_2
\stackrel{\beta}{\twoheadrightarrow} M_2\) である
上記の \(\beta\) 簡約を 1 ステップずつ書いて確かめよ。 つまり、
\[\begin{align*} \textit{if}\:\textit{true}\: M_1\:M_2 & \equiv (\lambda c t e. c t e)\:\textit{true}\:M_1\:M_2\\ & \rightarrow (\lambda t e. \textit{true}\:t\:e)\:M_1\:M_2 \\ & \rightarrow …\\ & \rightarrow M_1 \end{align*}\]であることを示せ
自然数 \(n\) に対してチャーチの数 \(c_n\) を以下のように定義する
\(\begin{align*} c_0 & \stackrel{\textrm{def}}{\equiv} \lambda f x. x \\ c_1 & \stackrel{\textrm{def}}{\equiv} \lambda f x. f x \\ c_2 & \stackrel{\textrm{def}}{\equiv} \lambda f x. f (f x) \\ c_3 & \stackrel{\textrm{def}}{\equiv} \lambda f x. f (f (f x)) \\ & \vdots \\ c _n & \stackrel{\textrm{def}}{\equiv} \lambda f x. \underbrace{f (f (\cdots (f}_{n個} x)\cdots)) \end{align*}\)さらに以下のように定義する
\(\begin{align*} \textit{plus} & \stackrel{\textrm{def}}{\equiv} \lambda m n f x. m f (n f x) \end{align*}\)すると \(\textit{plus}\:c_m\:c_n \stackrel{\beta}{\twoheadrightarrow} c_{m+n}\) である
先ほどの \(\beta\) 簡約を、m = 3, n = 2 などの具体例を用いて 1 ステップずつ書いて 確かめよ。つまり、
となることを示せ
次の関数をチャーチの数に対するラムダ式として定義せよ
すると次が成り立つ
\(\begin{align*} \textit{fst}\:(\textit{pair}\:M_1\:M_2) & \stackrel{\beta}{\twoheadrightarrow} M_1 \\ \textit{snd}\:(\textit{pair}\:M_1\:M_2) & \stackrel{\beta}{\twoheadrightarrow} M_2 \end{align*}\)問: 確かめよ
リスト型を表現するために、
| \(\textit{cons}\) | — Haskell の (:) |
| \(\textit{nil}\) | — Haskell の [] |
| \(\textit{isNull}\) | — Haskell の null |
| \(\textit{head}\) | — Haskell の head |
| \(\textit{tail}\) | — Haskell の tail |
に対応するラムダ式を定義せよ
以下のようなラムダ式を \(Y\) コンビネーターと呼ぶ
\(\begin{align*} Y & \stackrel{\textrm{def}}{\equiv} \lambda f. (\lambda x. f (x x)) (\lambda x. f (x x)) \end{align*}\)すると、任意のラムダ式 \(F\) に対して、以下が成り立つ
\(Y F \stackrel{\beta}{\rightarrow} (\lambda x. F (x x)) (\lambda x. F (x x))\)この右辺を \(U\) と置くと、以下の変換列が得られる
\(U\stackrel{\beta}{\rightarrow} F U \stackrel{\beta}{\rightarrow} F (F U) \stackrel{\beta}{\rightarrow} \cdots \stackrel{\beta}{\rightarrow} F (F (\cdots (F U) \cdots))\)\(U\) は \(F\) の不動点と考えられる ため、\(Y\) を不動点演算子 (fixed point operator) とも呼ぶ
この \(Y\) を使うとラムダ計算の中で再帰を表せる
例えば \(\textit{fact}\)というラムダ式を次のように定義する
\(\textit{fact} \stackrel{\textrm{def}}{\equiv} Y\:\underbrace{(\lambda f x. \textit{if}\:(\textit{zero}\:x)\:c_1\:(\textit{mult}\:x\:(f\:(\textit{pred}\:x))))}_{F\:とおく}\)\(F\), \(U\) を次のように定義する
\(\begin{align*} F &\stackrel{\textrm{def}}{\equiv} \lambda f x. \textit{if}\:(\textit{zero}\:x)\:c_1\:(\textit{mult}\:x\:(f\:(\textit{pred}\:x))) \\ U &\stackrel{\textrm{def}}{\equiv} (\lambda x. F (x x))(\lambda x. F (x x))\\ \end{align*}\)すると、
| \(\textit{fact}\:c_3\) | \(\equiv\) | \(Y\:F\:c_3\) | \(\stackrel{\beta}{\rightarrow}\) | \(U\:c_3\) | \(\stackrel{\beta}{\rightarrow}\) | \(F\:U\:c_3\) |
| \(\stackrel{\beta}{\rightarrow}\) | \(\textit{if}\:(\textit{zero}\:c_3)\:c_1\:(\textit{mult}\:c_3\:(U\:(\textit{pred}\:c_3)))\) | |||||
| \(\stackrel{\beta}{\rightarrow}\) | \(\cdots\) | \(\stackrel{\beta}{\rightarrow}\) | \(\textit{mult}\:c_3\:(U\:c_2)\) | |||
| \(\stackrel{\beta}{\rightarrow}\) | \(\cdots\) | |||||
上の \(\beta\) 簡約の続きを 1 ステップずつ確かめよ
お疲れさまでした