Page 1 of 1

avoiding eval in a macro

Posted: Fri Jan 06, 2012 1:09 pm
by murphey607
Hi there,

I'm not very deep into CL yet and struggling with this problem:
The following macro won't compile because ,@body is not a list (sbcl)
However if try a (listp ,body) it will return true. Can you please help me to understand this?
(the code is reduced beyond usefulness to show the problem)

TIA
murph

Code: Select all

(defmacro gen-name-broken (name)
  (let ((body (intern "BODY")))
    `(defmacro ,name (&body body)
       (let ((result (progn ,@body)))
	 result))))

Of course I can use eval like this, but I want to avoid it

Code: Select all


(defmacro gen-name-eval (name)
  (let ((body (intern "BODY")))
    `(defmacro ,name (&body body)
       (warn "is-list? ~S~%" (listp ,body))
       (let ((result (apply #'eval ,body)))
	 result))))

Re: avoiding eval in a macro

Posted: Fri Jan 06, 2012 2:42 pm
by ramarren
murphey607 wrote:I'm not very deep into CL yet and struggling with this problem:
You probably shouldn't be nesting DEFMACRO then. Or ever, nesting macro definitions generally and definitely directly is not really a good idea, because keeping track of scope is difficult.

In your case the variable body in the scope of the outer macro is not a list, it has a value of a single symbol created by INTERN. The LISTP in the second example is in the scope of the inner macro, which is a list because it refers to the argument of the inner macro.

Re: avoiding eval in a macro

Posted: Tue Jan 10, 2012 3:00 pm
by virex
The problem isn't scoping, it's that your backquoting levels aren't in order. The inner defmacro is inside a single backquote, so the call to ,@body is going to look for body outside of that backquote level and it finds a symbol, not a list (because that's what you introduced with intern). But the call that checks if body is a list is within the backquotes and thus sees the new definition of body, which is indeed a list. This means that you need to move that backquote around or add another one to get the thing to compile.

Re: avoiding eval in a macro

Posted: Sat Jan 21, 2012 5:28 am
by murphey607
Hi,
I was able to get behind my problem by changing the line

Code: Select all

  (let ((body (intern "BODY"))) 
to

Code: Select all

  (let ((body (intern "FOO"))) 
this made it possible to get different error-messages for the body variable depending on the backquote level

thanks for your help

greetings

murphy