avoiding eval in a macro

Discussion of Common Lisp
Post Reply
murphey607
Posts: 2
Joined: Fri Jan 06, 2012 12:48 pm

avoiding eval in a macro

Post by murphey607 » Fri Jan 06, 2012 1:09 pm

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))))

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: avoiding eval in a macro

Post by ramarren » Fri Jan 06, 2012 2:42 pm

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.

virex
Posts: 17
Joined: Fri Oct 28, 2011 3:41 pm

Re: avoiding eval in a macro

Post by virex » Tue Jan 10, 2012 3:00 pm

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.

murphey607
Posts: 2
Joined: Fri Jan 06, 2012 12:48 pm

Re: avoiding eval in a macro

Post by murphey607 » Sat Jan 21, 2012 5:28 am

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

Post Reply