When writing macros, one often uses something like with-gensyms for
lots of good reasons. I mean something like what Paul Graham uses in
"On Lisp"
(defmacro with-gensyms (symbols &body body)
"Binds a whole list of variables to gensyms."
`(let ,(mapcar #'(lambda (symbol) `(,symbol (gensym)))
symbols)
,@body))
This works great and solves all the problems it is supposed to. But
it leads to macro expansions that look like what follows (from the
with-redraw example also in "On Lisp")
(let ((#:g1000 objs))
(multiple-value-bind (#:g1001 #:g1002 #:g1003 #:g1004) (bounds
#:g1000)
(dolist (o #:g1000) (incf (obj-x o) dx) (incf (obj-y o) dy))
(multiple-value-bind (xa ya xb yb) (bounds #:g1000)
(redraw (min #:g1001 xa) (min #:g1002 ya)
(min #:g1003 xb) (min #:g1004 yb)))))
While this is manageable, the gensym names are far from obvious and
can make debugging more difficult. So why not do something like with-
unique-syms instead?
(defmacro with-unique-syms (symbols &body body)
"Binds a whole list of variables to fresh, uninterned symbols"
`(let ,(mapcar #'(lambda (symbol)
`(,symbol (make-symbol ,(string symbol))))
symbols)
,@body))
And then get a macro-expansion that looks like this:
(let ((#:gob objs))
(multiple-value-bind (#:x0 #:y0 #:x1 #:y1) (bounds #:gob)
(dolist (o #:gob) (incf (obj-x o) dx) (incf (obj-y o) dy))
(multiple-value-bind (xa ya xb yb) (bounds #:gob)
(redraw (min #:x0 xa) (min #:y0 ya)
(min #:x1 xb) (min #:y1 yb)))))
The hyperspec even says (in 10.2.7 gensym):
"(The only difference between gensym and make-symbol is in how the new-
symbol's name is determined.)"
So I am pretty sure this would work, but since I've not seen it
suggested before, I wonder if there is a good reason to prefer the
(gensym) approach.
·······@ravenpack.com wrote:
> The hyperspec even says (in 10.2.7 gensym):
> "(The only difference between gensym and make-symbol is in how the new-
> symbol's name is determined.)"
>
> So I am pretty sure this would work, but since I've not seen it
> suggested before, I wonder if there is a good reason to prefer the
> (gensym) approach.
copy-symbol is even more straightforward.
Pascal
--
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Peder O. Klingenberg
Subject: Re: Why not with-unique-syms (rather than with-gensyms)?
Date:
Message-ID: <kstzlchgmv.fsf@beto.netfonds.no>
·······@ravenpack.com writes:
> (defmacro with-unique-syms (symbols &body body)
> "Binds a whole list of variables to fresh, uninterned symbols"
> `(let ,(mapcar #'(lambda (symbol)
> `(,symbol (make-symbol ,(string symbol))))
> symbols)
> ,@body))
If you use the same variable name in multiple nestings of this, it
will be hard to tell one #:symbol from another while debugging. Even
harder than with the gensym solution you presented first.
Fortunately, there is a better way. Use the optional argument to
gensym:
(defmacro with-gensyms (symbols &body body)
"Binds a whole list of variables to gensyms."
`(let ,(mapcar #'(lambda (symbol) `(,symbol (gensym ,(string symbol))))
symbols)
,@body))
CL-USER> (with-gensyms (foo bar baz) (list foo bar baz))
(#:FOO19904 #:BAR19905 #:BAZ19906)
...Peder...
--
This must be Thursday. I never could get the hang of Thursdays.
On Jan 17, 11:48 am, ·····@news.klingenberg.no (Peder O. Klingenberg)
wrote:
> If you use the same variable name in multiple nestings of this, it
> will be hard to tell one #:symbol from another while debugging. Even
> harder than with the gensym solution you presented first.
>
> Fortunately, there is a better way. Use the optional argument to
> gensym:
>
> (defmacro with-gensyms (symbols &body body)
> "Binds a whole list of variables to gensyms."
> `(let ,(mapcar #'(lambda (symbol) `(,symbol (gensym ,(string symbol))))
> symbols)
> ,@body))
Yes, nesting is a very legitimate concern for readability/debug-
ability. I knew there was something obvious I wasn't considering.
Thanks.
-Jason
·······@ravenpack.com writes:
> When writing macros, one often uses something like with-gensyms for
> lots of good reasons. I mean something like what Paul Graham uses in
> "On Lisp"
>
> (defmacro with-gensyms (symbols &body body)
> "Binds a whole list of variables to gensyms."
> `(let ,(mapcar #'(lambda (symbol) `(,symbol (gensym)))
> symbols)
> ,@body))
>
> This works great and solves all the problems it is supposed to. But
> it leads to macro expansions that look like what follows (from the
> with-redraw example also in "On Lisp")
>
> (let ((#:g1000 objs))
> (multiple-value-bind (#:g1001 #:g1002 #:g1003 #:g1004) (bounds
> #:g1000)
> (dolist (o #:g1000) (incf (obj-x o) dx) (incf (obj-y o) dy))
> (multiple-value-bind (xa ya xb yb) (bounds #:g1000)
> (redraw (min #:g1001 xa) (min #:g1002 ya)
> (min #:g1003 xb) (min #:g1004 yb)))))
>
> While this is manageable, the gensym names are far from obvious and
> can make debugging more difficult. So why not do something like with-
> unique-syms instead?
>
> (defmacro with-unique-syms (symbols &body body)
> "Binds a whole list of variables to fresh, uninterned symbols"
> `(let ,(mapcar #'(lambda (symbol)
> `(,symbol (make-symbol ,(string symbol))))
> symbols)
> ,@body))
>
> And then get a macro-expansion that looks like this:
>
> (let ((#:gob objs))
> (multiple-value-bind (#:x0 #:y0 #:x1 #:y1) (bounds #:gob)
> (dolist (o #:gob) (incf (obj-x o) dx) (incf (obj-y o) dy))
> (multiple-value-bind (xa ya xb yb) (bounds #:gob)
> (redraw (min #:x0 xa) (min #:y0 ya)
> (min #:x1 xb) (min #:y1 yb)))))
>
> The hyperspec even says (in 10.2.7 gensym):
> "(The only difference between gensym and make-symbol is in how the new-
> symbol's name is determined.)"
>
> So I am pretty sure this would work, but since I've not seen it
> suggested before, I wonder if there is a good reason to prefer the
> (gensym) approach.
Hi!
http://darcs.informatimago.com/darcs/public/lisp/common-lisp/utility.lisp has:
#-:with-debug-gensym
(DEFMACRO WITH-GENSYMS (SYMS &BODY BODY)
"
DO: Replaces given symbols with gensyms. Useful for creating macros.
NOTE: This version by Paul Graham in On Lisp."
`(LET ,(MAPCAR (LAMBDA (S) `(,S (GENSYM ,(string s)))) SYMS) ,@BODY))
;; ^^^^^^^^^^^
There's also another version:
#+:with-debug-gensym
(defpackage "COM.INFORMATIMAGO.GENSYMS" (:USE))
#+:with-debug-gensym
(DEFMACRO WITH-GENSYMS (SYMS &BODY BODY)
"
DO: Replaces given symbols with gensyms. Useful for creating macros.
`(LET ,(MAPCAR
(LAMBDA (S) `(,S (INTERN (STRING (GENSYM ,(string s)))
"COM.INFORMATIMAGO.GENSYMS"))) SYMS) ,@BODY))
which let you use these symbol more easily in a debugger.
AFAIK:
(let ((counter 0))
(defun gensym (&optional (name "G"))
(make-symbol (format nil name (incf counter)))))
so there should be no difference.
--
__Pascal Bourguignon__
·······@ravenpack.com wrote:
> When writing macros, one often uses something like with-gensyms for
> lots of good reasons. I mean something like what Paul Graham uses in
> ........
> This works great and solves all the problems it is supposed to. But
> it leads to macro expansions that look like what follows (from the
> with-redraw example also in "On Lisp")
> .......(gensym) approach.
There were no responses to
http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/76ac84f0495b4e3a
but it may be useful to you
-Antony