これが動かない
スコープを曲げる
以下引用
これがunbound variable xで&assertionを投げる。(define-syntax let/scope (lambda(x) (syntax-case x () ((k scope-name body ...) #'(let-syntax ((scope-name (lambda(x) (syntax-case x () ((_ b (... ...)) #`(begin #,@(datum->syntax #'k (syntax->datum #'(b (... ...)))))))))) body ...))))) (let ((x 1)) (let/scope d1 (let ((x 2)) (let/scope d2 (let ((x 3)) (list (d1 x) (d2 x) x)))))) ;; ⇒ (1 2 3)
(キャッシュを使ってるともっとひどくて、マクロ展開時に死ぬ。何故だ?)
なぜ動かないか、「足りないからだ、憎しみ(識別子の中の環境のこと)が・・・」(by うちはいたち)
問題になるのはdatum->syntaxに渡されるテンプレート用の構文オブジェクト = 識別子。
Sagittariusでは他のR6RS処理系と違って、「k」は使い回しされる。かつ、「k」はここでは「let/scope」そのものになり、大域に出現した識別子となる。(多分これがもとでbound-identifier=?が上手く動かない)
問題はここからで、グローバルな識別子はそれ自身に環境を持っていない。持つ必要がないから。
そうすると、datum->syntaxが渡されたテンプレートに梱包されている環境(グローバルなので空)を元に新たな識別子を作り、結果、上記の(d1 x) (d2 x)はグローバルな呼び出しとなる。
突き止めるまでに1時間くらいかかったが、原理は分かった。問題は、ない情報をどこから引っ張り出してくるかということになる。
無知な頃に(今でもだが)作った(パクった?)部分が多々あるので、コードの読みにくさもあいまってマクロ周りは出来がひどい。リファクタリングも兼ねて一度見直すべきだろうか?
No comments:
Post a Comment