From: Andrew Cooke
Subject: macro macros
Date: 
Message-ID: <86nq4m$vt9$1@nnrp1.deja.com>
Hi,

The code below shows my attempts at writing a macro that generates
macro code.  I have had to introduce a "let" (in the third example) to
get arguments of the outer macro inserted into the inner macro.

The final attempt does what I want, but is ugly, evaluates "outer-arg"
and (I think) will shadow the variable "inner-copy" (not important in
these stylised examples, but worrying in the code I am writing).  How
should it be done?

Sorry to keep asking questions to this list - if you didn't post such
useful answers I'd go away :-)

Thanks,
Andrew


; single comma at two levels of quotes - would give an error at run-time
(defmacro macro-macro-1 (outer-arg)
  `(defmacro generated (inner-arg)
     `(progn
        (format t "inner-arg" ,inner-arg)
        (format t "outer-arg" ,outer-arg))))
(mac (macro-macro-1 1))

(DEFMACRO GENERATED (INNER-ARG)
  `(PROGN (FORMAT T "inner-arg" ,INNER-ARG) (FORMAT T "outer-arg"
,OUTER-ARG))
)

; two commas in two quotes - leaves an extra comma
(defmacro macro-macro-2 (outer-arg)
  `(defmacro generated (inner-arg)
     `(progn
        (format t "inner-arg" ,inner-arg)
        (format t "outer-arg" ,,outer-arg))))
(mac (macro-macro-2 1))

(DEFMACRO GENERATED (INNER-ARG)
  `(PROGN (FORMAT T "inner-arg" ,INNER-ARG) (FORMAT T "outer-arg" ,1))
)

; an extra "let" - this has the effect i want
(defmacro macro-macro-3 (outer-arg)
  `(defmacro generated (inner-arg)
     (let ((inner-copy ,outer-arg))
       `(progn
          (format t "inner-arg" ,inner-arg)
          (format t "outer-arg" ,inner-copy)))))

(mac (macro-macro-3 1))

