Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

newbie Q: defmacro

20 views
Skip to first unread message

abu...@ieee.org

unread,
Oct 24, 2006, 10:06:52 PM10/24/06
to
Hi:

I have the following:

(defmacro compile-machine (nnn)
`(progn ,(mapcar #'compile-node nnn)))

When I call:

(macroexpand '(compile-machine *nodes*))

I get the message:

*** - MAPCAR: A proper list must not end with *NODES*

Which is the same message I get if I call:

(mapcar #'compile-node '*nodes*)

If I replace nnn with *nodes* in my defmacro then it works. My question
is why is nnn not being evaluated all the way down to the list behind
*nodes*? And what should I write instead.

Thank you.

Adam

Bill Atkins

unread,
Oct 25, 2006, 12:02:43 AM10/25/06
to
abu...@ieee.org writes:

What were you expecting? You're passing in the symbol *NODES* to
MAPCAR. Remember that the macro COMPILE-MACHINE is run at
compile-time, so it receives the symbol *NODES*, and not its value.
I'm not sure how you should rewrite this, because I'm not sure what
you want COMPILE-MACHINE to do.

If you give a little more information about what you're trying to do
and how these macros would be used, someone can probably suggest
something. It might be the case that you don't need the macros at
all.

HTH,
Bill

Jack Unrue

unread,
Oct 25, 2006, 12:05:27 AM10/25/06
to

When you call a macro, the arguments are not evaluated like when you call
a function. This means that your macro expansion gets the symbol *NODES*
when the NNN parameter is evaluated inside the body of the macro. Hence
the error message in this case, because MAPCAR needs a list there, not
a symbol.

Also, it's critical to remember that macro expansion time is distinct
from runtime. If you want COMPILE-MACHINE to operate on a list of data,
that list cannot be computed at runtime because runtime is too late.
The solution really depends on where your *NODES* data is coming from;
it's hard to recommend EVAL-WHEN without knowing more about your exact
situation.

Finally, I suspect that you wanted ,@ instead of , so that the
result list from MAPCAR is spliced into the PROGN form instead
of being inserted as-is.

Note that passing a symbol instead of a value is not always wrong, sometimes
you want the macro caller to supply a variable name, like when you are writing
a WITH-FOO type of macro where FOO is something instantiated for use within
the body of the macro.

--
Jack Unrue

abu...@ieee.org

unread,
Oct 25, 2006, 12:39:27 AM10/25/06
to

Jack Unrue wrote:
> On 24 Oct 2006 19:06:52 -0700, abu...@ieee.org wrote:
> >
> > Hi:
> >
> > I have the following:
> >
> > (defmacro compile-machine (nnn)
> > `(progn ,(mapcar #'compile-node nnn)))
> >
> > When I call:
> >
> > (macroexpand '(compile-machine *nodes*))
> >
> > I get the message:
> >
> > *** - MAPCAR: A proper list must not end with *NODES*
> >
> > Which is the same message I get if I call:
> >
> > (mapcar #'compile-node '*nodes*)
> >
> > If I replace nnn with *nodes* in my defmacro then it works. My question
> > is why is nnn not being evaluated all the way down to the list behind
> > *nodes*? And what should I write instead.
>
> When you call a macro, the arguments are not evaluated like when you call
> a function. This means that your macro expansion gets the symbol *NODES*
> when the NNN parameter is evaluated inside the body of the macro. Hence
> the error message in this case, because MAPCAR needs a list there, not
> a symbol.

I was expecting NNN to evaluate to *NODES* which would in turn evaluate
to my list. I was not aware that function arguments are only evaluated
once. I thought they were evaluated until they boiled down to
something, but I guess if that were true every argument would be either
T or NIL.

> Also, it's critical to remember that macro expansion time is distinct
> from runtime. If you want COMPILE-MACHINE to operate on a list of data,
> that list cannot be computed at runtime because runtime is too late.

I'm using the clisp interpreter to parse a file, where the file
contains a solution to exercise 14.11 in Touretzky's book, "Common
Lisp: A Gentle Introduction to Symbolic Computation". I'm not a student
looking for answers to homework, I'm just trying to learn lisp and
picked this problem out of that book as an interesting place to start.

> Finally, I suspect that you wanted ,@ instead of , so that the
> result list from MAPCAR is spliced into the PROGN form instead
> of being inserted as-is.

Yes, the solution in the text uses ,@, but I'm not so worried about
that detail. For now, I think list splicing is not that complicated an
issue. I'm more interested in the parameter evaluation part.

> Note that passing a symbol instead of a value is not always wrong, sometimes
> you want the macro caller to supply a variable name, like when you are writing
> a WITH-FOO type of macro where FOO is something instantiated for use within
> the body of the macro.

Thank you for your time and detailed response.

Adam

Bill Atkins

unread,
Oct 25, 2006, 12:50:38 AM10/25/06
to
abu...@ieee.org writes:

> I was expecting NNN to evaluate to *NODES* which would in turn evaluate
> to my list. I was not aware that function arguments are only evaluated
> once. I thought they were evaluated until they boiled down to
> something, but I guess if that were true every argument would be either
> T or NIL.

The problem doesn't have to do with when function arguments are
evaluated; the thing to keep in mind is that a macro is passed
unevaluated code and that macros are called at compile-time. They can
only transform the code they are given into new code; they shouldn't
be evaluating anything.

As an aside, arguments are evaluated recursively until a QUOTE form is
reached, which signals to the evaluator that the next s-expression
should be taken literally. Function arguments are indeed evaluated
once - Lisp evaluates each argument from left to right and then passes
the result into the function you're calling. Since you're quoting the
MACROEXPAND call, that literal list is what will be expanded.

>> Also, it's critical to remember that macro expansion time is distinct
>> from runtime. If you want COMPILE-MACHINE to operate on a list of data,
>> that list cannot be computed at runtime because runtime is too late.
>
> I'm using the clisp interpreter to parse a file, where the file
> contains a solution to exercise 14.11 in Touretzky's book, "Common
> Lisp: A Gentle Introduction to Symbolic Computation". I'm not a student
> looking for answers to homework, I'm just trying to learn lisp and
> picked this problem out of that book as an interesting place to start.
>
>> Finally, I suspect that you wanted ,@ instead of , so that the
>> result list from MAPCAR is spliced into the PROGN form instead
>> of being inserted as-is.
>
> Yes, the solution in the text uses ,@, but I'm not so worried about
> that detail. For now, I think list splicing is not that complicated an
> issue. I'm more interested in the parameter evaluation part.

...but you should be interested in it, because had you used
(macroexpand `(compile-node ,@*nodes*)), you would have gotten the
result you wanted, and some additional insight into how macros work.

Here is the best explanation of macros I know of:
http://www.gigamonkeys.com/book/macros-defining-your-own.html .

HTH.

Ken Tilton

unread,
Oct 25, 2006, 1:09:59 AM10/25/06
to

Bill Atkins wrote:
> abu...@ieee.org writes:
>
>
>>Hi:
>>
>>I have the following:
>>
>> (defmacro compile-machine (nnn)
>> `(progn ,(mapcar #'compile-node nnn)))
>>
>>When I call:
>>
>> (macroexpand '(compile-machine *nodes*))
>>
>>I get the message:
>>
>> *** - MAPCAR: A proper list must not end with *NODES*
>>
>>Which is the same message I get if I call:
>>
>> (mapcar #'compile-node '*nodes*)
>>
>>If I replace nnn with *nodes* in my defmacro then it works. My question
>>is why is nnn not being evaluated all the way down to the list behind
>>*nodes*? And what should I write instead.
>>
>>Thank you.
>>
>>Adam
>
>
> What were you expecting?

Why are you asking? I did not find it very hard to figure out what the
OP was expecting.

:)

kt

--
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
-- Smiling husband to scowling wife, New Yorker cartoon

abu...@ieee.org

unread,
Oct 25, 2006, 1:19:56 AM10/25/06
to
Bill Atkins wrote:
> abu...@ieee.org writes:
>
> > I was expecting NNN to evaluate to *NODES* which would in turn evaluate
> > to my list. I was not aware that function arguments are only evaluated
> > once. I thought they were evaluated until they boiled down to
> > something, but I guess if that were true every argument would be either
> > T or NIL.
>
> The problem doesn't have to do with when function arguments are
> evaluated; the thing to keep in mind is that a macro is passed
> unevaluated code and that macros are called at compile-time. They can
> only transform the code they are given into new code; they shouldn't
> be evaluating anything.

Just for convenience:


(defmacro compile-machine (nnn) `(progn ,(mapcar #'compile-node nnn)))

(macroexpand '(compile-machine *nodes*))

I was expecting mapcar to be called with the list behind *nodes* rather
than with the symbol *nodes*. I thought that because I don't see where
*nodes* is quoted.

> As an aside, arguments are evaluated recursively until a QUOTE form is
> reached, which signals to the evaluator that the next s-expression
> should be taken literally.

Ok. That helps clarify things a bit. Thanks.

> Function arguments are indeed evaluated
> once - Lisp evaluates each argument from left to right and then passes
> the result into the function you're calling. Since you're quoting the
> MACROEXPAND call, that literal list is what will be expanded.

Yes, I see why the macroexpand argument must be quoted. And when you
say, "Function arguments are indeed evaluated once", you mean once
until the evaluate to a quoted s-expression even though that may
require a few steps?

[some stuff about splicing deleted]

> > Yes, the solution in the text uses ,@, but I'm not so worried about
> > that detail. For now, I think list splicing is not that complicated an
> > issue. I'm more interested in the parameter evaluation part.
>
> ...but you should be interested in it, because had you used
> (macroexpand `(compile-node ,@*nodes*)), you would have gotten the
> result you wanted, and some additional insight into how macros work.

Actually, clisp gives me an error if I try that. It says, "READ: comma
is illegal outside of backquote".

> Here is the best explanation of macros I know of:
> http://www.gigamonkeys.com/book/macros-defining-your-own.html .

I've read that, but it was several months ago. I'll go read it again.
Thanks.

So to summarise, I'm still unclear about why mapcar was not called the
way I expected.

Adam

Ken Tilton

unread,
Oct 25, 2006, 1:34:21 AM10/25/06
to

We call those "functions". :)

We only need a macro if we want to write code with a function (the
macro), using other code as its only input (the various macro
invocations somewhere out there in the source). And of course that is
the only possible input since the macro function is not around at
runtime. The code (tree of symbols) you write with the macro will
include evaluating references to runtime variables. That tree of symbols
will get compiled and some time later run. Your code will evaluate
variables and, well, get their values.

Remember that when writing the (macro) code for the function that uses
invoking source to tailor the expanded code the compiler will make into
an executable for the computer to run.

??

The idea is to write a macro whenever you see an opportunity to make
life easier for the person who must repeatedly author some pattern of
code, where the pattern lends itself to automatic transformation from
some simpler set of terms (the macro invocation) to significantly more
complex set of terms (the expansion).

I may be repeating myself.

abu...@ieee.org

unread,
Oct 25, 2006, 1:43:19 AM10/25/06
to
One key point here is that I'm doing all this in an interpreter, so
*NODES* does have a data structure behind it. Thanks.

Adam

Bill Atkins

unread,
Oct 25, 2006, 1:44:22 AM10/25/06
to
abu...@ieee.org writes:

> Bill Atkins wrote:
>> abu...@ieee.org writes:
>>
>> > I was expecting NNN to evaluate to *NODES* which would in turn evaluate
>> > to my list. I was not aware that function arguments are only evaluated
>> > once. I thought they were evaluated until they boiled down to
>> > something, but I guess if that were true every argument would be either
>> > T or NIL.
>>
>> The problem doesn't have to do with when function arguments are
>> evaluated; the thing to keep in mind is that a macro is passed
>> unevaluated code and that macros are called at compile-time. They can
>> only transform the code they are given into new code; they shouldn't
>> be evaluating anything.
>
> Just for convenience:
> (defmacro compile-machine (nnn) `(progn ,(mapcar #'compile-node nnn)))
> (macroexpand '(compile-machine *nodes*))
>
> I was expecting mapcar to be called with the list behind *nodes* rather
> than with the symbol *nodes*. I thought that because I don't see where
> *nodes* is quoted.

'(foo bar) means that nothing inside that list will be evaluated.
Instead it evaluates to a list with the elements FOO and BAR, (almost)
exactly as if you'd used (list foo bar). Because you're quoting what
you pass to macroexpand, nothing inside it will be evaluated. This is
why '(+ 4 5) evaluates to (+ 4 5) and not 9.

>> As an aside, arguments are evaluated recursively until a QUOTE form is
>> reached, which signals to the evaluator that the next s-expression
>> should be taken literally.
>
> Ok. That helps clarify things a bit. Thanks.
>
>> Function arguments are indeed evaluated
>> once - Lisp evaluates each argument from left to right and then passes
>> the result into the function you're calling. Since you're quoting the
>> MACROEXPAND call, that literal list is what will be expanded.
>
> Yes, I see why the macroexpand argument must be quoted. And when you
> say, "Function arguments are indeed evaluated once", you mean once
> until the evaluate to a quoted s-expression even though that may
> require a few steps?

Here are the basic rules of Lisp evaluation. Given an s-expression exp:

1. If exp is a list of the form (function [arg1 ... argn]),
recursively evaluate each argument and pass it to function. The
value function returns is the value of this expression.

2. If exp is a list, but the first element is a macro, call that
macro function with the unevaluated arguments (e.g. (defun foo ()
'x) passes the defun macro the symbol FOO, the empty list, and
the list (QUOTE FOO).).

3. If exp is a special form....do something special. In particular,
if exp is of the form (quote foo) (which is the same as 'foo),
simply return whatever was passed to quote and do not evaluate or
descend into QUOTE's argument.

4. If exp is a symbol, treat exp as a variable name and return the
value of the variable with that name.

5. If exp is anything else, then the value of the expression is exp
itself (e.g. (eval 4) -> 4, (eval "foo") => "foo", (eval 'foo) =>
"foo".

So, following these rules, your snippet of code passes the literal
list (compile-nodes *nodes*), i.e. a list of two symbols, to
COMPILE-NODE. The evaluator never touches these values unless
COMPILE-MACHINE happens to use them in its output.

> [some stuff about splicing deleted]
>
>> > Yes, the solution in the text uses ,@, but I'm not so worried about
>> > that detail. For now, I think list splicing is not that complicated an
>> > issue. I'm more interested in the parameter evaluation part.
>>
>> ...but you should be interested in it, because had you used
>> (macroexpand `(compile-node ,@*nodes*)), you would have gotten the
>> result you wanted, and some additional insight into how macros work.
>
> Actually, clisp gives me an error if I try that. It says, "READ: comma
> is illegal outside of backquote".

Are you sure it's really in a backquote, i.e. ` and not ' ?

>> Here is the best explanation of macros I know of:
>> http://www.gigamonkeys.com/book/macros-defining-your-own.html .
>
> I've read that, but it was several months ago. I'll go read it again.
> Thanks.
>
> So to summarise, I'm still unclear about why mapcar was not called the
> way I expected.

So let's walk through it.

(macroexpand '(compile-machine *nodes*))

The Lisp evaluator reaches the quote and doesn't evaluate the list.
It passes a list of two symbols to the function MACROEXPAND, which
figures out that COMPILE-NODE is a macro. So MACROEXPAND finds the
expander function for COMPILE-NODE (the expander function is what you
define when you use a DEFMACRO form). It calls the expander with one
argument, the symbol *NODES* (it was never evaluated because it was in
a QUOTE form). So COMPILE-MACHINE is

(defmacro compile-machine (nnn)
`(progn ,(mapcar #'compile-node nnn)))

Remember that the backquote is just syntactic sugar for:

(list 'progn (mapcar #'compile-mode nnn))

so the evaluator will actually see that expression. Following the
regular rules of evaluation, MAPCAR is called with two arguments: the
function COMPILE-NODE and the value of NNN, which is '*NODES*. MAPCAR
notices that its second argument is a symbol and not a list, so it
raises an error.

Bill Atkins

unread,
Oct 25, 2006, 1:45:06 AM10/25/06
to
abu...@ieee.org writes:

Doesn't matter. The macro only gets *CODE*, not the result of
evaluating that code.

Bill Atkins

unread,
Oct 25, 2006, 1:55:53 AM10/25/06
to
Bill Atkins <atk...@rpi.edu> writes:

> exactly as if you'd used (list foo bar). Because you're quoting what

Should be (list 'foo 'bar)

> the list (QUOTE FOO).).

Should be (QUOTE X).

> figures out that COMPILE-NODE is a macro. So MACROEXPAND finds the

Should be COMPILE-MACHINE.

> expander function for COMPILE-NODE (the expander function is what you

Ditto.

Sorry (it's late). I think Ken is right: you need to figure out if
you really want a macro here.

abu...@ieee.org

unread,
Oct 25, 2006, 2:16:29 AM10/25/06
to

Bill Atkins wrote:
> > So to summarise, I'm still unclear about why mapcar was not called the
> > way I expected.
>
> So let's walk through it.
>
> (macroexpand '(compile-machine *nodes*))
>
> The Lisp evaluator reaches the quote and doesn't evaluate the list.
> It passes a list of two symbols to the function MACROEXPAND, which
> figures out that COMPILE-NODE is a macro. So MACROEXPAND finds the
> expander function for COMPILE-NODE (the expander function is what you
> define when you use a DEFMACRO form). It calls the expander with one
> argument, the symbol *NODES* (it was never evaluated because it was in
> a QUOTE form). So COMPILE-MACHINE is
>
> (defmacro compile-machine (nnn)
> `(progn ,(mapcar #'compile-node nnn)))
>
> Remember that the backquote is just syntactic sugar for:
>
> (list 'progn (mapcar #'compile-mode nnn))
>
> so the evaluator will actually see that expression. Following the
> regular rules of evaluation, MAPCAR is called with two arguments: the
> function COMPILE-NODE and the value of NNN, which is '*NODES*. MAPCAR
> notices that its second argument is a symbol and not a list, so it
> raises an error.

Now I feel you are close to answering my question. :) *Why* is *nodes*
a symbol and not a list?

If I write (mapcar #'compile-node *nodes*) at the prompt then I get
the generated code I'm expecting, i.e. *nodes* is a list, whereas
(compile-machine *nodes*) gives me the "proper list" error. I'm
confused because the compile-machine macro is making the same mapcar
call that I am (I thought). However, the fact seems to be that *nodes*
is quoted in the defmacro case. I find that mysterious.

Adam

Barry Margolin

unread,
Oct 25, 2006, 2:39:21 AM10/25/06
to
In article <1161756989.1...@m73g2000cwd.googlegroups.com>,

abu...@ieee.org wrote:
> Now I feel you are close to answering my question. :) *Why* is *nodes*
> a symbol and not a list?
>
> If I write (mapcar #'compile-node *nodes*) at the prompt then I get
> the generated code I'm expecting, i.e. *nodes* is a list, whereas
> (compile-machine *nodes*) gives me the "proper list" error. I'm
> confused because the compile-machine macro is making the same mapcar
> call that I am (I thought). However, the fact seems to be that *nodes*
> is quoted in the defmacro case. I find that mysterious.

MAPCAR is an ordinary function, so the Lisp evaluator automatically
evaluates all the arguments to the function before calling the function.
So *NODES* is evaluated, resulting in the list that is its value. This
list is passed to MAPCAR.

But your COMPILE-MACHINE is not a function, it's a macro. Macro
arguments are *not* evaluated. The macro receives the literal objects

that were in the macro invocation expression. So when you write:

(defmacro compile-machine (nnn)
`(progn ,(mapcar #'compile-node nnn)))

(macroexpand '(compile-machine *nodes*))

the value of NNN is the symbol *NODES* -- not the list that is the value
of that variable. And when the expansion function runs, it's comparable
to you typing:

(setq nnn '*nodes*)
(mapcar #'compile-node nnn)

Try that -- you'll see that you get the same error that you originally
got.

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***

Bill Atkins

unread,
Oct 25, 2006, 2:36:26 AM10/25/06
to
abu...@ieee.org writes:

Because everything passed to a defmacro is literal code. It isn't
evaluated. I think this may have been mentioned once or twice ;-).

Your (mapcar ...) call follows the evaluation rules for a function;
(compile-machine ...) follows the evaluation rules for a macro.
Macros are passed in unevaluated code.

Pascal Bourguignon

unread,
Oct 25, 2006, 6:49:20 AM10/25/06
to
abu...@ieee.org writes:

> Hi:
>
> I have the following:
>
> (defmacro compile-machine (nnn)
> `(progn ,(mapcar #'compile-node nnn)))
>
> When I call:
>
> (macroexpand '(compile-machine *nodes*))
>
> I get the message:
>
> *** - MAPCAR: A proper list must not end with *NODES*
>
> Which is the same message I get if I call:
>
> (mapcar #'compile-node '*nodes*)
>
> If I replace nnn with *nodes* in my defmacro then it works.


The only differences between a macro and a function are:

1- the macro is called by the compiler at macroexpansion time.
(while the function is called by the program at run-time).

2- the arguments of the macros are not evaluated
(while the arguments of the function are evaluated
before the function is called).

3- the result of the macro is evaluated at run-time
(while the results of the function are just taken as returned).


The point 2 means that a macro is just a gimmick to avoid quote.

(defmacro mlistq (a) `(list ,a))

(macroexpand '(mlistq (+ 1 2)))
--> (LIST (+ 1 2)) ;
T

(defun flistq (a) `(list ,a))

(flistq '(+ 1 2))
--> (LIST (+ 1 2))


To illustrate the point 3 we can use EVAL, but since the code
resulting from the macro is used at compilation time, it can access
the lexical environment (which is not possible with EVAL):

(mlistq (+ 1 2))
--> (3)

(eval (flistq '(+ 1 2)))
--> (3)


So broadly, macro <=> eval+function+quote

So I would advise to write your macros as:

(defmacro m (args...)
(mf args...))

(defun mf (args...)
...)


And debug the function mf instead, not forgetting to quote all the
arguments, like in the case of flistq:

(defun flistq (a)
(print a) ; macroexpansion time.
`(list ,a)) ; result to be evaluated at run-time.

(flistq '(+ 1 2))
prints: (+ 1 2)
returns: (LIST (+ 1 2))

(flistq '*my-list*)
prints: *MY-LIST*
returns: (LIST *MY-LIST*)

(defmacro mlistq (a) (flistq a))

(mlistq (+ 1 2))
prints at macro expansion time: (+ 1 2)
returns at run-time: (3)

(defvar *my-list* '(* 3 4))
(mlistq '*my-list*)
prints at macro expansion time: *MY-LIST*
returns at run-time: ((* 3 4))


> My question
> is why is nnn not being evaluated all the way down to the list behind
> *nodes*?

Because it is not. That's the point of the macros, not to evaluate
its arguments. If you want the argument to be evaluated, don't write
a macro, write a function.


> And what should I write instead.

I would write a compiler using only functions. That is, design it to
be used at run-time.

When it's done and it works, if you need to call this compiler at
macroexpansion time, you can write a macro to do so.

(defmacro stuff (arg)
(compile-stuff arg))

So you can write

(stuff (foo bar))

instead of

(eval (compile-stuff '(foo bar)))

[which wouldn't even work if (foo bar) was to be resolved in the lexical scope].

--
__Pascal Bourguignon__ http://www.informatimago.com/

READ THIS BEFORE OPENING PACKAGE: According to certain suggested
versions of the Grand Unified Theory, the primary particles
constituting this product may decay to nothingness within the next
four hundred million years.

abu...@ieee.org

unread,
Oct 25, 2006, 8:20:03 AM10/25/06
to
Hi:

Points to Pascal Bourguignon for solving this riddle for me. The
following was especially helpful:

(defmacro mlistq (a) `(list ,a))

(defun flistq (a) `(list ,a))

(macroexpand '(mlistq (+ 1 2)))
--> (LIST (+ 1 2)) ;
T

(flistq '(+ 1 2))
--> (LIST (+ 1 2))

I suspected this had to be the case, but I could not find any
confirmation of it. So, for other newbies: defmacro quotes the values
of its arguments before doing the variable substitutions in the macro
body.

Thank you all for the detailed responses.

Adam

Ken Tilton

unread,
Oct 25, 2006, 10:09:46 AM10/25/06
to

abu...@ieee.org wrote:
> One key point here is that I'm doing all this in an interpreter, so
> *NODES* does have a data structure behind it.

When I wrote "That tree of symbols will get compiled and some time later
run", I did not specify whether "some time" was three years or three
milliseconds; the sequence I described happens no matter how fast it
happens and/or how short the intervals between the steps. The
interpreter may even compile on the fly (MCL does this), in which case
the sequence is exactly as I described, or it may be a separate module
(as with ACL) in which case I imagine the interpreter is /still/ hewing
to the same sequence, for all intents and purposes.

I saw your explanation to other noobs. Made no sense to me. Instead of
searching for a pithy way of synopsizing what is going, it actually
would be easier simply to learn what is going on. In full. The shortcut
thinking of your synopsis is too lossy, and macro-writing requires
precise understanding of what is going on.

abu...@ieee.org

unread,
Oct 25, 2006, 11:03:33 AM10/25/06
to
Ken Tilton wrote:
> abu...@ieee.org wrote:

[some stuff about macro expansion deleted]

> I saw your explanation to other noobs. Made no sense to me. Instead of
> searching for a pithy way of synopsizing what is going, it actually
> would be easier simply to learn what is going on. In full. The shortcut
> thinking of your synopsis is too lossy, and macro-writing requires
> precise understanding of what is going on.

You remind me of my early experiences learning French. It was often the
case that students who thought they were speaking French could easily
understand eachother while the francophones around them found them
difficult to understand. This was caused by the students having access
to English grammar and phonetics when interpreting the "French"
utterances. For example, beginners have no trouble with, "le brun
chaisses" even though the gender of the article is wrong, the adjective
is in the wrong place, and so on.

All that to say, I'm sorry that it seems I still have not entirely
figured out defmacro's treatment of arguments. I thought I had, and I
thought I was putting it in terms other newbies could understand.
Thanks for pointing out that I'm still missing something.

Adam

Bill Atkins

unread,
Oct 25, 2006, 11:57:33 AM10/25/06
to
abu...@ieee.org writes:

> confirmation of it. So, for other newbies: defmacro quotes the values
> of its arguments before doing the variable substitutions in the macro
> body.

Well, that's *the* reason to use a macro, after all...

Bill Atkins

unread,
Oct 25, 2006, 12:01:14 PM10/25/06
to
Bill Atkins <atk...@rpi.edu> writes:

Hmm, more precisely: "the reason to use a macro is that its arguments
are not evaluted (that is, quoted) before the call."

abu...@ieee.org

unread,
Oct 25, 2006, 12:08:46 PM10/25/06
to

*My* point is that they are not evaluated *after* the call either.

Adam

Pascal Bourguignon

unread,
Oct 25, 2006, 2:52:39 PM10/25/06
to
abu...@ieee.org writes:

Well, this depends.
Because the result of the macro WILL be evaluated at run-time.

So if you use the arguments of the macro to build the resulting form,
they _may_ be evaluated eventually.

In my opinion, it's not possible to understand CLHS (and programming
in general), if you don't write programs yourself.
Programming is an experimental science! ;-) So:

[19]> (defmacro example (never-evaluated evaluated-at-mext evaluated-at-rt)
;; note how this code will be executed at macro expansion time
(format t "~&Now is macro expansion time.~%")
(format t "Won't evaluate: ~S~%~
Evaluated now: ~S --> ~S~%~
Will evaluate at run-time: ~S~%"
never-evaluated
evaluated-at-mext
(eval evaluated-at-mext) ; Danger Robinson!
evaluated-at-rt)
;; and this one too, but it returns a form that will be executed
;; only at run-time:
`(progn
(format t "~&Now is run time.~%")
(format t "Won't evaluate: ~S~%~
Evaluated now: ~S --> ~S~%"
',never-evaluated
',evaluated-at-rt ,evaluated-at-rt)))

EXAMPLE
[20]> (macroexpand '(example (/ 1 0) (/ 1 2) (/ 1 3)))
Now is macro expansion time.
Won't evaluate: (/ 1 0)
Evaluated now: (/ 1 2) --> 1/2
Will evaluate at run-time: (/ 1 3)
(PROGN (FORMAT T "~&Now is run time.~%")
(FORMAT T
"Won't evaluate: ~S~%~
Evaluated now: ~S --> ~S~%"
'(/ 1 0) '(/ 1 3) (/ 1 3))) ;
T
[21]> (defun f () (example (/ 1 0) (/ 1 2) (/ 1 3)))
Now is macro expansion time.
Won't evaluate: (/ 1 0)
Evaluated now: (/ 1 2) --> 1/2
Will evaluate at run-time: (/ 1 3)
F
[22]> (f)
Now is run time.
Won't evaluate: (/ 1 0)
Evaluated now: (/ 1 3) --> 1/3
NIL


But you must be careful with this _evaluation_ at macro expansion time:

[23]> (defparameter *option-for-example* (/ 1 5))
*OPTION-FOR-EXAMPLE*
[24]> (example not-evaluated *option-for-example* (/ 1 6))
Now is macro expansion time.
Won't evaluate: NOT-EVALUATED
Evaluated now: *OPTION-FOR-EXAMPLE* --> 1/5
Will evaluate at run-time: (/ 1 6)
Now is run time.
Won't evaluate: NOT-EVALUATED
Evaluated now: (/ 1 6) --> 1/6
NIL
[25]> (let ((arg-for-example (/ 1 7)))
(example not-evaluated arg-for-example (/ 1 8)))
Now is macro expansion time.

*** - EVAL: variable ARG-FOR-EXAMPLE has no value

For some kind of arguments, for example, macro forms, you can macro
expand then at macro expansion time, but for this you need to use the
environment argument of the macros and macroexpand. In CL, EVAL
doesn't take such en environment argument, so it cannot access the
lexical environment (which will be know only at run-time!). But it's
rather rare to have to expand macros inside other macros; usually we
just return a form containing macro forms, and let the compiler do the
needed macro expansions.

--
__Pascal Bourguignon__ http://www.informatimago.com/

CONSUMER NOTICE: Because of the "uncertainty principle," it is
impossible for the consumer to simultaneously know both the precise
location and velocity of this product.

0 new messages