ホーム   最近   SikiWiki   編集   新規 

[SikiLanguage] [式鬼言語航海日誌]

2008-01-28

2008/01/29_005921




ということで、昨日の続きを少しだけ。実行プロセスについて。

あいかわらず自分専用メモということで、他の人に読まれることは考えていない酷い説明文になっています。

「昨日は手続きの種類分けだったね」

はい。普通の言語ですとFiber/Thread/Processぐらいの分類だと思いますが、式鬼言語の場合はForth的なものとしてプリミティブ命令的なMonomerとコマンド列のセットPolymerというのを考えています。で、Monomerというのは実装言語のC++で実行される関数(C++バインディング)を想定しているのですが……

「遅延評価のところで困っちまうわけだね」

遅延評価というのは『引数を実際に参照するときにその値を計算する』というもので、これがあると無限に続くストリームとか必要になる都度値を計算するジェネレーターとかを自然に活用できるようになりますので、かなり便利なものです。

ただ、『引数を実際に参照するときにその値を計算する』という遅延評価の挙動は、実装言語のC++と相性が悪いんですよね。

「何で? C++から遅延評価を呼べばいいんじゃないの?」

簡単に実装するならそういう実装でもいいのですが……色々と制限が発生するのと、思わぬ挙動になる可能性があるのが良くないですね。

まず、C++の関数の挙動ですが、基本的には『関数が呼び出されると、中のコードを実行して呼び出し元に戻る』という動作です。コルーチンみたいに動作中に中断することも、Schemeみたいに継続を渡すこともできません。関数は終了するまで抜け出せず、抜け出したあとは元に戻ることもはできません。

「まあ、そりゃそうだ。基本的な構造化プログラムの動作だわな」

で、Monomerは基本的に『C++で実行される関数を想定している』ということで、もしMonomer中で引数を処理したいときはMonomer中から引数を参照する必要があります。

「引数を参照するっつうことは、遅延評価が発生する、つうことだね」

はい、ここで遅延評価が発生します。つまりプリミティブ命令的で分割不可能なはずのMonomerの実行中に別の手続きが実行されるわけです。

「そりゃもうプリミティブじゃないね」

せめて遅延評価が発生した状態でMonomerの実行を中断できればいいのですが、実装言語にC++を使用している限りそんなことはできません。C++のメソッドにもコルーチンがあればなぁ。簡単に中断・復帰ができるのに。

で、具体的にどんな問題が出そうかというと、

  • 制御の動作がかなり神経質になる。気を付けないとすぐに破綻する。
  • 遅延評価の対象にPolymerを使用するのは不可。Monomerを使うか、あるいはFiber, Thread, Clothで実行して結果を引き出す必要がある。

とりあえず思い付くのはこんな感じですか。他にも色々とありそうですが。

解決方法としては、ざっと

  1. 遅延評価を捨てる
  2. Monomerの内部から(遅延評価の発生する)参照は禁止する
    1. Monomer実行前に、必要な引数の遅延評価を処理しておく
    2. C++バインディングを実装するときもPolymerの形で実装する
      引数を参照するところで分割して、遅延評価を行うMonomerを挿入する
  3. 遅延評価の対象はFiberしか許さない(Fiber以外は遅延評価しない)
  4. C++バインディングが中断に対応できるようにする。遅延評価前にC++の実行状態を記憶しておき、遅延評価後に状態を復元するようにする(手動でコルーチンをエミュレート。Polymer的な挙動)

といった感じかと。

遅延評価を捨てるのは無しにすると、お手軽に実装するなら3.で、C++バインディングに苦労してもらうなら2-1メインで2-2を併用(ループ処理などで)といったところでしょうか? Monomerの性質が失われますが、4.の案も毛嫌いするほどのものではない気がします。

「どれも悩ましいね」

スマートさからいうと2.なんですけど、実用上は3.でしょうしね。4.は破綻しにくいでしょうけどMonomerの性質が失われるのがちょっと……むむむ、どうしよう?





制作・著作: 野分(nowake) at fiercewinds.net (Creative Commons 表示-継承 2.1 日本)