compile-time schemeで副作用のある操作を行う

set!なんて静的にどうにかなりそうなのじゃなくて、I/Oとか乱数とかdynamicに評価しないと絶対どうにもならないやつをどうするか―― つまりモナド的なアレの導入を!
まず、静的に評価可能な操作とそうでない操作は静的に識別可能(ややこしい)。すなわち:

  1. 定数の評価は静的に決定可能
  2. 変数の評価は、今までにset!が適用されていないものであれば静的に決定可能
    • set!が適用されたものでも、それが静的に決定可能な文脈の上でなされたものであれば静的に決定可能
  3. 静的に決定可能なプリミティブ関数の参照は静的に決定可能
  4. 静的に決定可能な操作のみで構成され、静的に決定可能な変数しか参照していないクロージャの参照は静的に決定可能
  5. 静的に決定可能なクロージャ/関数に静的に決定可能な引数を適用した結果は静的に決定可能
  6. その他の操作は、静的に決定不可能

たとえば副作用ありの関数pと副作用なしの+があった場合、

(p (+ 1 2))

があった場合、(+ 1 2)は静的に決定可能であるので

Evaluator<Cons<Symbol<'p'>,Cons<Cons<Symbol<'+'>,Cons<int_<1>,Cons<int_<2>,nil>>,ni>l>>::result
→
DynamicEval<Cons<Symbol<'p'>,Cons<int_<3>,nil>>>

すなわち

(p 3)

に展開されて、つまり定数畳み込み操作をコンパイル時にやることになると。
それにしても悔やまれるのはC++にevalが存在しないことで、REPL使ったが最後全部動的評価する羽目になるからな!なんのありがたみもない。(evalDanoMoi関数を持たないDanoMoiを想像するとよい)