有选择地将评估参数传递给宏窗体的最佳做法是什么?评估宏表格的参数
详细说明:与函数形式的默认评估规则不同,宏的有用性在于它能够接收未评估的参数。但是,有一个评估宏参数的合法用例。
考虑一个人为的例子:
(defparameter *func-body* '((print i) (+ i 1)))
假设这将是很好的是*func-body*
可以作为一个宏观our-defun
身体被定义为:所以(our-defun foo (i) (+ 1 i))
后
(defmacro our-defun (fun args &body body)
`(defun ,fun ,args ,@body))
,我们可以比如(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
。
这导致我的问题在开始时,有没有更直接或原生的方式来做到这一点?
P.S.,
甲不那么人为的例子是在功能(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))))))
感谢您的解释。 通过“未评估的参数”,我的意思是宏绕过适用于函数参数的递归评估规则,并获取从阅读器生成的原始s-exp。 “读取时间评估”阅读器宏#的问题。在这种情况下,正如你所观察到的,它内部的表达式,即* func-body *在读取时没有值。 在这种情况下,我没有写(加钩)和(删除挂钩)。他们是由我以外的人写的。这就是为什么我需要找出将运行时值注入其参数的方法。 – 2013-03-28 00:17:28
@魏鹏彭巍:宏在编译时确实得到了源代码 - 在评估之前很久。 – 2013-03-28 06:14:54