| Register | FAQ | Calendar | Search | Today's Posts | Mark Forums Read |
|
#1
| |||
| |||
| 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. |
|
#2
| |||
| |||
| 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/ |
|
#3
| |||
| |||
| 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. |
|
#4
| |||
| |||
| 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 |
|
#5
| |||
| |||
| 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 |
|
#6
| |||
| |||
| 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 |
|
#7
| |||
| |||
| 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__ |
|
#8
| |||
| |||
| 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 |
![]() |
| Thread Tools | |
| Display Modes | |
In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.