有选择地将评估参数传递给宏形式的最佳实践是什么?
详细说明:宏的用处在于它能够接收未评估的参数,这与函数形式的默认评估规则不同。但是,评估宏参数有一个合法的用例。
考虑一个人为的例子:
(defparameter *func-body* '((print i) (+ i 1)))
假设*func-body*
可以用作our-defun
定义为的宏的主体会很好:
(defmacro our-defun (fun args &body body)
`(defun ,fun ,args ,@body))
所以之后(our-defun foo (i) (+ 1 i))
,我们可以说(foo 1)
得到2
。但是,如果我们使用(our-defun foo (i) *func-body*)
,则 的结果(foo 1)
将是((PRINT I) (+ I 1))
(即 的值*func-body*
)。如果我们可以强制将评估*func-body*
作为宏的参数,那就太好了our-defun
。
目前,我可以想到一种使用compile
并funcall
做到这一点的技术,如
(funcall (compile nil `(lambda () (our-defun foo (i) ,@*func-body*))))
之后将按预期(our-defun 1)
打印出 1 并返回。我2
可以考虑使用.eval
eval
这导致我一开始的问题,有没有更直接或本地的方式来做到这一点?
PS,
一个不太人为的例子是在 function(UPDATE-HOOK)
中,它使用两个库宏(ADD-HOOK)
并且(REMOVE-HOOK)
需要评估它的参数。这里使用了上面的(funcall (compile nil `(lambda () ...)))
技术。
(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))))))