Scheme のマクロを書いているときには副作用を意識しないといけないことがある。 下手に展開すると評価を2回してしまったり、直観に反する順序で評価してしまったりする。
そういったことを考慮して慎重に書くにこしたことは無いが、逆に副作用が無い式しか受取れないようにする方法は無いだろうかという考えが浮かんだ。 リテラルか変数しか受取らないなら副作用を考慮する必要は無くなるはずだ。
しかし、リテラルはともかく、変数であるかどうかを判定することは出来るのだろうか? 識別子かどうかなら identifier? で判定できるが…。
(define-syntax foo (lambda(x) (syntax-case x () ((_ a) (identifier? #`a) #`a))))
これだと展開すると変数になるようなマクロも使えない。
(define count 1) (foo (foo count)) ; => error!
逆に副作用があっても変数マクロが使えてしまう。
(define count 1) (define-syntax bar (lambda(x) (syntax-case x () (a #`(let ((t count)) (set! count (+ 1 count)) t))))) (foo bar) ; => 1 (foo bar) ; => 2
式のマクロ展開だけやる仕組みがあれば解決すると思うが、ポータブル (規格内) な方法は無さそう。
Document ID: 9c3329192355e1450c982e3635bc84ac