| email@example.com (Rob Warnock) wrote:
| > Richard J. Fateman <fate...@eecs.berkeley.edu> wrote:
| > +---------------
| > | The reason I had no *earmuffs* is that I was typing x and y in
| > | repeatedly for tests, and didn't want to type *x* and *y* so much.
| > +---------------
| > Use DEFLEX to get (well, simulate) top-level lexical variables:
| > http://rpw3.org/hacks/lisp/deflex.lisp
| Rob, this is really nitpicking, (and possibly wrong), but I am
| wondering if in your deflex gem one could do
| CL-USER> (defmacro deflex2 (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)) ; BUGFIX [see above]
| (backing-var (intern (concatenate 'string s0 s1 s2) s3)))
| (defparameter ,backing-var ,val ,(when docp `,doc))
| (define-symbol-macro ,var ,backing-var)
| ,(when docp
| `(setf (documentation ',var 'variable) ,doc)))))
| My only problem (i.e. lack of macro expertise) with this is that the
| when forms instead of returning nothing place a NIL in the macro
| expansion. But that does not seem to hurt things.
The idea of pushing the IF into the body of the PROGN is certainly
reasonable, and I've done it both ways at various times, but I left
the IF outside in the <http://rpw3.org/hacks/lisp/deflex.lisp> version
because I thought it would be a bit clearer to the newcomer.
However, since you brought it up... ;-} ;-}
First, my plain ,DOC gives identical results as your ,(WHEN DOCP `,DOC)
in the DEFPARAMETER's third arg. And neither solves the problem of the
third arg being always provided regardless of the value of DOC.
Fixing that requires using the same splicing hack used below for
the (SETF (DOCUMENTATION ...)) clause.
Anyway, to the main point: if I were to push the IF down in the PROGN,
I would do it the following way instead, which uses a bit more magic
macro syntax but doesn't require the out-of-order thinking that your PROG2
introduced (and also doesn't leave orphan NILs anywhere in the code):
(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))
(backing-var (intern (concatenate 'string s0 s1 s2) s3)))
(defparameter ,backing-var ,val ,@(when doc (list doc)))
(list `(setf (documentation ',var 'variable) ,doc)))
;; Must be last, so the value of the form is the symbol VAR.
(define-symbol-macro ,var ,backing-var))))
Yes, this version is *slightly* more compact than my original, but
also perhaps a bit harder to figure out.
Note that this splicing trick is quite useful for both optional and
keyword parameters. But you *must* use the LIST and not just QUOTE
the optional value, that is, write ,@(WHEN DOC (LIST DOC)) and not
just ,@(WHEN DOC '(DOC)), since the latter can result in constant
structure being modified, which is a big no-no. Whereas LIST will
allocate a fresh cons that can be cheerfully spliced.
Back to you...
 For maximum portability one should probably use the splicing hack
on the third arg of DEFPARAMETER, too, since the CLHS defines that arg
to be "a string", *not* "a string or NIL". Fortunately, this doesn't
seem to matter in all the CLs I have access to -- (DEFPARAMETER FOO val)
gives the same result as (DEFPARAMETER FOO val NIL). But I included that fix in the above
Rob Warnock <firstname.lastname@example.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607