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