考虑下面的代码片段:
[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]>
代码包含生成的错误消息。
我们可以清楚地看到,作为主体的代码
给出了一个结果但是相同的代码(通过替换
eval
和tester
,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
-它必须在编译时知道所有子句。