0

Have read that macro provide a way to perform transformations before the code is actually evaluated. When the macro is called, its arguments are passed to the macro as unevaluated forms. The macro then generates objects which are substituted and then evaluated in place of macro arguments.

Does this mean that macros are never mean to return a result as functions do ? And that the last expression in the body of the macro is never returned ? That thusly, one should not try to return anything as the last expression ?

The Lisp interpreter proceeds to evaluate the expansion as soon as it comes back from the macro. But, what does it mean that the value returned by the macro body is an alternate Lisp expression (expansion) ?.

2 Answers 2

3

A macro is a function that returns code. The code returned by the macro is executed instead of the macro invocation. Suppose we have the following macro:

(defmacro do-the-thing (foo bar)
  `(+ ,(third bar) ,(second foo)))

If I evaluate the expression (do-the-thing (* 3 5) (* 5 7)). The expression '(* 3 5) will be assigned to foo, and '(* 5 7) to bar. The third element of bar and the second element of foo will be substituted into a list, and the macro will return '(+ 7 3) to be evaluated.

Strictly speaking, code is executed in multiple steps. First, all of the macros are expanded. This is a recursive process, as it is not uncommon for a macro to emit code that itself uses macros. All of the code returned by the macros is substituted into the place of the macro calls, so at the end of this step there are no more macro calls anywhere in the code.

Only then is the resulting code evaluated.

These two steps might happen in quick succession, for example if you type some code into the *scratch* buffer and then hit C-j. Or they might be separated by a long time, for example if you byte–compile a file. The file is loaded, all of the macros are expanded, then the byte compiler does it’s thing, and the result is written to a file on disk. Only later is that file loaded and the code within it run.

You can see macro expansion in action by calling macroexpand or macroexpand-1, which expand macros and then return the code instead of letting it be evaluated:

(macroexpand-1 '(do-the-thing (* 3 5) (* 5 7))
(+ 7 3)

You should read chapter 14 of the Emacs Lisp manual which goes into detail about all of this.

9
  • So that is the return, the evaluation of the constructed code (+ 7 3). So it is last expression and is returned after evaluation. In this sense, the macro behaves just like a function because calling (do-the-thing (* 3 5) (* 5 7) gives 10 as the macro return. Just as might happen with a function (dodo 7 3).
    – Dilna
    Aug 5, 2023 at 16:37
  • This macro is not an amazing example, but notice that (second bar) is able to retrieve the 7 because the expression had not yet been evaluated. If do-the-thing had been a function instead, then the arguments would have been evaluated first and bar would have been 35. Calling second on that would have generated an error. Then, notice that the macro returns not 10 but the code '(+ 7 3). This is a list, just as much as if I had written (list '+ 7 3). Once the macro returns this list, the evaluator inserts it back into the code where it will eventually be evaluated.
    – db48x
    Aug 5, 2023 at 16:50
  • If it was a function bar would have been 35 - Agreed. You say the macro returns unevaluated code as '(+ 7 3). And macroexpand evaluates the unevaluated code output. Does this mean that the interpreter evaluates the code expression after the code expression is returned by a macro ?
    – Dilna
    Aug 5, 2023 at 17:23
  • macroexpand does not evaluate the return value of the macro. It just returns it so that it can be printed out. If you had evaluated it instead, the evaluator would have evaluated it and returned the 10 to you.
    – db48x
    Aug 5, 2023 at 17:38
  • 1
    Please remember that comments are not for conversation, but only for clarification of the question or answer provided. Add-on questions should instead become new questions.
    – Trevoke
    Aug 5, 2023 at 20:57
2

Since there's a lot in your comments, and comments can be deleted and aren't searchable, I'll add this info as an answer. As @db48x said, the macro call is expanded to produce some code, and that code is then evaluated.

Macro expansion is pure reduction, just like what pure functional programming does. The macro arguments are not evaluated, to start with, and some or all of them might never be evaluated during the macro call - they might even be ignored altogether.

Macro expansion need not really expand anything. What it does, using Lisp code, is produce some Lisp code.

After macro expansion, as the second step of evaluating a macro call, the code produced by the first step (macro expansion) is evaluated, and the result of that evaluation is returned.

In sum, Lisp sees a macro call, and ends up evaluating some code and returning its value. What code does it evaluate? The code generated by the macro definition - during the step that's called macro "expansion".

The macro definition, i.e., the code in the macro that generates code, doesn't evaluate that code. The Lisp interpreter sees a macro call, and to evaluate/interpret it, it uses the macro's code to perform macro expansion, and then the interpreter evaluates the result of that expansion.

Typically, the code in the macro-defining body that generates the code to evaluate does something with one or more of the arguments passed in the call. Typically, the arguments determine what code gets generated, in some way (e.g. condition tests).

The macro code that generates the code to be evaluated can, but it doesn't have to, evaluate one or more of the arguments.

Generally speaking, macro code doesn't perform side effects. If you're writing macro code that does that, then you're likely doing the wrong thing.

The only purpose of the macro code is to create the Lisp code that will be evaluated - nothing more. To do that, it can do anything it needs/wants to do, using anything Lisp provides.

2
  • In summary, a macro produces lisp code. But when saying that the code will be evaluated, it does not mean that the macro evaluates it. It will only be evaluated in some context that the interpreter determines to evaluate the code.
    – Dilna
    Aug 5, 2023 at 20:59
  • Please reread what I wrote. The macro definition, the code in the macro that generates code, doesn't evaluate that code. The Lisp interpreter sees a macro call, and to evaluate/interpret it, it uses the macro code to perform macro expansion, and then it evaluates the result of that expansion.
    – Drew
    Aug 5, 2023 at 21:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.