From: Helmut Eller on 25 Mar 2010 10:21 * Pascal Costanza [2010-03-25 11:50+0100] writes: > On 25/03/2010 07:51, Kazimir Majorinc wrote: >> Do CL-ers agree with Eli? > > What Eli says is correct, but only relevant when you use local macro > definitions. A canonical example is this: > > (let ((x 1)) > (macrolet ((foo () 'x)) > (let ((x 2)) > (foo)))) > > You have two variable bindings for x, and the expansion of foo will > refer to the inner one, so this form will yield 2. If you want to keep > the name x for both variable bindings, there is no way in Common Lisp > to reliably rewrite the macro foo such that it unambiguously refers to > the outer x, without adding some serious heavy machinery on top of > Common Lisp. You could simply write it as: (let ((x 1)) (flet ((foo () x)) (let ((x 2)) (foo)))) Or if you insist on using macros: (defmacro macrolet-with-alias ((macro-name (alias name) args &body expander) &body body) (let ((sym (gensym))) `(flet ((,sym () ,name)) (macrolet ((,macro-name ,args (symbol-macrolet ((,alias '(,sym))) . ,expander))) . ,body)))) (defun foo () (let ((x 1)) (macrolet-with-alias (foo (alias x) () `,alias) (let ((x 2)) (foo))))) Helmut
From: Pascal Costanza on 25 Mar 2010 11:13 On 25/03/2010 15:11, Kazimir Majorinc wrote: > On 25.3.2010 11:50, Pascal Costanza wrote: > >> Of course, you could decide to rename one of the two variable bindings. > > OK. But isn't it possible to change macrolet definition: > > (let((x 1)) > (macrolet-with-gensyms ((foo () 'x)) > '(x); 'variables to be replaced with gensyms > (let ((x 2)) > (foo)))) > > == expands to ==> > > (let((x 1)) > (let ((G3197 x)) > (macrolet((foo () 'G3197)) > (first (list (let ((x 2)) > (foo)))) > (setf x G3197)))) ;==>1 > > With real gensyms, these are manual equivalents. > Both outer and inner bindings are here, > which part of the problem is left? (let ((x 1)) (macrolet ((foo () 'x)) (let ((x 2)) (incf (foo))))) Pascal -- 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: Pascal Costanza on 25 Mar 2010 11:14 On 25/03/2010 15:21, Helmut Eller wrote: > * Pascal Costanza [2010-03-25 11:50+0100] writes: > >> On 25/03/2010 07:51, Kazimir Majorinc wrote: >>> Do CL-ers agree with Eli? >> >> What Eli says is correct, but only relevant when you use local macro >> definitions. A canonical example is this: >> >> (let ((x 1)) >> (macrolet ((foo () 'x)) >> (let ((x 2)) >> (foo)))) >> >> You have two variable bindings for x, and the expansion of foo will >> refer to the inner one, so this form will yield 2. If you want to keep >> the name x for both variable bindings, there is no way in Common Lisp >> to reliably rewrite the macro foo such that it unambiguously refers to >> the outer x, without adding some serious heavy machinery on top of >> Common Lisp. > > You could simply write it as: > > (let ((x 1)) > (flet ((foo () x)) > (let ((x 2)) > (foo)))) (let ((x 1)) (flet ((foo () x)) (let ((x 2)) (incf (foo))))) => doesn't work Pascal -- 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: Helmut Eller on 25 Mar 2010 11:35 * Pascal Costanza [2010-03-25 16:14+0100] writes: > On 25/03/2010 15:21, Helmut Eller wrote: >> * Pascal Costanza [2010-03-25 11:50+0100] writes: >> >>> On 25/03/2010 07:51, Kazimir Majorinc wrote: >>>> Do CL-ers agree with Eli? >>> >>> What Eli says is correct, but only relevant when you use local macro >>> definitions. A canonical example is this: >>> >>> (let ((x 1)) >>> (macrolet ((foo () 'x)) >>> (let ((x 2)) >>> (foo)))) >>> >>> You have two variable bindings for x, and the expansion of foo will >>> refer to the inner one, so this form will yield 2. If you want to keep >>> the name x for both variable bindings, there is no way in Common Lisp >>> to reliably rewrite the macro foo such that it unambiguously refers to >>> the outer x, without adding some serious heavy machinery on top of >>> Common Lisp. >> >> You could simply write it as: >> >> (let ((x 1)) >> (flet ((foo () x)) >> (let ((x 2)) >> (foo)))) > > (let ((x 1)) > (flet ((foo () x)) > (let ((x 2)) > (incf (foo))))) => doesn't work (defun foo () (let ((x 1)) (flet ((foo () x) ((setf foo) (value) (setf x value))) (let ((x 3)) (incf (foo)))))) Does work Helmut
From: Pascal Costanza on 25 Mar 2010 11:55
On 25/03/2010 16:35, Helmut Eller wrote: > * Pascal Costanza [2010-03-25 16:14+0100] writes: > >> On 25/03/2010 15:21, Helmut Eller wrote: >>> * Pascal Costanza [2010-03-25 11:50+0100] writes: >>> >>>> On 25/03/2010 07:51, Kazimir Majorinc wrote: >>>>> Do CL-ers agree with Eli? >>>> >>>> What Eli says is correct, but only relevant when you use local macro >>>> definitions. A canonical example is this: >>>> >>>> (let ((x 1)) >>>> (macrolet ((foo () 'x)) >>>> (let ((x 2)) >>>> (foo)))) >>>> >>>> You have two variable bindings for x, and the expansion of foo will >>>> refer to the inner one, so this form will yield 2. If you want to keep >>>> the name x for both variable bindings, there is no way in Common Lisp >>>> to reliably rewrite the macro foo such that it unambiguously refers to >>>> the outer x, without adding some serious heavy machinery on top of >>>> Common Lisp. >>> >>> You could simply write it as: >>> >>> (let ((x 1)) >>> (flet ((foo () x)) >>> (let ((x 2)) >>> (foo)))) >> >> (let ((x 1)) >> (flet ((foo () x)) >> (let ((x 2)) >> (incf (foo))))) => doesn't work > > (defun foo () > (let ((x 1)) > (flet ((foo () x) > ((setf foo) (value) (setf x value))) > (let ((x 3)) > (incf (foo)))))) Yes, and you're adding more and more definitions. If on top of that, you actually want a _macro_, you still haven't solved the problem (without adding more heavy machinery). Yes, you can always find workarounds for concrete examples (after all, you're in control of the complete expression), but there is no general solution that works the same for all cases, unless you introduce one of the known ways to make macro definition hygienic. (I'm not trying to say that Common Lisp has a serious problem here. To the contrary, I think the trade off made in Common Lisp's macro system is the right one - adding more features to guarantee macro hygiene makes a macro system more complicated than necessary, for no real benefit, and the known workarounds are, IMO, good enough. But that doesn't change the fact that Common Lisp's macro system does not provide straightforward means to write hygienic macros, and the only thing I'm doing here is to acknowledge that.) Pascal -- My website: http://p-cos.net Common Lisp Document Repository: http://cdr.eurolisp.org Closer to MOP & ContextL: http://common-lisp.net/project/closer/ |