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))))))
That's slightly confused. A macro does not receive unevaluated parameters.
A macro gets source code and creates source code from that. Remember also that source code in Lisp is actually provided as data. The macro creates code, which evaluates some forms and some not.
Macros need to work in a compiling system. Before runtime. During compile time. All the macro sees is source code and then it creates source code from that. Think of macros as code transformations, not about evaluating arguments or not.
It would be nice if we can force the evaluation of
*func-body*
as an argument to the macro our-defun
That is not very clean. In a compiled system, you would need to make sure that *func-body*
actually has a useful binding and that it can be resolved at COMPILE TIME.
If you have a macro like DEFUN
, it makes sense to have the source code static. If you want to insert some source code into a form, then it could make sense to do that at read time:
(defun foo (i) #.`(,@*foo*))
But that's code I usually would want to avoid.
two library macros
(ADD-HOOK)
and(REMOVE-HOOK)
and needs to evaluate its parameters.
Why should ADD-HOOK
and REMOVE-HOOK
be macros? If you don't have a real reason, they simply should be functions. Already since they make reuse difficult.
If you want to make ADD-HOOK
and REMOVE-HOOK
macros for some reason, then UPDATE-HOOK
usually should be a macro, too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With