Common Lisp でローカルな定数を導入する構文を作ろうとする記事を読んだ。
私は以前に似たようなことをやっていたことを思い出した。
以前に作ったマクロ define-constant
は最終的に define
に展開されるので、そのまま internal define に使っても機能はするのだが、あらためて let
系の形式でローカル定数を定義するマクロを書いてみることにした。
#!r6rs (import (rnrs)) (define-syntax let-constant (lambda(stx) (syntax-case stx () ((k ((var form) ...) body body* ...) (with-syntax (((t ...) (generate-temporaries #'(var ...)))) #'(let ((t form) ...) (let-syntax ((var (make-variable-transformer (lambda(stx2) (syntax-case stx2 () ((set! v _) (syntax-violation 'set! "attempt to assign constant" stx2 #'v)) (_ #'t))))) ...) body body* ...))))))) (let-constant ((x 1)) ;;(set! x 2) ;; ← もし set! を試みたらエラーになる (display x)))
例として書いた定数 x
は識別子マクロで、展開後には隠れた変数に置き換えられる。 識別子マクロは set!
で代入されるときの展開形を特別に定義することも出来て、ここではそういう形になっているときは syntax-violation
を使って構文エラーになるように定義した。
Document ID: d5f61355b4e55961f2af8517178d2c53