宏问题:宏体的Eval有效,但宏没有

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变量.)不起作用.

sds*_*sds 6

测试反引用时,只需打印它:

> `(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-它必须知道在编译时的所有条款.