From: Eric de Groot
Subject: macro help
Date: 
Message-ID: <4THO6.27311$vf6.2706845@news1.rdc1.sdca.home.com>
I'm trying to write a macro but it's not working out like I thought it
would.  I want a macro that when called like:

(mymacro (format t "blah blah")
                (format t "blah blah")
                (format t "blah blah"))

Will insert a statement before and after the code inside the call and end up
being

(format t "first inserted statement")
(format t "blah blah")
(format t "blah blah")
(format t "blah blah")
(format t "second inserted statement")

Nothing fancy.

How would I write that?

Here's what I've tried so far:

(defmacro mymacro (&rest body)
  '(format t "first inserted statement")
  body
  '(format t "second inserted statement"))

When I try this like:

(mymacro (format t "body statement!"))

All I get is "second inserted statement", nothing else.

What am I doing wrong here?

Also, does anyone know of a good macro explaination with good examples on
the web?

Thanks.

-Eric
···········@ericdegroot.com

From: Jochen Schmidt
Subject: Re: macro help
Date: 
Message-ID: <9efj07$2kcd6$1@ID-22205.news.dfncis.de>
Eric de Groot wrote:

> I'm trying to write a macro but it's not working out like I thought it
> would.  I want a macro that when called like:
> 
> (mymacro (format t "blah blah")
>                 (format t "blah blah")
>                 (format t "blah blah"))
> 
> Will insert a statement before and after the code inside the call and end
> up being
> 
> (format t "first inserted statement")
> (format t "blah blah")
> (format t "blah blah")
> (format t "blah blah")
> (format t "second inserted statement")

You'll need a progn around that
(progn
 (format t "first inserted statement")
 (format t "blah blah")
 (format t "blah blah")
 (format t "blah blah")
 (format t "second inserted statement"))


 
> (defmacro mymacro (&rest body)
>   '(format t "first inserted statement")
>   body
>   '(format t "second inserted statement"))

Only the last form is returned!!!
 
> When I try this like:
> 
> (mymacro (format t "body statement!"))
> 
> All I get is "second inserted statement", nothing else.
> 
> What am I doing wrong here?

See above

Regards,
Jochen
From: Eric de Groot
Subject: Re: macro help
Date: 
Message-ID: <QKIO6.27401$vf6.2719430@news1.rdc1.sdca.home.com>
Thanks.  One more thing, I also had a problem getting my &rest arg to work.
In order to prevent an additional set of parens around all the forms I had
to put an @ symbol in front of the var like this:

(defun mymacro (&rest contents)
  `(progn (format t "pre statement")
              ,@contents
              (format t "post statement")))

What does the @ do exactly?  I just saw it in an example in the book I have,
but there was no explaination as to what exactly it does or means.  Where
else and how can it be used?  All I know is it prevented the extra parens.

Thanks again.

-Eric
···········@ericdegroot.com



"Jochen Schmidt" <···@dataheaven.de> wrote in message
···················@ID-22205.news.dfncis.de...
> Eric de Groot wrote:
>
> > I'm trying to write a macro but it's not working out like I thought it
> > would.  I want a macro that when called like:
> >
> > (mymacro (format t "blah blah")
> >                 (format t "blah blah")
> >                 (format t "blah blah"))
> >
> > Will insert a statement before and after the code inside the call and
end
> > up being
> >
> > (format t "first inserted statement")
> > (format t "blah blah")
> > (format t "blah blah")
> > (format t "blah blah")
> > (format t "second inserted statement")
>
> You'll need a progn around that
> (progn
>  (format t "first inserted statement")
>  (format t "blah blah")
>  (format t "blah blah")
>  (format t "blah blah")
>  (format t "second inserted statement"))
>
>
>
> > (defmacro mymacro (&rest body)
> >   '(format t "first inserted statement")
> >   body
> >   '(format t "second inserted statement"))
>
> Only the last form is returned!!!
>
> > When I try this like:
> >
> > (mymacro (format t "body statement!"))
> >
> > All I get is "second inserted statement", nothing else.
> >
> > What am I doing wrong here?
>
> See above
>
> Regards,
> Jochen
From: Jochen Schmidt
Subject: Re: macro help
Date: 
Message-ID: <9efmca$2ptvp$1@ID-22205.news.dfncis.de>
Eric de Groot wrote:

> Thanks.  One more thing, I also had a problem getting my &rest arg to
> work. In order to prevent an additional set of parens around all the forms
> I had to put an @ symbol in front of the var like this:
> 
> (defun mymacro (&rest contents)
>   `(progn (format t "pre statement")
>               ,@contents
>               (format t "post statement")))
> 
> What does the @ do exactly?  I just saw it in an example in the book I
> have,
> but there was no explaination as to what exactly it does or means.  Where
> else and how can it be used?  All I know is it prevented the extra parens.

It's the "Splicing operator"

`(1 2 3 ,@4) => (cons '(1 2 3) 4) ==> (1 2 3 . 4)

`(1 2 3 ,@(list 4 5)) => (cons '(1 2 3) (list 4 5)) ==> (1 2 3 4)
`(1 2 3 ,@(list 4 5) 6 7) => (cons '(1 2 3) (append (list 4 5) '(6 7))) 
  ==> (1 2 3 4 5 6 7)
`(1 2 3 ,@4 5) => Error

Regards,
Jochen
From: Eric de Groot
Subject: Re: macro help
Date: 
Message-ID: <D4JO6.27409$vf6.2725660@news1.rdc1.sdca.home.com>
Cool.  But how come without @ I got:

((format t "blah") (format t "blah"))

and with the @ I got:

(format t "blah") (format t "blah")

if it was like cons, wouldent I get:

(format t "blah" format t "blah") ?

Thanks.

-eric

"Jochen Schmidt" <···@dataheaven.de> wrote in message
···················@ID-22205.news.dfncis.de...
> Eric de Groot wrote:
>
> > Thanks.  One more thing, I also had a problem getting my &rest arg to
> > work. In order to prevent an additional set of parens around all the
forms
> > I had to put an @ symbol in front of the var like this:
> >
> > (defun mymacro (&rest contents)
> >   `(progn (format t "pre statement")
> >               ,@contents
> >               (format t "post statement")))
> >
> > What does the @ do exactly?  I just saw it in an example in the book I
> > have,
> > but there was no explaination as to what exactly it does or means.
Where
> > else and how can it be used?  All I know is it prevented the extra
parens.
>
> It's the "Splicing operator"
>
> `(1 2 3 ,@4) => (cons '(1 2 3) 4) ==> (1 2 3 . 4)
>
> `(1 2 3 ,@(list 4 5)) => (cons '(1 2 3) (list 4 5)) ==> (1 2 3 4)
> `(1 2 3 ,@(list 4 5) 6 7) => (cons '(1 2 3) (append (list 4 5) '(6 7)))
>   ==> (1 2 3 4 5 6 7)
> `(1 2 3 ,@4 5) => Error
>
> Regards,
> Jochen
>
From: Barry Margolin
Subject: Re: macro help
Date: 
Message-ID: <fHPO6.18$XB6.812@burlma1-snr2>
In article <·······················@news1.rdc1.sdca.home.com>,
Eric de Groot <············@ericdegroot.com> wrote:
>Cool.  But how come without @ I got:
>
>((format t "blah") (format t "blah"))
>
>and with the @ I got:
>
>(format t "blah") (format t "blah")
>
>if it was like cons, wouldent I get:
>
>(format t "blah" format t "blah") ?

The &rest parameter is bound to a list of all the rest of the argument
forms.  So if you do

(mymacro x y)

CONTENTS is bound to the list (x y).  Similarly, if you do

(mymacro (format t "blah") (format t "blah"))

CONTENTS will be bound to the list ((format t "blah") (format t "blah")).

If you use , instead of ,@ to insert this into the result, the list is
placed directly in the result, i.e. (x ,contents y) becomes (list 'x
contents 'y).  But if you use ,@ instead, it's spliced in by using some
combination of functions like CONS and APPEND: (x ,@ y) becomes (cons 'x
(append contents '(y))).

-- 
Barry Margolin, ······@genuity.net
Genuity, 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: Eric de Groot
Subject: Re: macro help
Date: 
Message-ID: <IeKO6.27699$vf6.2735358@news1.rdc1.sdca.home.com>
Is it possible to combine &key and &rest?  So a call to mymacro would be
like:

(mymacro :blah 2 :toast 1
  (format t "blah blah blah")
  (format t "blah blah blah"))

the &key parameters blah and toast would be used to generate the resulting
form.

when I do

(defmacro mymacro (&key (blah nil) &rest contents)
...etc

I get an error saying i have a badly placed rest.

Also what does &body do?  I've seen that in a few examples, but everything
only seems to mention &key, &rest, and auxillary.

Oh, and another thing, when generating the resulting form in a macro, with
if statements would you do it like:

(defmacro mymacro (&key (blah nil) &rest contents)
  (let ((x '(progn (format t "first statement"))))
    (when (not (eq nil blah))
      (cons x '(format t "an extra statement")))
    (cons x ,@contents '(format t "last statement"))
    x))

Thanks a lot.  I've read books, and it all sounds good and easy, but when
you actually get down and start using...;)  Lisp is rad, I've been a
C/C++/Java programmer for years and was always been disappointed, I only
wish I decided to learn lisp sooner.  Hopefully once i've got it good enough
I can get my employer to pay me to use it instead of other langs heh heh;)
anyways, thanks again!

-eric

"Jochen Schmidt" <···@dataheaven.de> wrote in message
···················@ID-22205.news.dfncis.de...
> Eric de Groot wrote:
>
> > Thanks.  One more thing, I also had a problem getting my &rest arg to
> > work. In order to prevent an additional set of parens around all the
forms
> > I had to put an @ symbol in front of the var like this:
> >
> > (defun mymacro (&rest contents)
> >   `(progn (format t "pre statement")
> >               ,@contents
> >               (format t "post statement")))
> >
> > What does the @ do exactly?  I just saw it in an example in the book I
> > have,
> > but there was no explaination as to what exactly it does or means.
Where
> > else and how can it be used?  All I know is it prevented the extra
parens.
>
> It's the "Splicing operator"
>
> `(1 2 3 ,@4) => (cons '(1 2 3) 4) ==> (1 2 3 . 4)
>
> `(1 2 3 ,@(list 4 5)) => (cons '(1 2 3) (list 4 5)) ==> (1 2 3 4)
> `(1 2 3 ,@(list 4 5) 6 7) => (cons '(1 2 3) (append (list 4 5) '(6 7)))
>   ==> (1 2 3 4 5 6 7)
> `(1 2 3 ,@4 5) => Error
>
> Regards,
> Jochen
>
From: Pierre R. Mai
Subject: Re: macro help
Date: 
Message-ID: <87vgmsl86h.fsf@orion.bln.pmsf.de>
"Eric de Groot" <············@ericdegroot.com> writes:

> Is it possible to combine &key and &rest?  So a call to mymacro would be
> like:

It is possible, but you'll have to do some post-processing on the rest
parameter, since the keywords and values will also be included in the
rest parameter.  For macros it is nearly always better to put keyword
parameters into their own sub-list, i.e. instead of

> (mymacro :blah 2 :toast 1
>   (format t "blah blah blah")
>   (format t "blah blah blah"))

You do 

(mymacro (:blah 2 :toast 1)
  (format t "blah blah blah")
  (format t "blah blah blah"))

That way you will receive the keyword and rest/body arguments nicely
separated.

> (defmacro mymacro (&key (blah nil) &rest contents)
> ...etc
> 
> I get an error saying i have a badly placed rest.

You need to place the rest parameter before the &key parameters, like
this:

(defmacro mymacro (&rest contents &key blah toast)
  ...)

For the preferred macro syntax I posted, the correct syntax uses
destructuring in order to get at the &key parameters, in this way:

(defmacro mymacro ((&key blah toast) &rest contents)
  ...)

> Also what does &body do?  I've seen that in a few examples, but everything
> only seems to mention &key, &rest, and auxillary.

&body is exactly like &rest, but it indicates to 3rd parties (editors,
pretty-printers, compilers, people reading your source), that the rest
parameter is really the body of a construct, like e.g. the body of a
defun.

In your case using &body seems apropriate.

> (defmacro mymacro (&key (blah nil) &rest contents)
>   (let ((x '(progn (format t "first statement"))))
>     (when (not (eq nil blah))
>       (cons x '(format t "an extra statement")))

This isn't going to do what you expect it to do.  cons doesn't modify
its arguments, it just creates a new return value.  If you want to
side effect x, then you need to assign the return value to x using
setq.  Furthermore you need to play around with lists a bit more to
understand how to build up lists from conses.

>     (cons x ,@contents '(format t "last statement"))

You can only use , and ,@ inside a backquoted structure.  Backquote
and ,/,@ are used instead of cons, list, nconc, etc., not together
with them.

>     x))

Furthermore beware that when writing macros, the arguments you receive
haven't been evaluated yet, so testing their values at compile-time
(i.e. unevaluated) is normally not what you want to be doing, except
under very special circumstances.

What I think you really want to be doing is something like this:

(defmacro mymacro ((&key blah) &body body)
  `(progn
     (format t "first statement")
     (when ,blah
       (format t "second statement"))
     ,@body
     (format t "last statement")))

In fact, if you care about the return value of the last form in your
body (which you should, because people expect bodies to behave like
implicit progn forms, unless there are really good reasons for
expecting otherwise), then this should be:

(defmacro mymacro ((&key blah) &body body)
  `(multiple-value-prog1
       (progn
         (format t "first statement")
         (when ,blah
           (format t "second statement"))
         (progn
           ,@body))
     (format t "last statement")))

Of course if you really want to test the unevaluated blah form, then
you'll have to do things differently, but that should be done only
under very specific circumstances.

Hope this helps.

Regs, Pierre.

-- 
Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
 The most likely way for the world to be destroyed, most experts agree,
 is by accident. That's where we come in; we're computer professionals.
 We cause accidents.                           -- Nathaniel Borenstein
From: Eric de Groot
Subject: Re: macro help
Date: 
Message-ID: <qXYO6.28521$vf6.2802386@news1.rdc1.sdca.home.com>
Nuts.  That woulda been sweet to beable to call a macro like that:

(mymacro :blah 1 :bleh 2
  (format t "toast")
  (format t "toast"))

I started writing to macro to generate a form that detects those keys in
body, setqs a var using the following symbol as the value, and then pop'ing
both, but it seemed like more trouble than it was worth.  Anyone know of any
example code that does this?  Instead I'm trying this:

(defmacro mymacro (attributes &body body)
  ...)

and calling it like:

(mymacro '(("blah" 1) ("bleh" 2))
  (format t "toast")
  (format t "toast"))

and using assoc in the generated form to detect/read.

Is that bad form?  Seems ok to me, though being able to use &keys would have
been sweet..  I know I can just have a fixed number of parameters, but for
this macro there are like 10 attributes, and none are required.  Having to
enter nil for each and remember the order would suck.

Thanks.

-eric


"Pierre R. Mai" <····@acm.org> wrote in message
···················@orion.bln.pmsf.de...
> "Eric de Groot" <············@ericdegroot.com> writes:
>
> > Is it possible to combine &key and &rest?  So a call to mymacro would be
> > like:
>
> It is possible, but you'll have to do some post-processing on the rest
> parameter, since the keywords and values will also be included in the
> rest parameter.  For macros it is nearly always better to put keyword
> parameters into their own sub-list, i.e. instead of
>
> > (mymacro :blah 2 :toast 1
> >   (format t "blah blah blah")
> >   (format t "blah blah blah"))
>
> You do
>
> (mymacro (:blah 2 :toast 1)
>   (format t "blah blah blah")
>   (format t "blah blah blah"))
>
> That way you will receive the keyword and rest/body arguments nicely
> separated.
>
> > (defmacro mymacro (&key (blah nil) &rest contents)
> > ...etc
> >
> > I get an error saying i have a badly placed rest.
>
> You need to place the rest parameter before the &key parameters, like
> this:
>
> (defmacro mymacro (&rest contents &key blah toast)
>   ...)
>
> For the preferred macro syntax I posted, the correct syntax uses
> destructuring in order to get at the &key parameters, in this way:
>
> (defmacro mymacro ((&key blah toast) &rest contents)
>   ...)
>
> > Also what does &body do?  I've seen that in a few examples, but
everything
> > only seems to mention &key, &rest, and auxillary.
>
> &body is exactly like &rest, but it indicates to 3rd parties (editors,
> pretty-printers, compilers, people reading your source), that the rest
> parameter is really the body of a construct, like e.g. the body of a
> defun.
>
> In your case using &body seems apropriate.
>
> > (defmacro mymacro (&key (blah nil) &rest contents)
> >   (let ((x '(progn (format t "first statement"))))
> >     (when (not (eq nil blah))
> >       (cons x '(format t "an extra statement")))
>
> This isn't going to do what you expect it to do.  cons doesn't modify
> its arguments, it just creates a new return value.  If you want to
> side effect x, then you need to assign the return value to x using
> setq.  Furthermore you need to play around with lists a bit more to
> understand how to build up lists from conses.
>
> >     (cons x ,@contents '(format t "last statement"))
>
> You can only use , and ,@ inside a backquoted structure.  Backquote
> and ,/,@ are used instead of cons, list, nconc, etc., not together
> with them.
>
> >     x))
>
> Furthermore beware that when writing macros, the arguments you receive
> haven't been evaluated yet, so testing their values at compile-time
> (i.e. unevaluated) is normally not what you want to be doing, except
> under very special circumstances.
>
> What I think you really want to be doing is something like this:
>
> (defmacro mymacro ((&key blah) &body body)
>   `(progn
>      (format t "first statement")
>      (when ,blah
>        (format t "second statement"))
>      ,@body
>      (format t "last statement")))
>
> In fact, if you care about the return value of the last form in your
> body (which you should, because people expect bodies to behave like
> implicit progn forms, unless there are really good reasons for
> expecting otherwise), then this should be:
>
> (defmacro mymacro ((&key blah) &body body)
>   `(multiple-value-prog1
>        (progn
>          (format t "first statement")
>          (when ,blah
>            (format t "second statement"))
>          (progn
>            ,@body))
>      (format t "last statement")))
>
> Of course if you really want to test the unevaluated blah form, then
> you'll have to do things differently, but that should be done only
> under very specific circumstances.
>
> Hope this helps.
>
> Regs, Pierre.
>
> --
> Pierre R. Mai <····@acm.org>                    http://www.pmsf.de/pmai/
>  The most likely way for the world to be destroyed, most experts agree,
>  is by accident. That's where we come in; we're computer professionals.
>  We cause accidents.                           -- Nathaniel Borenstein
From: Jochen Schmidt
Subject: Re: macro help
Date: 
Message-ID: <9ehmpq$335e4$1@ID-22205.news.dfncis.de>
Eric de Groot wrote:


> 
> (mymacro '(("blah" 1) ("bleh" 2))
>   (format t "toast")
>   (format t "toast"))
> 
> and using assoc in the generated form to detect/read.
> 
> Is that bad form?  Seems ok to me, though being able to use &keys would
> have
> been sweet..  I know I can just have a fixed number of parameters, but for
> this macro there are like 10 attributes, and none are required.  Having to
> enter nil for each and remember the order would suck.

Why not...

(defmacro mymacro ((&key (blah 1) (bleh 2)) &body body)
 `(progn (format t "first statement")
            ,@body
           (format t "last statement")))

(mymacro (:blah 4 :bleh 2) (format t "Body"))

If you would not use any keyword-parameters you'll have to use the empty 
list:

(mymacro () (format t "Body"))

Regards,
Jochen
From: Eric de Groot
Subject: Re: macro help
Date: 
Message-ID: <ZsZO6.28661$vf6.2809394@news1.rdc1.sdca.home.com>
Ah I see.  This is what I wrote to test using assoc:

(defmacro mymacro (attributes &body body)
  `(progn (format t "first statement~%")
              (dolist (attribute ,attributes)
                (format t "~a=~a~%" (first attribute) (second attribute)))
              (format t "second statement~%")
              ,@body
              (format t "last statement~%")))

calling it like:

(mymacro '(("blah" 1) ("bleh" 2))
  (format t "toast"))

works fine, but still requires a '() if not specifying any attributes, which
sucks..  so I might aswell do it the way you said with the keys.  Does lisp
have any function overloading?  I could have one macrodef with the keys, and
one macrodef with no keys at all..  I don't think so though..

Thanks.

-eric


"Jochen Schmidt" <···@dataheaven.de> wrote in message
···················@ID-22205.news.dfncis.de...
> Eric de Groot wrote:
>
>
> >
> > (mymacro '(("blah" 1) ("bleh" 2))
> >   (format t "toast")
> >   (format t "toast"))
> >
> > and using assoc in the generated form to detect/read.
> >
> > Is that bad form?  Seems ok to me, though being able to use &keys would
> > have
> > been sweet..  I know I can just have a fixed number of parameters, but
for
> > this macro there are like 10 attributes, and none are required.  Having
to
> > enter nil for each and remember the order would suck.
>
> Why not...
>
> (defmacro mymacro ((&key (blah 1) (bleh 2)) &body body)
>  `(progn (format t "first statement")
>             ,@body
>            (format t "last statement")))
>
> (mymacro (:blah 4 :bleh 2) (format t "Body"))
>
> If you would not use any keyword-parameters you'll have to use the empty
> list:
>
> (mymacro () (format t "Body"))
>
> Regards,
> Jochen