【问题标题】:Macro Issues: Eval of a macro body works, but the macro doesn't宏问题:宏体的 Eval 有效,但宏无效
【发布时间】:2017-06-09 12:46:47
【问题描述】:

考虑以下代码sn-p:

[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 ,给出结果。但是相同的代码(通过替换 *clist*'1clistindex 变量。)在用作宏的主体时不起作用。

【问题讨论】:

  • 请复制并粘贴确切的代码和消息。众所周知,comma is illegal outside of backquote,所以你的问题是在骗我们。
  • 我错误地删除了反引号。现在的问题是他们。 @sds
  • 谢谢。我为你修复了格式。现在请重新编写最后两段。不是以英语为母语的人,我无法理解您的意思。请注意,没有 emacs-REPL 这样的东西。
  • 请删除所有提及 Emacs。 Emacs Lisp 没有在这里进行评估,也没有发出错误信号。错误来自 SBCL,请在常规 REPL 中自行查看。
  • *clist* 是一个symbol,它的值是一个list。你没有评估它。

标签: macros lisp common-lisp


【解决方案1】:

测试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""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 没有胜利 - 它必须在编译时知道所有子句。

【讨论】:

  • 发生这种情况是因为宏不评估它们的参数,因此,宏tester没有评估*clist*,只是把符号*clist*,进入扩展?
【解决方案2】:

让我们使用你的宏,删除扩展并打印它的参数:

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

所以index1clist 是符号*clist*

现在让我们尝试使用函数rest 和符号*clist* 调用mapcar

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* 不是有效列表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 2015-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多