S f g x = (f x) (g x)
K x y = x
SKIコンビネータだね。できるよ。
それってどうやってやるの? ほんとにS
とK
だけで全部できるの?
そう、できる。方法はいくつかあるけど、わかりやすいものとしては「λリフティング」と「α-消去」を使う方法がある。
なんか難しそう?
少しずつやっていけば大丈夫。順に説明していこう。
ええと、つまりどういうこと?
例えば、λ式で関数を定義する場合、
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
こんな形になるよね。
うん。
それを、
変換前:
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
変換後:
Y f = (L f) (L f)
L f x = f (M x)
M x v = (x x) v)
こういう風に、複数のコンビネータの定義に変換する。右辺からλの記号が無くなるようにするんだ。
λを無くしちゃうんだ。
そう。この次の「α-消去」はλが無い式を対象にしているのでλを消しておく必要があるんだ。
じゃあこの例を見ながら説明しよう。
λリフティングのために、内側にあるλから順に消していく。まず最初は一番内側にある“λv. ((x x) v
”だ。まずはコンビネータの名前を決める。名前はなんでも良いけど他と被らない名前にする。ここでは“M”にしよう。
変換前:
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
変換中の部分:
λv. (x x) v
変換後:
Y = ...
M ... = ...
さて、では“M ... = ...
”と置いて、左側の...の部分を決めよう。
変換中の部分には変数が2つ使われているね。
えっと、つまり?
変換前:
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
変換中の部分:
λv. (x x) v
変換後:
Y = ...
M ... = ...
“x
”と“v
”。この2つはパラメータである“v
”とそれ以外である“x
”に分けられる。パラメータの方は「束縛変数」と言い、それ以外は「自由変数」という。
「そくばくへんすう」と、「じゆうへんすう」。
そう。それでM
のパラメータは「自由変数」全てと「束縛変数」とする。
変換前:
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
変換中の部分:
λv. (x x) v
変換後:
Y = ...
M x v = ...
つまりこういう形になる。
順番はなんでもいいの?
順番は自由変数が先で束縛変数が後になるようにする。話が前後するけどこのあと変換中の部分をM x
という式で置き変えるのでxが先じゃないといけないんだ。自由変数同士の順番は変えても良い。
さて、変換後の式の右辺なんだけどこっちは簡単で、変換中の部分の.の後ろそのままでいい。
つまり?
変換前:
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
変換中の部分:
λv. (x x) v
変換後:
Y = ...
M x v = (x x) v
こうなる。
これで完成?
最後に変換前の式“Y = ...
”の中で変換中の部分“λv. (x x) v
”が使われていた所を“M x
”で置き換える。
変換前:
Y = λf. (λx. f (λv. (x x) v))
(λx. f (λv. (x x) v))
変換中の部分:
λv. (x x) v
変換後:
Y = λf. (λx. f (M x)) (λx. f (M x))
M x v = (x x) v
“M x
”の後に“v
”は付けなくていいの?
うん。自由変数だけを並べればいい。これで式“λv. (x x) v
”のλリフティングが完了した。
ええと、まとめると、
でいいの?
うん。じゃあ次は“λf. (λx. f (M x))
”でやってみよう。
まず名前を付ける。“L
”とすると、こんな風になるのかな?
変換前:
Y = λf. (λx. f (M x)) (λx. f (M x))
変換中の部分:
λx. f (M x)
変換後:
Y = ...
L ... = ...
M x v = (x x) v
うん。
次に、変数は……、“f
”と“x
”で、“f
”が自由変数、“x
”が束縛変数?
合ってる。
それで右辺は.の後ろそのままだったから、じゃあこんな感じ?
変換前:
Y = λf. (λx. f (M x)) (λx. f (M x))
変換中の部分:
λx. f (M x)
変換後:
Y = ...
L f x = f (M x)
M x v = (x x) v
うん。問題無い。
最後に変換前の式を書き換えて、こうかな?
変換前:
Y = λf. (λx. f (M x)) (λx. f (M x))
変換中の部分:
λx. f (M x)
変換後:
Y = λf. (L f) (L f)
L f x = f (M x)
M x v = (x x) v
うん。完璧。
わぁい
最後にY
にも同じことをする。この場合は自由変数が無いので、次のようになる。
Y f = (L f) (L f)
L f x = f (M x)
M x v = (x x) v
さて、λリフティングによって、一般のλ計算の式からλを含まないような式に変換できた。ここからさらにS
とK
の組み合わせに変換していこう。
その前に、S
とK
だけだと長くてわかりづらくなってしまうので、I
というコンビネータを導入しよう。
I x = x
I
はこのように、引数をそのまま返すコンビネータだ。
そのまま返すんだったら無くてもいいんじゃないの?
I x = x
W f x = (f x) x
例えば、こんな風なコンビネータW
を作りたいとする。
I x = x
W f x = (f x) x
W f x = S f I x
このとき、コンビネータW
はこんな風にS
とI
を使って表せる。
ええと、そうなの?
I x = x
W f x = (f x) x
W f x = S f I x = (f x) (I x) = (f x) x
式を変形すると同じになるよ。
うーん……、うん、たしかにそうだね。
それで、I
はS
とK
で表わせるんだっけ?
I x = x
I = S K K
そう。こんな感じで表せる。
これでI
になるの?
I x = x
I = S K K
(S K K) x = (K x) (K x) = x
S K K
にx
を与えるとこんな風になってx
が戻ってくる。
……これって、2つ目のK
は使われてないの?
そう。だからS K S
でもS K (K K)
でもなんでもいい。S K K
と定義することが多いけどね。
S f g x = (f x) (g x)
K x y = x
I x = x
T x y = y x
例えば、こういうコンビネータT
があったとする。
T x y = y x
T x = S I (K x)
T = S (K (S I)) K
ここから変数を1つずつ消していって、最後にはS
とK
とI
だけにする。
これでちゃんと元のままなの?
T x y = y x
T x = S I (K x)
T = S (K (S I)) K
S I (K x) y = (I y) (K x y) = y x
例えば、y
だけを消した式にy
を与えると元の式になる。x
の方も同様だ。
T x y = y x
T x y = □ y
ただし、□はyを含まない式
こんな風に式を立てて、□
がわかったらy
を両辺から消す。
T x y = y x
T x y = □ y
ただし、□はyを含まない式
T x = □
つまり、変数y
を含む式から変数y
を消去するためには、□ y
が元の式と同じになるような□
を求めればよい。
変数y
の消去を「y
-消去」と言う。変数x
であれば「x
-消去」。まとめて「α-消去」と言う。
「あるふぁしょうきょ」。
うん。その具体的な方法なんだけど、今回もやはり式の内側から処理していく。
T x y = y x
T x y = y x
y = □ y
y = □ y
と置くと、□
はなにになるかな?
……うーんと、これってもしかしてさっきのI
?
T x y = y x
y = I y
そう。だからT
は次のように変形できる。
T x y = y x
y = I y
T x y = (I y) x
T x y = y x
T x y = (I y) x
T x y = y x
T x y = (I y) x
x = □ y
この場合は□
はどうなるかな?
うーんと、……y
からx
を作るのって、できるの?
□
の部分は1つのコンビネータとは限らなくて、複雑な式でもいい。その中にx
が含まれていてもいいよ。
y
はいらないけどどうするの?
要らないものを捨てたいときにはK
を使うといい。
K
を使う……。つまり、K x y = x
だから、□
はK x
?
T x y = y x
T x y = (I y) x
x = K x y = (K x) y
そう。だからT
はさらに次のように変形できる。
T x y = y x
T x y = (I y) x
x = K x y = (K x) y
T x y = (I y) (K x y)
T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
y
自身をy
-消去するとI
になる。x
をy
-消去するとK x
になる。ここで、2つ目の規則はさらに一般化して次のように書ける。
T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
y
自身をy
-消去するとI
になる。y
を含まない式X
をy
-消去するとK X
になる。ここでX
はただの変数だけでなく、複雑な式でいい。この一般化はしなくてもいいけど、した方が消去後の式が小さくなる。
さて、λ計算の式はλと変数と関数適用でできていた。λは最初のλリフティングで消えていて、変数の場合は今見た規則でα-消去できる。あとは関数適用の場合だ。
T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
(I y) (K x y) = □ y
こういう風におくと、□
はなにになるだろうか。
うーんと、いままでS
使ってなかったからS
使う?
そう。
じゃあ、S f g y = (f y) (g y)
だったから……、□
はS I (K x)
でいいのかな?
T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
(I y) (K x y) = (S I (K x)) y
そう。完璧。
えへへ。
するとT
は次のように変形できる。
T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
(I y) (K x y) = (S I (K x)) y
T x y = (S I (K x)) y
T x = (S I (K x))
これでy
を消去できた。関数適用のy
-消去は一般的には次のような規則になる。
T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
T x y = (S I (K x)) y
T x = (S I (K x))
F
とX
をy
-消去した結果がそれぞれF1
とX1
であるとき、関数適用F X
をy
-消去するとS F1 X1
となる。T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
T x y = (S I (K x)) y
T x = (S I (K x))
ええと、まとめるとこうかな?
I
、K
、S
、を使う。
そう。さらに最適化として次の規則を加えてもよい。
X
が変数y
を含まないとき、式X y
をy
-消去するとX
になる。元々y
-消去した形になってるからだね。
これでλ計算の全ての式がS
とK
だけで表せるようになった。
2つだけで表わせるなんてなんか不思議だね。
実は1つだけでも表せる。
えっ、ほんと?
うん。だけど今日は長くなったからまたこんどね。