What is the best practice for selectively passing evaluated arguments to a macro form?
To elaborate: The usefulness of macros lies in its ability to receives unevaluated parameter, unlike the default evaluation rule for function forms. However, there is a legitimate use cases for evaluating macro arguments.
Consider a contrived example:
(defparameter *func-body* '((print i) (+ i 1)))
Suppose it would be nice that *func-body*
could serve as the body of a macro our-defun
that is defined as:
(defmacro our-defun (fun args &body body)
`(defun ,fun ,args ,@body))
So after (our-defun foo (i) (+ 1 i))
, we could say (foo 1)
to get 2
. However, if we use (our-defun foo (i) *func-body*)
, the result of (foo 1)
will be ((PRINT I) (+ I 1))
(i.e., the value of *func-body*
). It would be nice if we can force the evaluation of *func-body*
as an argument to the macro our-defun
.
Currently, I can think of a technique of using compile
and funcall
to do this, as in
(funcall (compile nil `(lambda () (our-defun foo (i) ,@*func-body*))))
after which (our-defun 1)
will print out 1 and return 2
, as intended. I can think of case of making this work with eval
, but I would rather stay away from eval
due to its peculiarity in scoping.
This leads to my question at the begining, is there a more straightforward or native way to do this?
P.S.,
A not-so-contrived example is in the function (UPDATE-HOOK)
, which uses two library macros (ADD-HOOK)
and (REMOVE-HOOK)
and needs to evaluate its parameters. The (funcall (compile nil `(lambda () ...)))
technique above is used here.
(defun update-hook (hook hook-name &optional code)
(funcall (compile nil `(lambda () (remove-hook ,hook ',hook-name))))
(unless (null code)
(compile hook-name `(lambda () ,@code))
(funcall (compile nil `(lambda () (add-hook ,hook ',hook-name))))))