高階ことりちゃんと学ぶSKIコンビネータ

進む
S f g x = (f x) (g x)
K x y   = x
ことり:

ねぇ、この前ね、λ式はみんなこんな感じの関数“S”と“K”だけで表現できるって聞いたんだけど、本当?

チョウゲンボウ:

SKIコンビネータだね。できるよ。

ことり:

それってどうやってやるの? ほんとにSKだけで全部できるの?

チョウゲンボウ:

そう、できる。方法はいくつかあるけど、わかりやすいものとしては「λリフティング」と「α-消去」を使う方法がある。

ことり:

なんか難しそう?

チョウゲンボウ:

少しずつやっていけば大丈夫。順に説明していこう。

λリフティング

チョウゲンボウ:

まず、「λリフティング」をすると、λ式をコンビネータの定義の集まりに変換できる。

ことり:

ええと、つまりどういうこと?

チョウゲンボウ:

例えば、λ式で関数を定義する場合、

 
  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)
チョウゲンボウ:

こういう風に、複数のコンビネータの定義に変換する。右辺からλの記号が無くなるようにするんだ。

ことり:

λを無くしちゃうんだ。

チョウゲンボウ:

そう。この次の「α-消去」はλが無い式を対象にしているのでλを消しておく必要があるんだ。

チョウゲンボウ:

じゃあこの例を見ながら説明しよう。

変換前:
  Y = λf. (λx. f (λv. (x x) v))
             (λx. f (λ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”のλリフティングが完了した。

ことり:

ええと、まとめると、

  1. 新しい名前を付ける
  2. 自由変数と束縛変数を=の左に並べる
  3. .の後ろを=の右に書く
  4. 変換前の式の中で変換中の式が使われていた所を、新しいコンビネータの名前と自由変数を並べた式で置き換える
ことり:

でいいの?

チョウゲンボウ:

うん。じゃあ次は“λ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 f g x = (f x) (g x)
K x y   = x
チョウゲンボウ:

さて、λリフティングによって、一般のλ計算の式からλを含まないような式に変換できた。ここからさらにSKの組み合わせに変換していこう。

チョウゲンボウ:

その前に、SKだけだと長くてわかりづらくなってしまうので、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はこんな風にSIを使って表せる。

ことり:

ええと、そうなの?

I x = x
W f x = (f x) x
W f x = S f I x = (f x) (I x) = (f x) x
チョウゲンボウ:

式を変形すると同じになるよ。

ことり:

うーん……、うん、たしかにそうだね。

ことり:

それで、ISKで表わせるんだっけ?

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 Kxを与えるとこんな風になってxが戻ってくる。

ことり:

……これって、2つ目のKは使われてないの?

チョウゲンボウ:

そう。だからS K SでもS K (K K)でもなんでもいい。S K Kと定義することが多いけどね。

チョウゲンボウ:

さて、ではλを含まないような式について、S, K, Iだけで表してみよう。

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つずつ消していって、最後にはSKIだけにする。

ことり:

これでちゃんと元のままなの?

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
チョウゲンボウ:

まず最初に最初の“y”の部分について考える。

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
チョウゲンボウ:

次に、右側の“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)
チョウゲンボウ:

ここで、2つ目の規則はさらに一般化して次のように書ける。

T x y = y x
T x y = (I y) x
T x y = (I y) (K x y)
チョウゲンボウ:

ここで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))
チョウゲンボウ:

これでひととおりα-消去ができるようになった。

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))
ことり:

ええと、まとめるとこうかな?

を使う。

チョウゲンボウ:

そう。さらに最適化として次の規則を加えてもよい。

ことり:

元々y-消去した形になってるからだね。

チョウゲンボウ:

これでλ計算の全ての式がSKだけで表せるようになった。

ことり:

2つだけで表わせるなんてなんか不思議だね。

チョウゲンボウ:

実は1つだけでも表せる。

ことり:

えっ、ほんと?

チョウゲンボウ:

うん。だけど今日は長くなったからまたこんどね。

高階ことりちゃんについて詳しくはこちら