Moo*_*ter 1 lisp macros common-lisp
请考虑以下代码段:
[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]>
Run Code Online (Sandbox Code Playgroud)
该代码包含生成的错误消息.
正如人们可以清楚地看到的那样eval,用作宏体的代码tester会产生结果.但是当它被用作宏的主体时,相同的代码(通过替换
*clist*和'1,clist以及index变量.)不起作用.
测试反引用时,只需打印它:
> `(case '1 ,@(mapcar #'rest *clist*))
(CASE '1 (1 21) (2 32) (3 43))
Run Code Online (Sandbox Code Playgroud)
当测试宏,你不(无论是在REPL或者,更何况,使用评估他们eval
明确).
您使用宏来扩展宏macroexpand
并检查代码.
例如,
> (macroexpand-1 '(tester '1 *clist*))
*** - MAPCAR: A proper list must not end with *CLIST*
Run Code Online (Sandbox Code Playgroud)
这告诉你tester传递symbol *CLIST*而不是它的值mapcar.
您需要根据"编译时间" 与"执行时间"来考虑您要 执行的操作.
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
Run Code Online (Sandbox Code Playgroud)
既然你不知道价值的clist在编译时(仅保存它的变量名),则在不使用赢case-它必须知道在编译时的所有条款.