syntax-caseの実装が甘いのがここにきて痛い感じだ。
たとえばこんなコード。
(define-syntax print (syntax-rules () ((_ o) (begin (display o) (newline))))) (print (let ((x 'outer)) (let-syntax ((m (syntax-rules () ((m) x)))) (let ((x 'inner)) (m)))))xという変数は合計で3回出現しているが、printマクロを噛ませることですべて同じ識別子へと見事な変貌を遂げている。これが問題なのだ・・・
syntax-rules内のxが3回目のxと同じため出力としてはinnerが帰ってくる。でも、printマクロを噛ませないとouterが帰る。これは最初のxが束縛された際の環境をマクロ展開器が知っているため、単なるシンボルであれば環境を閉じ込めて識別子にすることができるからだ。
あぁ、そうか。ならラップする際に何とかできればいいのか。いや、待てよ。同じ識別子なんだから、環境内でも同じか。結局簡単な方法はunrenameすることになるのか・・・
さて、もう一ひねりしてみるか・・・orz
捻ってみたのだがいまいちいい案がでなかった。とりあえず、syntax-caseを通ったら全部が識別子になるというのをやめたらR6RSのテストは通るようになった。(identifier?でfenderを書くのが不可能になるが)
結局うまい方法が見つからない。他の実装をあまり知らないのでなんとも言えないが、syntax-caseって明確にマクロ展開時とコンパイル時を分けないと実装できないんじゃないかと思えてきた。知っている実装で、Ypsilon、psyntax、とSRFIのどれかのがあるのだが、どれもマクロ展開->コンパイルという順になっている。
となると、最初にdefine-syntaxもしくは、let(rec)-syntaxを全部拾ってマクロを展開してからコンパイルするしかないのだろうか?いやいや待て待て、現状問題になっているのは、上記で書いた識別子が一意過ぎる問題だ。となると、やっぱりコンパイラがローカル変数を束縛する際にunrenameしてやればいいのか。
やっぱり、rename回数の管理かなぁ・・・
No comments:
Post a Comment