Subject: Re: Lisp mistakes in Python
From: rpw3@rpw3.org (Rob Warnock)
Date: Sat, 09 Sep 2006 07:05:56 -0500
Newsgroups: comp.lang.lisp
Message-ID: <_o-dnWJzfMK5M5_YnZ2dnUVZ_s2dnZ2d@speakeasy.net>
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