Consider the following code snippet:
[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]>
The code contains the error-message generated.
As one can clearly see, that eval
of the code that is used as the body
of the macro tester
, gives a result. But the same code (by replacing
*clist*
and '1
, by clist
and index
variables.) doesn't work when it's used as a body of the macro.
答案 0 :(得分:6)
测试backquote时,只需打印它:
> `(case '1 ,@(mapcar #'rest *clist*))
(CASE '1 (1 21) (2 32) (3 43))
在测试宏时,你会不评估它们(在REPL或者全部
更是如此,使用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
没有胜利 - 它必须在编译时知道所有子句。
答案 1 :(得分:1)
让我们拿你的宏,删除扩展并打印它的参数:
CL-USER 4 > (defmacro tester (index clist)
(print (list :macro-tester :index index :clist clist))
nil)
TESTER
现在我们用你的例子来称呼它:
CL-USER 5 > (tester 1 *clist*)
(:MACRO-TESTER :INDEX 1 :CLIST *CLIST*)
NIL
因此index
为1
而clist
为符号*clist*
。
现在让我们尝试使用函数mapcar
和符号rest
来调用*clist*
:
CL-USER 9 > (mapcar #'rest '*clist*)
Error: *CLIST* (of type SYMBOL) is not of type LIST.
1 (abort) Return to level 0.
2 Return to top loop level 0.
这是你看到的错误。符号*clist*
不是有效列表。