R6RSライブラリ中のexportしていないシンボルへのアクセス
↑のコードは、以下のように、expand時に発生する*objects*への副作用に依存している。
(library (sublib) (export %bury %disinter) (import (rnrs)) (define *objects* (make-eq-hashtable)) (define (%bury key obj) (hashtable-set! *objects* key obj)) (define (%disinter key) (hashtable-ref *objects* key #f))) (library (lib) (export define-thing thing) (import (rnrs) (for (sublib) expand)) (define-syntax define-thing (lambda (stx) (syntax-case stx () ((_ ?key ?id) (begin (%bury (syntax->datum #'?key) #'?id) #'(define dummy #f)))))) (define-syntax thing (lambda (stx) (syntax-case stx () ((_ ?key) (with-syntax ((obj (%disinter (syntax->datum #'?key)))) #'(obj)))))))
これは、副作用の発生をrun時点に移動すれば(= defineを使って遅延させる)期待通りに動作する。
(library (lib) (export define-thing thing) (import (rnrs) (sublib)) (define-syntax define-thing (syntax-rules () ((_ ?key ?id) (define dummy (%bury '?key ?id))))) (define-syntax thing (syntax-rules () ((_ ?key) ((%disinter '?key))))))
(もちろん、マクロを使う本来の目的は、プログラムのexpand時にこれらの処理を行うことにあるので、このような変更はあまり意味が無い。)
R6RSは、macro transformerが実際の実行と同一のランタイムで実行されることを特に要求していない(?)ので、文脈情報を持つオブジェクトがhash-tableに格納できるとは限らない。run時点であれば、これはシンボルや値になっているので確実に動作する。
nmoshでは、hash-tableに文脈情報を持つシンボル(これは現在の所vectorで表現されている)を格納することが出来るので一見動きそうに思えるが、(psyntaxと違って)シンボルの文脈情報はグローバルに有効なわけではないので結局動作しない。(psyntax moshでも、キャッシュを使うと文脈情報のスコープが失われるので問題が起こると考えられる)
このsyntax→datumをつかってlibraryのexportしていない値が取り出せてしまう問題はR6RSのcorner-caseでshibuya.lisp TT2でのYpsilonの発表にも含まれていた。
この発表の例では、syntax→datumとdatum→syntaxを文脈情報の有効範囲内で行っているため、nmoshでは(Larcenyと同様に)値が取り出せてしまう。
okuoku@okupcb ~/check/virtual-proof $ mosh nmosh> (import (rnrs load) (nmosh expander)) nmosh> (load "access.scm") #<unspecified> nmosh> (expand-sequence '((import (rnrs) (access)) (foo login-name))) ((begin (ex:import-libraries-for-run '(((access) 0) ((rnrs) 0)) '(&build~1262021243~27 &build~1261944474~3417) 0) &login-name~1262021243~9)) nmosh>
最後に出力された&login-name~1262021243~9がバックエンドにおけるライブラリ(access)中のlogin-nameであるため、これを指定すれば表示することができる。この長い名前は、ライブラリをexpandしたときにシステムによって命名される。
nmosh> (import (mosh) (access)) nmosh> (symbol-value '&login-name~1262021243~9) shibuya
本来、デコレートされた名前を取得する方法、つまり、login-nameと&login-name~1262021243~9を対応づける正当な方法は、ライブラリのimportとexportしか無い。syntax→datumのときに追加のチェックを行うことで、このような問題を検出することができるだろう。