Scheme の規格であるところの R6RS では library から import した変数に set! することは出来ない。 それを出来る (かのように見せる) ようにする方法を以前に記事にした。
http://saito.hatenablog.jp/entry/20100822/1282449327
パラメタに入れたのを識別子マクロで隠蔽しているが、パラメタでなく単なるコンスセルでもよかったかもしれない。
さて、今回は逆の話をしよう。 import した変数に set! できないという制約がある一方で、同じライブラリ (又はプログラム) の中にある変数に対して set! を禁止する方法は用意されていない。 無ければ作ればいいじゃない、というわけで出来上がったのがこちら。
#!r6rs (library (constant) (export define-constant) (import (rnrs)) (define-syntax define-constant (syntax-rules () ((_ var form) (begin (define t form) (define-syntax var (make-variable-transformer (lambda(stx) (syntax-case stx () ((set! v _) (syntax-violation 'set! "attempt to assign constant" stx #'v)) (_ #'t))))))))) )
define-constant で定義した変数には set! できなくなり、 set! した場合はエラーとして検出される。
#!r6rs (import (rnrs) (constant)) (define-constant a 1) (display a) (set! a 2) ;; ←ここがエラーとして検出される。 コメントアウトすれば動く。
うっかり書換えてしまうのを防止できるが、そもそも定数の類は別のライブラリに分けることが多いのでそんなに使い出がないかもしれないなぁ。
Document ID: 17cf49d96aece555810683f0296da8ab