Prev: Typed hygienic macros with "local" reasoning.
Next: wholesale POLO 3 T-shirt from china,paypal payment and free shipping
From: Joshua Taylor on 21 Jun 2010 16:08 Hi all, Is there any kind of standard terminology for describing these two approaches to macroexpansion: 1) Expand one layer at a time. (defmacro let** (bindings &body body) (if (endp bindings) `(progn ,@body) (destructuring-bind (binding &rest bindings) bindings (destructuring-bind (var form) (if (listp binding) binding (list binding 'nil)) `(let ((,var ,form)) (let** ,bindings ,@body)))))) Macroexpansion expands the outermost let**, but leaves more inside to be processed: (macroexpand-1 '(let** ((x 1) (y (+ 1 x)) (z (+ 1 x y))) (list x y z))) (LET ((X 1)) (LET** ((Y (+ 1 X)) (Z (+ 1 X Y))) (LIST X Y Z))) 2) Expand all layers at once. (defmacro let*** (bindings &body body) (labels ((expand-let*** (bindings body) (if (endp bindings) `(progn ,@body) (destructuring-bind (binding &rest bindings) bindings (destructuring-bind (var form) (if (listp binding) binding (list binding 'nil)) `(let ((,var ,form)) ,(expand-let*** bindings body))))))) (expand-let*** bindings body))) Macroexpansion expands all the bindings here, and anything in the body will be expanded later. (macroexpand-1 '(let*** ((x 1) (y (+ 1 x)) (z (+ 1 x y))) (list x y z))) (LET ((X 1)) (LET ((Y (+ 1 X))) (LET ((Z (+ 1 X Y))) (PROGN (LIST X Y Z))))) I think that the latter makes avoiding wrapping the body in progns a bit easier (e.g., a modification to this example that has expand-let*** return a list of forms), and I suppose that in some situations maybe file compilation could happen a bit quicker (since there would be fewer distinct calls to macroexpansion functions). I don't expect that these considerations are all that important, of course. What I find more interesting are cases where the second approach makes things that seem to be impossible with the first. The instance that I've recently come across is that of destructuring binding wherein equality of subpatterns is to be enforced. E.g., causing some something like (destructuring-bind* (op x x) '(+ 1 2) ...) to fail (since x wouldn't be allowed to take on both non-eql values 1 and 2) is much easier with the second approach to macroexpansion, and much more difficult (if not impossible) with the first. In describing this to a colleague, I found myself wondering if there was a standard terminology for these two approaches. Does anyone know of one? //JT
From: Tamas K Papp on 22 Jun 2010 01:03 On Mon, 21 Jun 2010 16:08:01 -0400, Joshua Taylor wrote: > Hi all, > > Is there any kind of standard terminology for describing these two > approaches to macroexpansion: > > > 1) Expand one layer at a time. > > (defmacro let** (bindings &body body) > (if (endp bindings) > `(progn ,@body) > (destructuring-bind (binding &rest bindings) bindings > (destructuring-bind (var form) > (if (listp binding) binding (list binding 'nil)) > `(let ((,var ,form)) > (let** ,bindings > ,@body)))))) > > Macroexpansion expands the outermost let**, but leaves more inside to be > processed: > > (macroexpand-1 '(let** ((x 1) > (y (+ 1 x)) > (z (+ 1 x y))) > (list x y z))) > (LET ((X 1)) (LET** ((Y (+ 1 X)) (Z (+ 1 X Y))) (LIST X Y Z))) > > > 2) Expand all layers at once. > > (defmacro let*** (bindings &body body) > (labels ((expand-let*** (bindings body) > (if (endp bindings) > `(progn ,@body) > (destructuring-bind (binding &rest bindings) bindings > (destructuring-bind (var form) > (if (listp binding) binding (list binding 'nil)) > `(let ((,var ,form)) > ,(expand-let*** bindings body))))))) > (expand-let*** bindings body))) > > Macroexpansion expands all the bindings here, and anything in the body > will be expanded later. > > (macroexpand-1 '(let*** ((x 1) > (y (+ 1 x)) > (z (+ 1 x y))) > (list x y z))) > (LET ((X 1)) (LET ((Y (+ 1 X))) (LET ((Z (+ 1 X Y))) (PROGN (LIST X Y > Z))))) > > > I think that the latter makes avoiding wrapping the body in progns a bit > easier (e.g., a modification to this example that has expand-let*** > return a list of forms), and I suppose that in some situations maybe > file compilation could happen a bit quicker (since there would be fewer > distinct calls to macroexpansion functions). I don't expect that these > considerations are all that important, of course. > > What I find more interesting are cases where the second approach makes > things that seem to be impossible with the first. The instance that > I've recently come across is that of destructuring binding wherein > equality of subpatterns is to be enforced. E.g., causing some something > like > > (destructuring-bind* (op x x) '(+ 1 2) ...) > > to fail (since x wouldn't be allowed to take on both non-eql values 1 > and 2) is much easier with the second approach to macroexpansion, and > much more difficult (if not impossible) with the first. > > In describing this to a colleague, I found myself wondering if there was > a standard terminology for these two approaches. Does anyone know of > one? I would just call the first approach recursive. The second one also uses recursion, but not at the level of the macro, just for implementing the expansion, which you could do very easily with a loop or mapcar. I use the recursive approach so often that I have a utility function in tpapp-utils: (defmacro define-with-multiple-bindings (macro) "Define a version of `macro' with multiple arguments, given as a list. Application of `macro' will be nested. The new name is the plural of the old one (generated using format)." (let ((plural (intern (format nil "~aS" macro)))) `(defmacro ,plural (bindings &body body) ,(format nil "Multiple binding version of ~(~a~)." macro) (if bindings `(,',macro ,(car bindings) (,',plural ,(cdr bindings) ,@body)) `(progn ,@body))))) Eg CFFI has WITH-FOREIGN-POINTER, but lacks the plural form, so when I need it, I just (define-with-multiple-bindings with-foreign-pointer) Best, Tamas
From: nanothermite911fbibustards on 22 Jun 2010 01:59
Watch this: http://www.youtube.com/watch?v=kTn-w3xjprg&feature=related and share with others On Jun 21, 10:03 pm, Tamas K Papp <tkp...(a)gmail.com> wrote: > On Mon, 21 Jun 2010 16:08:01 -0400, Joshua Taylor wrote: > > Hi all, > > > Is there any kind of standard terminology for describing these two > > approaches to macroexpansion: > > > 1) Expand one layer at a time. > > > (defmacro let** (bindings &body body) > > (if (endp bindings) > > `(progn ,@body) > > (destructuring-bind (binding &rest bindings) bindings > > (destructuring-bind (var form) > > (if (listp binding) binding (list binding 'nil)) > > `(let ((,var ,form)) > > (let** ,bindings > > ,@body)))))) > > > Macroexpansion expands the outermost let**, but leaves more inside to be > > processed: > > > (macroexpand-1 '(let** ((x 1) > > (y (+ 1 x)) > > (z (+ 1 x y))) > > (list x y z))) > > (LET ((X 1)) (LET** ((Y (+ 1 X)) (Z (+ 1 X Y))) (LIST X Y Z))) > > > 2) Expand all layers at once. > > > (defmacro let*** (bindings &body body) > > (labels ((expand-let*** (bindings body) > > (if (endp bindings) > > `(progn ,@body) > > (destructuring-bind (binding &rest bindings) bindings > > (destructuring-bind (var form) > > (if (listp binding) binding (list binding 'nil)) > > `(let ((,var ,form)) > > ,(expand-let*** bindings body))))))) > > (expand-let*** bindings body))) > > > Macroexpansion expands all the bindings here, and anything in the body > > will be expanded later. > > > (macroexpand-1 '(let*** ((x 1) > > (y (+ 1 x)) > > (z (+ 1 x y))) > > (list x y z))) > > (LET ((X 1)) (LET ((Y (+ 1 X))) (LET ((Z (+ 1 X Y))) (PROGN (LIST X Y > > Z))))) > > > I think that the latter makes avoiding wrapping the body in progns a bit > > easier (e.g., a modification to this example that has expand-let*** > > return a list of forms), and I suppose that in some situations maybe > > file compilation could happen a bit quicker (since there would be fewer > > distinct calls to macroexpansion functions). I don't expect that these > > considerations are all that important, of course. > > > What I find more interesting are cases where the second approach makes > > things that seem to be impossible with the first. The instance that > > I've recently come across is that of destructuring binding wherein > > equality of subpatterns is to be enforced. E.g., causing some something > > like > > > (destructuring-bind* (op x x) '(+ 1 2) ...) > > > to fail (since x wouldn't be allowed to take on both non-eql values 1 > > and 2) is much easier with the second approach to macroexpansion, and > > much more difficult (if not impossible) with the first. > > > In describing this to a colleague, I found myself wondering if there was > > a standard terminology for these two approaches. Does anyone know of > > one? > > I would just call the first approach recursive. The second one also > uses recursion, but not at the level of the macro, just for > implementing the expansion, which you could do very easily with a loop > or mapcar. > > I use the recursive approach so often that I have a utility function > in tpapp-utils: > > (defmacro define-with-multiple-bindings (macro) > "Define a version of `macro' with multiple arguments, given as a > list. Application of `macro' will be nested. The new name is the > plural of the old one (generated using format)." > (let ((plural (intern (format nil "~aS" macro)))) > `(defmacro ,plural (bindings &body body) > ,(format nil "Multiple binding version of ~(~a~)." macro) > (if bindings > `(,',macro ,(car bindings) > (,',plural ,(cdr bindings) > ,@body)) > `(progn ,@body))))) > > Eg CFFI has WITH-FOREIGN-POINTER, but lacks the plural form, so when I > need it, I just > > (define-with-multiple-bindings with-foreign-pointer) > > Best, > > Tamas |