Let's start Scheme

2011-07-27

Syntax-caseめぇ・・・

本当に実装者泣かせだ(僕だけ?)
これが動かない
スコープを曲げる
以下引用
(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)
これがunbound variable xで&assertionを投げる。
(キャッシュを使ってるともっとひどくて、マクロ展開時に死ぬ。何故だ?)

なぜ動かないか、「足りないからだ、憎しみ(識別子の中の環境のこと)が・・・」(by うちはいたち)

問題になるのはdatum->syntaxに渡されるテンプレート用の構文オブジェクト = 識別子。
Sagittariusでは他のR6RS処理系と違って、「k」は使い回しされる。かつ、「k」はここでは「let/scope」そのものになり、大域に出現した識別子となる。(多分これがもとでbound-identifier=?が上手く動かない)
問題はここからで、グローバルな識別子はそれ自身に環境を持っていない。持つ必要がないから。
そうすると、datum->syntaxが渡されたテンプレートに梱包されている環境(グローバルなので空)を元に新たな識別子を作り、結果、上記の(d1 x) (d2 x)はグローバルな呼び出しとなる。
突き止めるまでに1時間くらいかかったが、原理は分かった。問題は、ない情報をどこから引っ張り出してくるかということになる。
無知な頃に(今でもだが)作った(パクった?)部分が多々あるので、コードの読みにくさもあいまってマクロ周りは出来がひどい。リファクタリングも兼ねて一度見直すべきだろうか?

No comments:

Post a Comment