defvar で再定義

lisp を書いてると defvar の初期値を変更して読み込んでも値は変わらなくて、「めんどくせーな」とか言いながら repl から setf し直すハメになることがちょくちょくあるので、defvar で再定義したときに最初(前回)の初期値から変更されてなければ値を更新するようにした。
どれだか忘れたけど Common Lisp だか Emacs だかで同じファイルから再定義したときのみ更新するという話を聞いたことがあるような気がするけど、めんどいのと defvar を別ファイルに引っ越したいことがたまにあるのでそこは無視した。

間違って2度 defvar してたりすると不可思議なことになると思うので、lisp 書く人以外は使わない方がいいと思う。

(defmacro defvar (name &optional (init nil sv) doc)
  (let ((UNDEF '#:undef))
    `(labels ((%get (symbol indicator default)
                (do ((plist (symbol-plist symbol) (cddr plist)))
                    ((endp plist)
                     default)
                  (when (eql (car plist) indicator)
                    (return (cadr plist))))))
       ,(when sv
          `(let ((#1=#:value ,init))
             (when (or (not (boundp ',name))
                       (equal ,name (%get ',name 'lisp::variable-default-value ',UNDEF)))
               (set ',name #1#))
             (si:*putprop ',name #1# 'lisp::variable-default-value)))
       ,(when doc
          `(si:*putprop ',name ,doc 'lisp::variable-documentation))
       (si:*make-special ',name)
       ',name)))