From: rif
Subject: avoiding eval in macroexpansion
Date: 
Message-ID: <wj0hedsc7p6.fsf@five-percent-nation.mit.edu>
I'm working through Chapter 15 of Graham's ANSI Common Lisp book
(Example:Inference).  He includes the following macro (and variable
definition):

(defvar *rules* (make-hash-table))

(defmacro <- (con &optional ant)
  `(length (push (cons (cdr ',con) ',ant)
                 (gethash (car ',con) *rules*))))

So let's say I want to make a bunch of calls of the form

(<- person foo)

where foo varies.  I'd like to do this as some sort of mapping over a
list.  I can do it using eval:

(dolist (p '(donald nancy bumble lina sally))
  (eval `(<- (person ,p))))    

But surely there's a better way?  It's not that I particularly have to
do this, I'm just trying to get a better understanding of macros.

rif

From: Frode Vatvedt Fjeld
Subject: Re: avoiding eval in macroexpansion
Date: 
Message-ID: <2hhedsx9pz.fsf@vserver.cs.uit.no>
rif <···@mit.edu> writes:

> But surely there's a better way?  It's not that I particularly have
> to do this, I'm just trying to get a better understanding of macros.

Write a version of the <- macro that evaluates its arguments. It
should make a good exercise in macro writing (it's not hard). Make
sure your macro obeys the standard evaluation rules: Each argument
should be evaluated exactly once, in left to right order.

-- 
Frode Vatvedt Fjeld
From: Kalle Olavi Niemitalo
Subject: Re: avoiding eval in macroexpansion
Date: 
Message-ID: <87smxbcuuk.fsf@Astalo.y2000.kon.iki.fi>
rif <···@mit.edu> writes:

> I'd like to do this as some sort of mapping over a
> list.  I can do it using eval:
> 
> (dolist (p '(donald nancy bumble lina sally))
>   (eval `(<- (person ,p))))    

If the list is known at read time, you can do this:

  #.`(progn
       ,@(loop for p in '(donald nancy bumble lina sally)
               collect `(<- (person ,p))))

Or at compile time:

  (macrolet ((<-list (key items &optional (ant nil antp))
               `(progn
                  ,@(loop for item in items
                          collect `(<- (,key ,item)
                                       ,@(when antp (list ant)))))))
    (<-list person (donald nancy bumble lina sally)))

If you don't have the list until at run time, then you have to
use eval or change the <- macro.

Style question: Is it good to use `(progn ,@(...)) rather than
(cons 'progn (...))?  I feel that the first form shows the intent
better: that the result is a proper list and nothing else will be
consed in front of the PROGN.