haXeで作るプログラミング言語(12)

関数がクロージャになるように変更


みなさんは、クロージャってご存知でしょうか?
正確に説明となると難しいですが、簡単にいうと親の関数の環境も参照できる関数をクロージャといいます。
親の親の関数の環境も、親の親の親の関数の環境も、と祖先の環境を参照できる関数といったほうがいいのでしょうか?
ま、そんなやつです。


今回は、環境を持った関数を作成します。

co=fun(a){fun(b){a=a+b}} c=co(0)println(c(1))println(c(1))c(1)

というプログラムを実現します。
このcoという関数は関数を返す関数です。
coが返す関数は内部にa変数を持った状態で帰ります。
そのため、c = co(0)のcはfun(b){a=a+b}で、最初aは0なので、1が返ります。
次にもう一度呼び出すとaは2なので、2が返ります。
このように関数なのに、aという値を持った関数になります。
なぜこのようなことができるのか?というと、c関数が環境を持っているからです。


そんなカウンターを実現してみます。


現状の処理系は、環境は関数内でしか参照できません。
これを親の環境も参照できるようにすればクロージャとして動作するようにできます。
今回は現在はメジャーな静的スコープ(static scope)レキシカルスコープとも呼ばれる構文上で決まる親の環境を参照することにします。
静的スコープに対して動的スコープ(dynamic scope)というのもあります。(perlのlocal変数など)
動的スコープの場合は、スタック構造の1つ上を参照すればよくて簡単です。


静的スコープを実現するには関数を変数に保存するときに環境も一緒に保存するようにします。

そして、変数の値を取得する際に、自分の関数の環境に変数がなかった場合は親の環境を参照するようにします。

ということで、プログラム完成です。

コンパイルして

neko Calc12

と実行すればうまく動くはず。

とりあえず、サンプルが動くようにバグ取りました。haXeenum使った言語作りはしんどいので、もういやです。(笑
次回は、最終回。マクロを使えるようにします。そして、新たなシリーズでは、phpで言語を作ります。
なぜ、phpなのかというと、最近phpを仕事で使っているからです。


以下ソースです。

続きを読む