読者です 読者をやめる 読者になる 読者になる

explicit renaming でスコープを曲げる

[追記]
丁寧に解説してくれました。
explicit renaming占い - .mjtの日記復帰計画
[/追記]

Scheme 処理系 Gauche に explicit-renaming というマクロ機構が入った。 とりあえず機能を確認するのにちょうどよい例がないか考えてみたところ、以前に syntax-case を使って書いた let/scope というマクロを思い出した。

以下が explicit-renaming を使って書き直したものだ。

(cond-expand
 (gauche (import (scheme base) (scheme write) (gauche base)))
 (chibi  (import (scheme base) (scheme write) (chibi)))
 (sagittarius (import (scheme base) (scheme write)))
 (else (begin)))

(define id?
  (cond-expand
   ((or sagittarius gauche)
    (lambda(x)(or (symbol? x) (identifier? x))))
   (else symbol?)))

(define (traverse proc obj)
  (let loop ((obj obj))
    (cond ((id? obj)     (proc obj))
          ((pair? obj)   (cons (loop (car obj)) (loop (cdr obj))))
          ((vector? obj) (vector-map loop obj))
          (else obj))))

(define-syntax let/scope
  (er-macro-transformer
   (lambda(form rename _)
     (let ((scope (cadr form))
           (body (cddr form)))
       `(let-syntax ((,scope
                      (,(rename 'er-macro-transformer)
                       (,(rename 'lambda) (f r _)
                        (,(rename 'let) ((form2 (,(rename 'cdr) f)))
                         (,(rename 'cons)
                          ',(rename 'begin)
                          (,(rename 'traverse) r form2)))))))
          ,@body)))))

(let ((x 1))
  (let/scope scope-1
    (let ((x 2))
      (let/scope scope-2
        (let ((x 3))
          (let/scope scope-1
            (let ((x 4))
              (display (scope-2 (scope-1 x)))
              (display (scope-2 x))
              (display (scope-1 x))
              (display x))))))))

ところが explicit-renaming を提供している他の処理系で試すと Gauche と異なる出力を得た。

Gauche

1234

Sagittarius

2234

MIT-GNU Scheme

2234

Chibi-scheme

2234

Gauche の他はいずれも 2234 が出力された。 私自身は Gauche の挙動を期待していたので驚いた。

スコープをネストしている箇所で差が生じているので、二回のリネームをすることについて考え方の差があるのだと思うのだけど、 explicit-renaming について充分に理解できていないので考察しきれていない。

Document ID: d471f00225844659c46f6f87c1acb796