SKIコンビネータについて簡潔にまとまったサイトがみつからなかったので要点だけまとめました。1
ラムダ計算式とは
関数f(x)=x+2
をラムダ計算では λx.x+2
と表す。λx.x
ならf(x)=x
、つまり入力値をそのまま返す関数となる。
xy
のように2つ並べられている時はx
にy
を引数として適用することを意味する。λx.((xy)z)
は単に λx.xyz
と書ける。各関数は左結合であり順序が明確な時はこのようにカッコを省略することができる。
λxy.x
のように左辺に2つ並べたら、xとyの2つの引数をとる関数を意味する。この場合はyの値を無視してxをそのまま帰す関数f(x,y)=x
となる。
λx.xy
にある2つの変数 x y
のうち、パラメータとして使われる変数(この場合はx
)を束縛変数(bound variable)、それ以外は自由変数(free variable)という。
λリフティング
ラムダ式の中のλ
を取り除きコンビネータで置き換える。例として下記の式の場合を考える。
Y = λf.(λx.f(λv.(xx)v))(λx.f(λv.(xx)v))
まず一番内側のカッコ内にあるλ
の箇所、λv.(xx)v
を対象とする。コンビネータを仮にM
と置く。M
のパラメータは自由変数を先に書き、後ろに束縛変数を書く。右辺は元の式のままでMxv=(xx)v
となる。
これを最初の式のλv.(xx)v
と置き換える。この時、束縛変数は置く必要がない。2
Y = λf.(λx.f(Mx))(λx.f(Mx))
次に(λx.f(Mx))
を置き換える。コンビネータ L
と置いて Lfx = f(Mx)
。これを元の式に適用する。x
は束縛変数なので消去されて下記のようになる。
Y = λf.(Lf)(Lf)
最後にこの式のλ
をとる。Y
には束縛変数fしかないのでYf = (Lf)(Lf)
となる。以上をまとめると元のラムダ式をλリフティングした結果は下記のようになる。
Yf = (Lf)(Lf)
Lfx = f(Mx)
Mxv = (xx)v
SKIコンビネータ
S K I
3つのコンビネータを下記のように定義するとすべてのラムダ式をこれらだけで表すことができる。3
Sfgx = (fx)(gx)
Kxy = x
Ix = x
I
は入力値をそのまま返すだけのコンビネータ。K
は(x y)
の2つのパラメータをとるがy
を無視してx
を返す。
α-消去
T x y = y x
というコンビネータTがあるとする。これはパラメータ x y
の適用順を逆にして y x
を返す。これは下記のように変形できる。
Txy = yx ... Iy=yなので
= (Iy)x ... Kxy=xなので
= (Iy)(Kxy) ... Sfgxのf=I,g=Kx,x=yとおくと(Iy)(Kxy)は(fx)(gx)の形式なので
= SI(Kx)y
∴Tx = SI(Kx) ... y消去完了
Tx = SI(Kx) ... Kxy=xよりK(SI)x=(SI)となるので
= (K(SI)x)(Kx) ... Sfgxのf=K(SI),g=K,x=xとおいて
= S(K(SI))Kx
∴T = S(K(SI))K ... x消去完了
このようにしてパラメータを消去していくことをα-消去という4。これでTをSKIで表現することができた。
オンラインでSKIコンビネータを解釈してくれるサービスに投げると動作を確認できる。
http://ski.aditsu.net/
先程のS(K(SI))K
を入れるRunを押すと(x0->(x1->x1(x0)))
となるのでたしかに引数を
x0,x1
の順番に取得したのに`x1,x0`の順番で合成していることがわかる。
参考サイト
- 高階ことりちゃんと学ぶSKIコンビネータ
- http://www.tatapa.org/~takuo/kotori_ski/index.html
- きっかけはここだったのですが、ラムダ書式の説明が足りないのとTxy = yxのy消去だけでx消去がなかったので自力で説いてみました。
- Wikipedia ラムダ計算 https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%A0%E3%83%80%E8%A8%88%E7%AE%97
- Wikipedia SKIコンビネータ計算 https://ja.wikipedia.org/wiki/SKI%E3%82%B3%E3%83%B3%E3%83%93%E3%83%8D%E3%83%BC%E3%82%BF%E8%A8%88%E7%AE%97