From: Doug Tolton
Subject: Winstond and Horn Macros
Date: 
Message-ID: <p5f2jvo5cmjfbfrei7ht4s5rq992mdni2u@4ax.com>
Ok, so I've been working through Winston and Horn's book, When I got
to chapter 12 on Macros and Backquote it pretty much made sense to me,
however when I was working through the problems I got completely stuck
on problem 12-4 and on.    I re-read portions of the chapter, and I
think there is something I'm just not getting with Macros.

Problem 12-4 is:
Suppose, for some immensely peculiar reason, you want a form of LET
that does not evaluate initial value forms.  Define LETQ such that
LETQ arranges the following translation:
(letq ((<variable1> <value1>)
         (<variable2> <value2>)
          ...)
  <body> )

translate to:

(let ((<variable1> '<value1>)
       (<variable2> '<value2>)
       ...)
  <body> )


This question seems to have jumped several notches in difficulty
compared to 12-3 which is just defining a WHEN-NIL form that
translates to (when (not

(when-nil <trigger> <result>)

translate to 

(when (not <trigger> <result))

so I wrote this macro:
(defmacro when-nil (trigger result)
   `(when (not ,trigger) ,result))

for the most part in Winston and Horn they seem to use very simple
translations, and avoid building any type of very complex form.  I
could just be missing something simple, but I don't understand how I
would take an arbitrary number of variables, and map only value
expressions so they aren't evaluated.  Is there something simple I'm
missing?  Or is there an entire conceptual idea I'm not getting?

I've seen reference to macroexpand, does this return the expanded form
of the macro?

Thanks in advance,
Doug Tolton

From: Kaz Kylheku
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <cf333042.0308061450.656d4c86@posting.google.com>
Doug Tolton <·······@yahoo.com> wrote in message news:<··································@4ax.com>...
> Problem 12-4 is:
> Suppose, for some immensely peculiar reason, you want a form of LET
> that does not evaluate initial value forms.  Define LETQ such that
> LETQ arranges the following translation:
> (letq ((<variable1> <value1>)
>          (<variable2> <value2>)
>           ...)
>   <body> )
>
> translate to:
> 
> (let ((<variable1> '<value1>)
>        (<variable2> '<value2>)
>        ...)
>   <body> )

[ snip ]

> I
> could just be missing something simple, but I don't understand how I
> would take an arbitrary number of variables, and map only value
> expressions so they aren't evaluated.  Is there something simple I'm
> missing?  Or is there an entire conceptual idea I'm not getting?

A macro is just a Lisp function that turns the list (LETQ ...) to (LET
...) according to the above schema. Write a function that does this,
and then turn it into a macro.

You might be confused by the DEFMACRO utility, which has built-in
destructuring. Prior to things like DEFMACRO, Lisp macros were written
as ordinary functions that worked on the entire form. A LETQ macro
would receive just one argument: the entire source code of the macro
call: (LETQ ...)

With DEFMACRO, you have some built-in analysis. The form is matched
against a syntactic pattern, and pieces are assigned to variables. 
(You can still receive the entire form in one piece using the &whole
lambda keyword).

With the preprocessing that DEFMACRO performs, it's no longer as
obvious to newbies that the macro is a function that turns one form
into another.

When there are repeated units to be handled, like ((<variable> <value>
...)) lists, newbies get confused, because they can't find the right
DEFMACRO syntax which would nicely destructure it without any
expenditure of programming work. ;)

The answer is that where DEFMACRO's destructuring runs out of steam,
you have to switch to ``manual'' list processing. For example, you can
capture the entire ((<variable> <value>) ...) sublist, attaching it to
one variable:

  (defmacro letq ((&rest variable-value-list) &body forms)
    `(let ,(transform-variable-value-list variable-value-list)
       ,@forms))

Now you just need to write the function TRANSFORM-VARIABLE-VALUE-LIST.
This can be done using

   (loop for (variable value) in variable-value-list
         collecting `(,variable (quote ,value)))

so the whole macro becomes:

  (defmacro letq ((&rest variable-value-list) &body forms)
    (let ((transformed-list (loop for (variable value)
                                  in variable-value-list
                                  collecting `(,variable ',value))))
      `(let ,transformed-list ,@forms)))

In other words, the function is nice and short so we roll it into the
body of the macro, thus sparing ourselves a lesson about eval-when. ;)

Note how we leveraged the built-in destructuring facility of the IN
clause of the LOOP macro. With LOOP we can iterate over lists
containing substructures, and pull apart each substructure according
to a syntax like (VARIABLE VALUE). The in the COLLECTING clause we
used a backquote to re-integrate the destructured material to the
shape we want.

So we have two similar levels of processing going on: the LETQ macro
as a whole performs coarse-grained destructuring and reassembly on the
entire form, and the LOOP does it on a fine level within the lambda
list.

Note that for LETQ to be useful, it should to handle lambda list items
clauses which don't fit the (VARIABLE VALUE) syntax, such as simple
VARIABLE items.

> I've seen reference to macroexpand, does this return the expanded form
> of the macro?

Yes. Very useful for debugging macros. For instance, we can use it on
the above macro:

  [12]> (macroexpand '(letq ((a b) (c d)) z))
  (LET ((A 'B) (C 'D)) Z) ;
  T

Looks good!

The T, by the way, is a second value which tells us that the form was
recognized as a macro call and expanded.
From: Conrad Barski
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <a4af10cf.0308061807.3674339f@posting.google.com>
I find it easier to think of

(let ((a 'b) (c 'd)) ...
    
as

(let ((a (quote b)) (c (quote d))) ...


The quote symbols are just a nicety that makes lisp programs easier to
read. The key now is to think of the letq source block as simply a
list of symbols (NOT a program) that need to be changed:

(letq ((a 1) (b 1)) ...)
   |
   |
   |
   V
(let ((a (quote b)) (c (quote d))) ...)


Write a program that does this and your macro is done.
From: Barry Margolin
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <FrbYa.64$Mg5.0@news.level3.com>
In article <··································@4ax.com>,
Doug Tolton  <·······@yahoo.com> wrote:
>for the most part in Winston and Horn they seem to use very simple
>translations, and avoid building any type of very complex form.  I
>could just be missing something simple, but I don't understand how I
>would take an arbitrary number of variables, and map only value
>expressions so they aren't evaluated.  Is there something simple I'm
>missing?  Or is there an entire conceptual idea I'm not getting?

Lisp macros have the full capabilities of Lisp at their disposal.  In
particular, you can use MAPCAR or LOOP to iterate over a list.

>I've seen reference to macroexpand, does this return the expanded form
>of the macro?

Yes.  It's used to debug macros.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, 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: Doug Tolton
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <6qo2jv88qisi6fb71s97jriejdoivrk77h@4ax.com>
On Wed, 06 Aug 2003 18:05:25 GMT, Barry Margolin
<··············@level3.com> wrote:

>In article <··································@4ax.com>,
>Doug Tolton  <·······@yahoo.com> wrote:
>Lisp macros have the full capabilities of Lisp at their disposal.  In
>particular, you can use MAPCAR or LOOP to iterate over a list.

I believe they said that in the book, but they didn't really cover how
to take advandage of them for anything but a trivial example.  There
was no looping or recursion in the examples.

Should I be building up a list to return for execution?  Are there any
specific gotchas, or is there somewhere that I can read a more
detailed exposition on the usage of macros?  I would really like to
seem some really good examples with a detailed dissection of how the
code is constructed.  Then again, I want a better tax code system too.

Doug Tolton

p.s. sorry to Winston for the typo
From: Barry Margolin
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <NHdYa.71$Mg5.44@news.level3.com>
In article <··································@4ax.com>,
Doug Tolton  <·······@yahoo.com> wrote:
>On Wed, 06 Aug 2003 18:05:25 GMT, Barry Margolin
><··············@level3.com> wrote:
>
>>In article <··································@4ax.com>,
>>Doug Tolton  <·······@yahoo.com> wrote:
>>Lisp macros have the full capabilities of Lisp at their disposal.  In
>>particular, you can use MAPCAR or LOOP to iterate over a list.
>
>I believe they said that in the book, but they didn't really cover how
>to take advandage of them for anything but a trivial example.  There
>was no looping or recursion in the examples.

I guess they intended for the student to work it out.

>Should I be building up a list to return for execution?  Are there any

Yes, that's what you should be doing.  For instance, in the LETQ macro,
you'd probably have some code that looks like

(let ((new-init-list
        (mapcar #'(lambda (var-init)
                    `(,(first var-init) ',(second var-init)))
                init-list)))
  ...)

This transforms ((var1 init1) (var2 init2) ...) into ((var1 'init1) (var2
',init2) ...).

>specific gotchas, or is there somewhere that I can read a more
>detailed exposition on the usage of macros?  I would really like to

The main thing to avoid is any destructive operations on the list structure
that's handed to you.  In an interpreter, that will end up modifying the
original function definition.

Also, if you find yourself needing to use EVAL in a macro, you're probably
doing something wrong.  This is a common beginner mistake.  They know that
macro arguments aren't evaluated automatically, so they use EVAL on the
parts that they want to undo this suppression for.  The problem with this
is that the evaluation happens at the wrong time (compile time rather than
run time) and in the wrong environment (global rather than lexical).  You
should be returning new code that will do the right thing when *it* is
evaluated.

>seem some really good examples with a detailed dissection of how the
>code is constructed.  Then again, I want a better tax code system too.

You might try the book "Lisp Style & Design".  I don't have it handy, so I
don't know offhand if it covers this in any depth, but it may.

BTW, don't feel bad.  Lisp macros are very powerful, but they can also be
extremely confusing.  I remember that it took me a few weeks to get the
hang of them.  But eventually you should have that Aha! moment, and from
then on you'll wonder how people get along in all those other languages
that don't have them.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, 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: Doug Tolton
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <ktt2jvso6bpi7dae7619jibem6eavukjnd@4ax.com>
>Yes, that's what you should be doing.  For instance, in the LETQ macro,
>you'd probably have some code that looks like
>
>(let ((new-init-list
>        (mapcar #'(lambda (var-init)
>                    `(,(first var-init) ',(second var-init)))
>                init-list)))
>  ...)
>
>This transforms ((var1 init1) (var2 init2) ...) into ((var1 'init1) (var2
>',init2) ...).

this is exactly the kind of thing I was looking for.  I was really
stuck on the very simple examples they provided.  Using mapcar makes
sense though, I'll play around with it and some more of the examples
tonight when I get home from work.


>You might try the book "Lisp Style & Design".  I don't have it handy, so I
>don't know offhand if it covers this in any depth, but it may.

I'll check this book out.  My Lisp library is starting to grow now,
and there are a few more books I really want to get.
I just got Lisp in Small Pieces, and I've got SICP and How to Design
Programs as well as ANSI Lisp by Paul Graham.

So far I really like the Winston and Horn book the best.  Someone on
this list recommended it a month or two ago, but I don't remember who.
Thanks though, it's been really good so far.

>BTW, don't feel bad.  Lisp macros are very powerful, but they can also be
>extremely confusing.  I remember that it took me a few weeks to get the
>hang of them.  But eventually you should have that Aha! moment, and from
>then on you'll wonder how people get along in all those other languages
>that don't have them.

That's good news, I really want to get them mastered for that reason.
Lisp is by far my favorite language already, and I've only been
playing with it for a few months.  What turned me on to it was Paul
Graham's web site.  He makes some pretty grandiose claims for Lisp,
can anyone comment on how true his claims are?  I'm definitely
intrigued by what I've already seen, but I'm at a point now though
where I want to make a decision on getting a post grad degree.  I am
seriously considering pursuing a Ph.D with the main thrust of my
research being in Lisp.  This is pretty off-topic and if you think I
should make a separate post for this discussion, I'll do so.


Barry thank you very much for your well thought out and helpful
answers.
From: Kalle Olavi Niemitalo
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <87znimzdqo.fsf@Astalo.kon.iki.fi>
Doug Tolton <·······@yahoo.com> writes:

> Should I be building up a list to return for execution?

I'm not sure how to interpret this.  Of course the macro should
expand to a list.

The general shape of LETQ would look like this:

  (defmacro letq (bindings &body body)
    `(let ,(transform-letq-bindings bindings)
       ,@body))

Then write a suitable TRANSFORM-LETQ-BINDINGS function,
or replace the call with inline code.

Side question: Should I have written the lambda list as
((&rest bindings) &body body)?
From: Barry Margolin
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <BafYa.77$Mg5.42@news.level3.com>
In article <··············@Astalo.kon.iki.fi>,
Kalle Olavi Niemitalo  <···@iki.fi> wrote:
>Side question: Should I have written the lambda list as
>((&rest bindings) &body body)?

That would be reasonable -- the system could then automatically perform
syntax checking and reject

(letq some-symbol ...)

because a list is required where SOME-SYMBOL exists.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, 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: Kent M Pitman
Subject: Re: Winstond and Horn Macros
Date: 
Message-ID: <sfwfzkdqygw.fsf@shell01.TheWorld.com>
Barry Margolin <··············@level3.com> writes:

> In article <··································@4ax.com>,
> Doug Tolton  <·······@yahoo.com> wrote:
> >for the most part in Winston and Horn they seem to use very simple
> >translations, and avoid building any type of very complex form.  I
> >could just be missing something simple, but I don't understand how I
> >would take an arbitrary number of variables, and map only value
> >expressions so they aren't evaluated.  Is there something simple I'm
> >missing?  Or is there an entire conceptual idea I'm not getting?
> 
> Lisp macros have the full capabilities of Lisp at their disposal.  In
> particular, you can use MAPCAR or LOOP to iterate over a list.
> 
> >I've seen reference to macroexpand, does this return the expanded form
> >of the macro?
> 
> Yes.  It's used to debug macros.

I use MACROEXPAND-1 to debug macros, not MACROEXPAND.