読者です 読者をやめる 読者になる 読者になる

短いマクロ定義でシンボル補足を避けるための簡単な方法

common lisp

シンボル補足を避けるためにたまに使う方法。
uninternされたシンボルとリードマクロのラベル付け/参照機能を併用。

;; uninternされたシンボル
;; 印字名が同じでも実体は異なるので、衝突は起きない
(eq '#:var '#:var)
--> NIL

;; #n=および#n#構文を使えば、複数箇所から参照可能
(eq '#1=#:var '#1#)
--> T
;;;;
;; 「On Lisp」第九章から引用(シンボル補足の例)
;; startからstopまでの値をvarに束縛してbodyの実行を繰り返す
(defmacro for ((var start stop) &body body)
  `(do ((,var ,start (1+ ,var))
        (limit ,stop))
       ((> ,var limit))
      ,@body))

(for (x 1 5)
  (print x))
1 
2 
3 
4 
5 
--> NIL

;; マクロの使用者がlimitシンボルにアクセスが可能
(for (x 1 5)
  (setf limit 0)
  (print x))
1
--> NIL


;;;;
;; 修正版
(defmacro for ((var start stop) &body body)
  `(do ((,var ,start (1+ ,var))
        (#1=#:limit ,stop))  ; limitをuninternされたシンボルに変更
       ((> ,var #1#))  
      ,@body))

(for (x 1 5)
  (print x))
1 
2 
3 
4 
5 
--> NIL

;; マクロの使用者はマクロ内で使われている#:limitシンボルへのアクセスは不可能
(for (x 1 5)
  (setf #:limit 0)
  (print x))

;     (SETF #:LIMIT 0)
; ==>
;   (SETQ #:LIMIT 0)
; 
; caught WARNING:
;   undefined variable: #:LIMIT
; 
; compilation unit finished
;   Undefined variable:
;     #:LIMIT
;   caught 1 WARNING condition

1 
2 
3 
4 
5 
--> NIL

マクロ定義が大きくなると可読性が悪くなるが、数行程度のマクロであればそれほど問題ない。