Scheme の話題がネタ切れ気味になってきたので、過去に書いたものを見返していたところ、 R6RS で explicit renaming を実装するというネタが目に止まった。
http://saito.hatenablog.jp/entry/20110914/1316020026
そういえば syntactic closure もいずれやってみようと思っていたのだった。
で、出来上がったのがこちら。
#!r6rs (library (syntactic-closure) (export sc-macro-transformer make-syntactic-closure) (import (rnrs)) (define (tree-walk proc ls) (let loop ((ls ls)) (cond ((null? ls) '()) ((pair? ls) (cons (loop (car ls)) (loop (cdr ls)))) (else (proc ls))))) (define-syntax sc-macro-transformer (lambda(stx2) (syntax-case stx2 () ((k proc) #'(lambda(stx) (syntax-case stx () ((env . arg) (tree-walk (lambda(x) (if (symbol? x) (datum->syntax #'k x) x)) (proc (syntax->datum #'(env . arg)) #'env))))))))) (define (make-syntactic-closure env names form) (tree-walk (lambda(x) (if (symbol? x) (if (memv x names) x (datum->syntax env x)) x)) form)) )
使用例はこんな感じ。
#!r6rs (import (rnrs) (for (syntactic-closure) expand)) (define-syntax swap! (sc-macro-transformer (lambda (form env) (let ((a (make-syntactic-closure env '() (cadr form))) (b (make-syntactic-closure env '() (caddr form)))) `(let ((value ,a)) (set! ,a ,b) (set! ,b value)))))) (define c 1) (define d 2) (swap! c d) (display c) (newline) (display d) (newline)
いくつかの処理系で試していたのだが、 Ypsilon でだけ以下のような例がエラーになってしまった。 let-syntax の定義部での文脈をうまく扱えないらしい。
#!r6rs (import (rnrs) (for (syntactic-closure) expand)) (let-syntax ((foo (sc-macro-transformer (lambda(expr env) (let ((var (cadr expr))) `(display ,(make-syntactic-closure env '() var))))))) (let ((x 2)) (foo x)))
Document ID: f4f2d89748919445e1bcb89d09350dd8