In article <3d56c36
...@nntphost.cis.strath.ac.uk>, Thomas Stegen CES2000 wrote:
> In my quest for understanding macros a bit better I have a few
> questions.
> Is using a macro the same as returning a form from a function
> and using eval on that form?
Not exactly. If all you are doing is writing macros in the
read-eval-print-loop, then the answer is yes, sort of.
If you write for instance
(setf *foo* 3)
which invokes the SETF macro, then indeed, the evaluation of the macro produces
a form, and that form is evaluated right away as if someone invoked
eval on it.
However, macros may occur in contexts in which their expansion are not
evaluated right away, for instance:
(defun some-function ()
(setf *foo* 3))
Is the macro expansion evaluated now? No, the macro expansion is evaluated
when you call the function. And it's not done in the same way as eval,
because the expansion has access to the lexical environment. Consider:
(let ((lexical-variable 42))
(eval 'lexical-variable))
==> error, lexical-variable not bound
When is the macro expanded? That depends; it may be expanded as late as
the first call to the function.
Lisp is also compiled as well as interpreted language; some-function could be
compiled, which means that the macro could be expanded in the environment of
the compiler.
Perhaps the single best way to understand macros is that they are invoked at
macro-expansion time, to produce a piece of code which is then substituted in
their place, and then in that place subject to the normal evaluation rules as
if it was written there.
Macro-expansion time can happen in a compiler, or the first time a macro form
is evaluated, or as the code is being loaded or read. This multitude is
a consequence of the various situations in which Lisp code can be processed.
> Trivial example to show what I mean:
> (defmacro madd ()
> (+ 5 10))
This macro actually computes the number 15 at expansion time, and
returns that. So the integer 15 is substituted for the macro call.
> (defun dadd ()
> '(+ 5 10))
> Are the following two forms semantically equivalent?
> (madd)
Consequently, the effect of this is the same as just writing the number 15.
> (eval (dadd))
The effect of this is also the same as writing the number 15, if the compiler
can deduce that the (dadd) always returns the list constant '(+ 5 10)
in every possible context. Since it's a top-level expression that is
evaluated in all the situations when the immediately preceding function
definition is evaluated, it's deducible that it calls that function
and not some other. But if you had this in, say, a function body:
(defun some-func ()
(eval (dadd)))
now there is the suspicion that the function dadd can be replaced with
another one, so this actually has to do the evaluation. It cannot
just be replaced by the constant 15. Adding a (declaim (inline dadd))
declaration to tell the compiler that the function may be inlined
would make that deduction permissible.
Now suppose you have these
(defmacro madd () '(+ a b))
(defun dadd () '(+ a b))
And suppose that at the top level you have
(madd)
(eval (dadd))
These do the same thing, namely evaluate (+ a b) but this is only
the same only because you are at the top level. Suppose the
evaluation is nested in a form:
(let ((a 1) (b 2))
(madd))
This is the same as
(let ((a 1) (b 2))
(+ a b))
which of course produces 3.
But
(defvar a 0)
(defvar b 0)
(let ((a 1) (b 2))
(eval (dadd)))
produces 0. The lexical environment is not available in the eval,
so it simply refers to the dynamic bindings of a and b, established
in the defvar forms.
So that is a huge difference, which makes it incorrect to say that
macro expansions are subject to eval.
> And one more question. When is a macro expanded?
I think I answered that; it can happen in a number of contexts. Most of the
time it doesn't matter; though a macro ought to be written so that it expands
properly in all these various situations, most of the time this doesn't pose
any challenge.
Sometimes macros need to be broken down into functions, because they
are too complex to write as one big function. They also may refer to
variables or constants. Then the macro expansion time starts to
matter, because if a Lisp compiler expands the macro in its own bowels,
the functions are not available by default. Suppose you are compiling
the following:
(defun cool-expander (...) ...)
(defmacro cool-macro (args) ... (cool-expander ...))
The compiler might do something like this: it will read cool-expander,
compile it and deposit the results into the object file, but it won't
actually evaluate the defun to instantiate the function! That would just waste
space and time in the compiler. The compiler's job is to produce translate the
function definitions, not to carry them out, right? Most of the time,
it doesn't need the definitions, only the target program needs them.
And so then the macro refers to an undefined function; when an expansion is
attempted, it will fail. Because the macro does need the function at compile
time.
To make the compiler define the cool-expander function to itself, so that your
macro can call it during expansion, you have to surround the defun with this:
(eval-when (:compile-toplevel :load-toplevel :execute)
(defun cool-expander (...) ...))
The arguments to eval are the ``times''; they refer situations in which the
code may be processed, and specify that you want want the enclosed forms to be
evaluated when it is processed in these situations (and no others).