Why not with-unique-syms (rather than with-gensyms)?

This is a discussion on Why not with-unique-syms (rather than with-gensyms)? within the lisp forums in Programming Languages category; 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 ...

Go Back   Application Development Forum > Programming Languages > lisp

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #1  
Old 01-17-2008, 05:08 AM
jcornez@ravenpack.com
Guest
 
Default Why not with-unique-syms (rather than with-gensyms)?

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.
Reply With Quote
  #2  
Old 01-17-2008, 05:37 AM
Pascal Costanza
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

jcornez@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/
Reply With Quote
  #3  
Old 01-17-2008, 05:48 AM
Peder O. Klingenberg
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

jcornez@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.
Reply With Quote
  #4  
Old 01-17-2008, 05:57 AM
jcornez@ravenpack.com
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

On Jan 17, 11:48 am, pe...@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
Reply With Quote
  #5  
Old 01-17-2008, 05:58 AM
Marco Antoniotti
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

On Jan 17, 11:37*am, Pascal Costanza <p...@p-cos.net> wrote:
> jcor...@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.


That works well to change the (make-symbol (string ,symbol)) part.
However I would advocate the following

(defmacro with-unique-syms (symbols &body body)
"Binds a whole list of variables to fresh, uninterned symbols"
`(let ,(mapcar #'(lambda (symbol)
`((gensym ,(symbol-name symbol)) ,symbol) ; OP
has a mistake here.
symbols)
,@body))


That way you get new symbols which are uninterned (which on some CL
has its own advantages) and with more informative names.
I bet some of the versions of WITH-UNIQUE-NAMES floating around work
like this. I have not checked.

Cheers
--
Marco

Reply With Quote
  #6  
Old 01-17-2008, 06:01 AM
Marco Antoniotti
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

On Jan 17, 11:58*am, Marco Antoniotti <marc...@gmail.com> wrote:
> On Jan 17, 11:37*am, Pascal Costanza <p...@p-cos.net> wrote:
>
> > jcor...@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.

>
> That works well to change the (make-symbol (string ,symbol)) part.
> However I would advocate the following
>
> (defmacro with-unique-syms (symbols &body body)
> * "Binds a whole list of variables to fresh, uninterned symbols"
> * `(let ,(mapcar #'(lambda (symbol)
> * * * * * * * * * * *`((gensym ,(symbol-name symbol)) ,symbol) ; OP
> has a mistake here.


Sorry. My bad here.


> * * * * * * * * *symbols)
> * * *,@body))
>
> That way you get new symbols which are uninterned (which on some CL
> has its own advantages) and with more informative names.
> I bet some of the versions of WITH-UNIQUE-NAMES floating around work
> like this. *I have not checked.
>
> Cheers
> --
> Marco


Reply With Quote
  #7  
Old 01-17-2008, 06:15 AM
Pascal J. Bourguignon
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

jcornez@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...p/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__
Reply With Quote
  #8  
Old 01-17-2008, 09:08 PM
lisp linux
Guest
 
Default Re: Why not with-unique-syms (rather than with-gensyms)?

jcornez@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....ac84f0495b4e3a
but it may be useful to you
-Antony

Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 04:09 PM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2009, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.