Pascal Costanza <pc@p-cos.net> wrote:
+---------------
| (defmacro define-constant (name value)
| (let ((internal-name (copy-symbol name)))
| `(progn
| (defconstant ,internal-name ,value)
| (define-symbol-macro ,name ,internal-name))))
+---------------
One of the things I like about this group is that you always learn
something new, in this case a non-trivial use for COPY-SYMBOL
[instead of GENSYM]. I've been using the following rather clunky
macro for some time -- mainly in the REPL -- to define "global
lexical variables":
(defmacro deflex (var val &optional (doc nil docp))
(let* ((s0 (symbol-name '#:*storage-for-deflex-var-))
(s1 (symbol-name var))
(s2 (symbol-name '#:*))
(s3 (symbol-package var))
(shadow-var (intern (concatenate 'string s0 s1 s2) s3)))
`(progn
(defparameter ,shadow-var ,val ,doc)
,@(when docp (list `(setf (documentation ',var 'variable) ,doc)))
(define-symbol-macro ,var ,shadow-var))))
But that whole *STORAGE-FOR-DEFLEX-VAR-${whatever}* hack was only
there for debugging, to make MACROEXPAND, error messages, and
the like print something useful instead of some random gensym.
I think the following -- modelled on your DEFINE-CONSTANT -- does
the job just as well but is much cleaner:
(defmacro deflex (var val &optional (doc nil docp))
(let* ((shadow-var (copy-symbol var)))
`(progn
(defparameter ,shadow-var ,val ,doc)
,@(when docp (list `(setf (documentation ',var 'variable) ,doc)))
(define-symbol-macro ,var ,shadow-var))))
Used like so:
> (deflex foo 13 "A sample global lexical")
FOO
> (defun foo () foo)
FOO
> (let ((foo 57))
(list foo (foo)))
(57 13)
> (describe 'foo)
FOO is an internal symbol in the COMMON-LISP-USER package.
It is a symbol macro with expansion: #:FOO.
Macro documentation:
A sample global lexical
> (describe (macroexpand 'foo))
FOO is an uninterned symbol.
It is a special variable; its value is 13.
Special documentation:
A sample global lexical
>
-Rob
p.s. Originally I had only DEFLEX, defined as above using
DEFPARAMETER to (re)bind the shadow variable every time the
DEFLEX is executed [as when a file is reLOADed], like Scheme's
top-level DEFINE, but I found that I also occasionally needed
a version that provided DEFVAR behavior rather than DEFPARAMETER,
so I called it DEFLEXVAR. I'm now wondering if I got it backwards,
that instead it's DEFLEX that should have DEFVAR behavior, and
(say) DEFLEXICAL should have DEFPARAMETER behavior. Opinions?
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607