トップレベルのレキシカル変数 - lisp-cookbook-ja/common-lisp GitHub Wiki

Common Lispにはトップレベルのレキシカル変数はありませんが、シンボルマクロと格納用変数で動作を模倣することは可能です。

(defmacro deflex (var val &optional (doc nil docp))
  (let* ((backing-var (intern (format nil "*storage-for-deflex-var-~A*" var) 
                              (symbol-package var))))
    `(progn
      (defparameter ,backing-var ,val ,@(when docp `(,doc)))
      ,@(when docp
          `((setf (documentation ',var 'variable) ,doc)))
      (define-symbol-macro ,var ,backing-var))))

実行例

(deflex lexical-foo 42)


(defun foo ()
  (lambda () lexical-foo))


(let ((lexical-foo 0))
  (setq lexical-foo 44)
  (print lexical-foo)
  (funcall (foo)))
;->  
;->  0 
;=>  42
lexical-foo
;=>  42


(setq lexical-foo 100)
;=>  100


(let ((lexical-foo 0))
  (setq lexical-foo -1)
  (print lexical-foo)
  (funcall (foo)))
;->  
;->  -1 
;=>  100

この方法であれば、意図しないスペシャル宣言を防止できることもメリットと考えられます。

(declaim (special lexical-foo))
;!! Cannot proclaim a MACRO variable SPECIAL: LEXICAL-FOO

(let ((lexical-foo 0))
  (declare (special lexical-foo))
  (print lexical-foo)
  (funcall (foo)))
;!! Can't declare macro variable locally special: LEXICAL-FOO

参考