考虑下面的代码片段:

[1]> (defvar *clist* '((2 1 21) ( 3 2 32) (4 3 43)))
*CLIST*
[2]> (eval `(case '1 ,@(mapcar #'rest *clist*)))
21
[3]> (defmacro tester (index clist)
      `(case ,index ,@(mapcar #'rest clist)))
TESTER
[4]> (tester '1 *clist*)
*** - MAPCAR: A proper list must not end with *CLIST*
The following restarts are available:
ABORT          :R1      Abort main loop
Break 1 [5]>

代码包含生成的错误消息。
我们可以清楚地看到,作为主体的代码
给出了一个结果但是相同的代码(通过替换
evaltester,by*clist*'1变量)用作宏体时不起作用。

最佳答案

测试backquote时,只需打印:

> `(case '1 ,@(mapcar #'rest *clist*))
(CASE '1 (1 21) (2 32) (3 43))

测试宏时,不计算它们(在REPL或all
使用eval
明确)。
使用macroexpand展开宏
并检查代码。
例如。,
> (macroexpand-1 '(tester '1 *clist*))
*** - MAPCAR: A proper list must not end with *CLIST*

这告诉您tester通过symbol*CLIST*而不是
其值为mapcar
你得想想你想做什么
"compile-time"
vs"execution time"
你知道编译时的index吗?
你知道编译时的clist吗?
在您的情况下,没有理由使用case
(defmacro tester (index clist) `(third (find ,index ,clist :key #'second)))
(macroexpand-1 '(tester 1 *clist*))
==> (THIRD (FIND 1 *CLIST* :KEY #'SECOND)) ; T
(tester 1 *clist*)
==> 21

因为您不知道编译时clist的值(只有
变量名存储在哪里
使用case-它必须在编译时知道所有子句。

07-27 14:00