2
votes

I am trying to use macro with two forms in LISP, which evaluates both forms but always return the result of form 2. Below is the code that I am using -

(defmacro testmac (x body) (prog2 x body))

When executing the macro with following forms, It works correctly and always return 5 which is the second form.

(testmac (- 10 6) (/ 10 2))

However when I try to execute macro with following forms, its return error.

(testmac (print a) (print b)) 

Below is the error I get -

debugger invoked on a UNBOUND-VARIABLE: The variable B is unbound.
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV B #<NULL-LEXENV>)

Why am I getting this error and how can I use macro to make this work?

P.S. I cannot use defun need to use macro to execute (testmac (print a) (print b))

2
Welcome on StackOverflow! This is a well-formed first question. However... Please write “Lisp”, w/o caps ;)Ealhad
@ Ealhad. Sure and thanks for your advise.Mike Randor
You are very welcome! Good luck and happy hacking.Ealhad
@Rainer @ Ealhad, thank you all for your feedback and suggestion. Based on what you all have pointed out, I am executing code as (testmac (print 'a) (print 'b)) which returns B and no errors. It solves the original problem that I was trying to sole, i.e. use macro and prog2 to evaluate both forms (@rainer, I understand it isn't advisable) and return result of the second form. I hoe that this is the correct resolution and not a workaround. Thanks.Mike Randor

2 Answers

5
votes

I am trying to use macro with two forms in LISP, which evaluates both forms but always return the result of form 2.

That's usually not a good idea - though it might be just not precise wording. A macro should not evaluate code - not without a good reason. Usually the macro just transforms code. The generated code then decides what to evaluate.

(defmacro testmac (x body) (prog2 x body))

(testmac (- 10 6) (/ 10 2))

So x is the list (- 10 6) and body is the list (/ 10 2).

Your macro returns the second list.

CL-USER 11 > (macroexpand-1 '(testmac (print a) (print b)))
(PRINT B)

The macro returns the form (print b). It then gets executed.

CL-USER 12 > (testmac (print a) (print b))

Error: The variable B is unbound.

If B is undefined you get the error you see.

There is no magic going on.

3
votes

That's because your testmac macro directly executes (prog2 x body), instead of expanding into it.

You need to write it like this:

(defmacro testmac (x body)
  `(prog2 ,x ,body))

The form after the backquote won't be evaluated, but those after a comma will.

You can (and you should!) test the expansion like this:

(macroexpand-1 '(testmac (print 42) (print 51)))

Which gives:

(PROG2 (PRINT 42) (PRINT 51))