compile-time schemeで変数の再定義を実装したい

つまりはset!。
変数テーブルはネストした型として表現されているので、一度束縛された値を変更することはできない。さてどうするか。
単純な例なら、意外とあっさり解決する。evalは<式,環境>のペアから<式の値>を返す関数となっているが、これを<式の値,新しい環境>のペアを返すようにする。

<a, ((a 10) (b 20))> =eval=> <10 , ((a 10) (b 20))>
<(set! b 200), ((a 10) (b 20))> =eval=> < _ , ((a 10) (b 200))>

新しい式をevalするときは一つ手前のevalが返した環境を使えば再束縛が実装できる。
ただしそれだけではクロージャの呼び出しに対応できないのだ。

(define f nil)
((lambda (n) (set! f (lambda (x) (set! n x))) 0)

クロージャは、その内部に環境を保持している。クロージャ

<args,env,body>=<(x), ((n 0)), (set! n x)>

に1を適用した場合、値の変化に対応して

<(x), ((n 1)), (set! n x)>

という新たなクロージャを作成し、古いクロージャを参照しているすべての変数を新しいクロージャへ再束縛した環境を作る必要があるのだがツリー構造になってる環境を全部走査して対象のクロージャを置換しながら新しい環境セットを作成し…… ううう。
このへん純粋関数型プログラミング言語を理解すると何らかのヒントが得られそうなのだが。Haskellやるかなー。

あー、今のままだと

((lambda (x) x) 10)

という関数を二回呼び出すと二回ともLambda<(x),(x),( (x 10) )>みたいな型が生成されるわけで、みわけがつかなくて多分困る。つまり同一の名前-値ペアをもつ環境を複数つくれるようにしたいわけで、int型のidでもくっつけとくかなあ。どうやって生成しよう。

こんなことで苦労するのもSchemeが純粋関数型じゃないのがすべて悪い