(DEFMACRO GENERATED (INNER-ARG)
  (LET ((INNER-COPY 1))
    `(PROGN (FORMAT T "inner-arg" ,INNER-ARG)
       (FORMAT T "outer-arg" ,INNER-COPY)
) )  )


Sent via Deja.com http://www.deja.com/
Before you buy.

From: Michael Hudson
Subject: Re: macro macros
Date: 
Message-ID: <m31z74iijd.fsf@atrus.jesus.cam.ac.uk>
Andrew Cooke <······@andrewcooke.free-online.co.uk> writes:

> Hi,
> 
> The code below shows my attempts at writing a macro that generates
> macro code.  I have had to introduce a "let" (in the third example) to
> get arguments of the outer macro inserted into the inner macro.
> 
> The final attempt does what I want, but is ugly, evaluates "outer-arg"
> and (I think) will shadow the variable "inner-copy" (not important in
> these stylised examples, but worrying in the code I am writing).  How
> should it be done?
> 
> Sorry to keep asking questions to this list - if you didn't post such
> useful answers I'd go away :-)
> 
> Thanks,
> Andrew

[schnipp]

> ; two commas in two quotes - leaves an extra comma
> (defmacro macro-macro-2 (outer-arg)
>   `(defmacro generated (inner-arg)
>      `(progn
>         (format t "inner-arg" ,inner-arg)
>         (format t "outer-arg" ,,outer-arg))))
> (mac (macro-macro-2 1))
> 
> (DEFMACRO GENERATED (INNER-ARG)
>   `(PROGN (FORMAT T "inner-arg" ,INNER-ARG) (FORMAT T "outer-arg" ,1))
> )

Almost.

[20]> (defmacro macro-macro-2 (outer-arg)
  `(defmacro generated (inner-arg)
     `(progn
        (format t "inner-arg" ,inner-arg)
        (format t "outer-arg" ,',outer-arg))))
MACRO-MACRO-2
[21]> (macroexpand-1 '(macro-macro-2 1))
(DEFMACRO GENERATED (INNER-ARG)
  `(PROGN (FORMAT T "inner-arg" ,INNER-ARG) (FORMAT T "outer-arg" 1))
) ;
T

That what you wanted?

Cheers,
Michael
From: Joe Marshall
Subject: Re: macro macros
Date: 
Message-ID: <UrZj4.55705$Rj5.44209@dfw-read.news.verio.net>
The important trick here, as Michael Hudson is obviously aware of, is
that to `pop' two levels in a backquote you use ,',  rather than ,,


Michael Hudson <·····@cam.ac.uk> wrote in message
···················@atrus.jesus.cam.ac.uk...
> Andrew Cooke <······@andrewcooke.free-online.co.uk> writes:
>
> > Hi,
> >
> > The code below shows my attempts at writing a macro that generates
> > macro code.  I have had to introduce a "let" (in the third example) to
> > get arguments of the outer macro inserted into the inner macro.
> >
> > The final attempt does what I want, but is ugly, evaluates "outer-arg"
> > and (I think) will shadow the variable "inner-copy" (not important in
> > these stylised examples, but worrying in the code I am writing).  How
> > should it be done?
> >
> > Sorry to keep asking questions to this list - if you didn't post such
> > useful answers I'd go away :-)
> >
> > Thanks,
> > Andrew
>
> [schnipp]
>
> > ; two commas in two quotes - leaves an extra comma
> > (defmacro macro-macro-2 (outer-arg)
> >   `(defmacro generated (inner-arg)
> >      `(progn
> >         (format t "inner-arg" ,inner-arg)
> >         (format t "outer-arg" ,,outer-arg))))
> > (mac (macro-macro-2 1))
> >
> > (DEFMACRO GENERATED (INNER-ARG)
> >   `(PROGN (FORMAT T "inner-arg" ,INNER-ARG) (FORMAT T "outer-arg" ,1))
> > )
>
> Almost.
>
> [20]> (defmacro macro-macro-2 (outer-arg)
>   `(defmacro generated (inner-arg)
>      `(progn
>         (format t "inner-arg" ,inner-arg)
>         (format t "outer-arg" ,',outer-arg))))
> MACRO-MACRO-2
> [21]> (macroexpand-1 '(macro-macro-2 1))
> (DEFMACRO GENERATED (INNER-ARG)
>   `(PROGN (FORMAT T "inner-arg" ,INNER-ARG) (FORMAT T "outer-arg" 1))
> ) ;
> T
>
> That what you wanted?
>
> Cheers,
> Michael
From: Michael Hudson
Subject: Re: macro macros
Date: 
Message-ID: <m3ya9bzb6p.fsf@atrus.jesus.cam.ac.uk>
"Joe Marshall" <·········@alum.mit.edu> writes:

> The important trick here, as Michael Hudson is obviously aware of, is
> that to `pop' two levels in a backquote you use ,',  rather than ,,

Not so much "aware of" as "bloody minded enough to fiddle until it
works", though I hope I'll be able to remember next time I need to use
it...

Cheers,
M.
From: Thomas A. Russ
Subject: Re: macro macros
Date: 
Message-ID: <ymipuun1j5z.fsf@sevak.isi.edu>
Andrew Cooke <······@andrewcooke.free-online.co.uk> writes:

Others have pointed out the ,', trick.  I'll handle another detail that
you (quite wisely) touched upon:

>The final attempt does what I want, but is ugly, evaluates "outer-arg"
>and (I think) will shadow the variable "inner-copy" (not important in
>these stylised examples, but worrying in the code I am writing).  How
>should it be done?

> ; an extra "let" - this has the effect i want
> (defmacro macro-macro-3 (outer-arg)
>   `(defmacro generated (inner-arg)
>      (let ((inner-copy ,outer-arg))
>        `(progn
>           (format t "inner-arg" ,inner-arg)
>           (format t "outer-arg" ,inner-copy)))))

The usual solution to this is to use Lisp's GENSYM function to produce a
guaranteed fresh uninterned symbol.  The uninterned part is important,
because it means that the name cannot be used to find the symbol.  The
importance of that is that it means the variable capture problem is
solved, since even if a user typed a symbol with the same name, it
would be DIFFERENT from the GENSYM'd symbol.

(defmacro macro-macro-3 (outer-arg)
  (let ((let-var (gensym "ARG-")))     ;; We need a binding to the
                                      ;;   created variable.
   `(defmacro generated (inner-arg)
      (let ((,let-var ,outer-arg))
        `(progn
           (format t "inner-arg" ,inner-arg)
           (format t "outer-arg" ,,let-var))))))


The technique of using a generated variable is also useful to avoid
evaluating arguments to a macro twice:

(defmacro bad-double (arg)
  `(+ ,arg ,arg))

(defmacro good-double (arg)
  (let ((let-var (gensym "ARG-")))
    `(let ((,let-var ,arg))
       (+ ,let-var ,let-var))))

To see the difference, try the following:

(defvar *foo*)
(setq *foo* 2)
(bad-double (incf *foo*))   => 7    *foo* = 4

(setq *foo* 2)
(good-double (incf *foo*))  => 6    *foo* = 3


That is because bad-double expands into:

  (+ (INCF *FOO*) (INCF *FOO*))

whereas good-double expands into something like:

(LET ((#:ARG-36006 (INCF *FOO*))) 
  (+ #:ARG-36006 #:ARG-36006))

-Tom.

-- 
Thomas A. Russ,  USC/Information Sciences Institute          ···@isi.edu    
From: Barry Margolin
Subject: Re: macro macros
Date: 
Message-ID: <gULj4.31$m86.2517@burlma1-snr2>
In article <············@nnrp1.deja.com>,
Andrew Cooke  <······@andrewcooke.free-online.co.uk> wrote:
>The code below shows my attempts at writing a macro that generates
>macro code.  I have had to introduce a "let" (in the third example) to
>get arguments of the outer macro inserted into the inner macro.

FYI, very few Lisp programmers are able to write macro-generating macros
well.  Getting them right is the hallmark of being an accomplished
macrologist.  And if you can write third-level macros, you're a macro
wizard.  Good luck in your progress towards that level.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Samir Barjoud
Subject: Re: macro macros
Date: 
Message-ID: <wk66wgxlw1.fsf@mindspring.com>
Barry Margolin <······@bbnplanet.com> writes:

> FYI, very few Lisp programmers are able to write macro-generating macros
> well.  Getting them right is the hallmark of being an accomplished
> macrologist.  And if you can write third-level macros, you're a macro
> wizard.  Good luck in your progress towards that level.
> 

Do you have any examples of the use of third-level macros?

-- 
Samir Barjoud
·····@mindspring.com
From: Andrew Cooke
Subject: Re: macro macros
Date: 
Message-ID: <86oue9$pe5$1@nnrp1.deja.com>
In article <··············@mindspring.com>,
  Samir Barjoud <·····@mindspring.com> wrote:
> Barry Margolin <······@bbnplanet.com> writes:
>
> > FYI, very few Lisp programmers are able to write macro-generating
macros
> > well.  Getting them right is the hallmark of being an accomplished
> > macrologist.  And if you can write third-level macros, you're a
macro
> > wizard.  Good luck in your progress towards that level.
> >
>
> Do you have any examples of the use of third-level macros?


I can imagine an example.  I am writing second-level macros because I
have a macro which generates an environment in which variables (not
visible directly to the user) are used to provide some extra
functionality.  This uses macrolet to provide macros within the
environment that can access those variables (as suggested in another
thread here).  So a macro that helps me write such macros could be third
level (I've not written enough to know whether there's anything to
abstract into such a macro, though).

(Thanks for all the replies)

Andrew


Sent via Deja.com http://www.deja.com/
Before you buy.