Compilation と execution の分離

しかし今回の Shiro さんの指摘は「compiler 型のスゝメ」なのだろうか。いや、先方の意図がどうあれ、そういう風に心を動かされた。別に macro がどうとかいう話とは関係無しに前から気になっていたことでもある。太田さんは SigScheme を始めるときに compiler 型と現在の純粋 interpreter の両方を考察したのだろうか、それとも与し易そうな方を選んだだけなのだろうか。後者ならば、いずれは compile phase をわけるつもりはあるのだろうか。
Compiler 型はほとんどソースを読んでないし、SICP もまだ compiler の章は読んでないので詳しくは分かり兼ねるが、今のところの想像で言うと interpreter が他とはこういう違いがありそうだ。

Compiler 型の advantages

速くなる

言うまでもない。が、uim のように小さい S 式を繰り返し渡しては評価するように要求して来られると、compile の overhead が勝るかもしれない。ガチガチに最適化をかけようとしなければいいような気もする。そもそも uimUIM_EVAL_STRING() はどれぐらいの頻度で呼ばれてるんだろう。どっかに byte code を cache しとけないだろうか。むしろ自前 preprocessor で compile 時に byte code にするとか。

Code を compact に格納できる?

当然 byte code の設計と実際の Scheme code の相性とかに依存するけども、一部の例外を除けば、source file から読み込んだ pair とかはほとんど捨てていいような気がする。LISP では code と data は一緒だと言うけれど、実際に code の一部を data としてとっておく必要がある (とっておいた方が有利になる) のは、

  • quote and friends
  • list (library procedure)

ぐらいしか思いつかない。Byte code はあまり凝りすぎなければ (時間はかかるけど) source code をある程度は復元できるように設計できるだろうし、if などが数 bytes で表現できれば code を格納するのに必要なメモリは大きく減りそう。
ただし、前 vector map_eval() について言った、Scheme heap の代わりに C heap を消費する問題が起きるので、一概には言えない。

Macro の扱いが自然になる。

ただし code 量は増える。今の architecture だと他の仕組と癒着させられるから。

Compiler 型の disadvantages

Compiler がメモリを喰う

どの程度大きくなるか分からないけど、凝ったことをしすぎなければ、source file から読み込む code に比べて大した大きさにはならないんじゃあないか。C で書くより Scheme で書いた方が小さくなるのかな。後者の場合の bootstrap は Gauche とかで。

Evaluator が大きくなる

巨大な switch (というか SWITCH((Computed goto で素早く dispatch するため))) になる。でもこれも大した肥大化には思えない。

Compile の overhead

これにはもう言及した。

Debug が大変そう

慣れのような気も。

総合すると、SigScheme も compiler 型にした方がいいような気がする。でもこれを言い出したそもそもの発想が結構安易なのと、もうひとつ重要な事に、compiler 型がいいのなら今自分がめんどくさい*1のに耐えてやってる改造は何なのかという話になるので、「甘い、甘すぎるわこの青二才が!」と言わんばかりに勘違いをあげつらって突っ込んでほしかったりする。

PS: 改造の方はもうちょいです…

*1:この日記の entry 自体が息抜きに書いてるものなのだ!