为什么这个常见的lisp宏不会评估第一个s-exp?

时间:2016-10-04 22:17:19

标签: macros common-lisp ccl

我研究了define-easy-handler macro from the hunchentoot package(它创建了一个名为NAME的函数),并使defun部分工作,但是我无法通过这个宏将NAME推送到名为{{1}的列表中}:

*observers*

(defmacro add-observer (name params &body body) ;; add NAME to the list *observers* `(push ,name *observers*) ;; define a lisp function with the name NAME ;; with key arguments given in PARAMS `(defun ,name (&key ,@(loop for p in params collect p)) ,@body))) 的示例调用是:

#'add-observer

NAME功能已定义且工作正常,但NAME未添加到列表(add-observer below-80 (id blood-sugar) (when (< blood-sugar 80) (format t "Patient No: ~A is hypoglycemic." id)) 中。如果我将两个s表达式都放在预测中并不重要。 macroexpand清楚地显示没有预测的*observers*调用的缺失。我在解释什么错误?

修改

当我尝试这样的预测时:

push

它以`(progn (push ... (defn ... 失败。当我把反引号放回#&#39; push和#&#39; defun时,再次推送#&#39; push不起作用。

1 个答案:

答案 0 :(得分:3)

宏获取源表单并计算第一个结果表单:(push foo *observers*)然后将此表单返回到垃圾收集器的必杀技,因为它没有存储在任何地方,没有返回给任何调用者,没有执行,......立刻就是垃圾。所以一个聪明的编译器甚至可以删除它......

宏表单然后计算第二个表单(defun ...)。此表单从宏返回,然后执行。

要么在宏扩展时执行第一个表单,那么你需要通过删除反引号和逗号来使其可执行。

或者您希望将其包含在生成的源代码中,然后您需要返回一个progn表单,其中包含所有子表单。

当宏表单多次执行/展开时,您可能还想考虑PUSHPUSHNEW的效果......

使用宏时不需要的符号评估

记住:符号是Lisp代码中的变量。如果你想将它们视为符号本身,那么你需要引用它们出现的符号或数据结构。

说,你的表格是:

(add-observer below-80 ...)

这意味着below-80没有引用。

现在,您也可以生成符号未加引号的代码。

(push below-80 ...)

当然,这会尝试评估变量 below-80,它似乎在您的代码中未绑定。

如果您希望在评估期间将below-80视为符号,则必须引用它:'below-80。生成的代码应如下所示:

(push 'below-80 ...)

在你的代码中引用它

(add-observer 'below-80 ...)

或通过进入扩展:

(push 'below-80 ...)

反引号模板是

`(progn
   (push ',name ...)
   ...)
相关问题