2013-02-27 57 views
1

我对传递给宏的参数如何得到评估有疑问,细节如下。在宏体内传递参数的评估

这个宏定义

(defmacro test-macro (xlist) 
    `(* ,@xlist)) 

并没有这个全局变量(defvar *test-list* '(1 100 2 200))

*test-list*传递给这个宏(test-macro *test-list*),返回此错误 -

value *TEST-LIST* is not of the expected type LIST. 
    [Condition of type TYPE-ERROR] 

但如果功能被修改为这个,返回

(defmacro test-macro (xlist) 
    `(,@xlist)) ;; removed the * operator 

(test-macro *test-list*)名单将返回(1 100 2 200)

所以我怀疑为什么,@xlist在第一种情况下没有得到评估,即应用了*操作符。任何帮助,高度赞赏。

回答

4

调试宏时,正确的方法是使用macroexpand,而不是评估宏的形式。例如,在你的情况下:

(defmacro test-macro1 (xlist) `(* ,@xlist)) 
(macroexpand '(test-macro1 foo)) 
==> (* . FOO) 
(defmacro test-macro2 (xlist) `(,@xlist)) 
(macroexpand '(test-macro2 foo)) 
==> FOO 

既不可能是你想要的。

+0

非常感谢。宏观膨胀是超级有用的.. – 5Fists 2013-02-27 15:39:54

+0

@ 5fists有一个热键macroexpand在粘液;这是1,slimv – 2013-02-28 06:56:31

3

令人困惑的是宏是一个预处理器:它没有内置机制来知道运行时值。所以,当你使用术语:

(test-macro test-list) 

所有宏看到的是标识test-list:它不知道的前期的运行值是一个列表,只有源程序已经使用这种变量标识符。

宏是源到源重写器:它不知道程序的动态。一个更聪明的编译器可能会看到测试列表是一个常量并进行内联,但宏扩展器并不聪明。

你可以做什么可能是这样的:

(defmacro test-macro (xlist) 
    (cond 
    (;; If we see test-macro is being used with a quoted list of things 
    ;; then we can rewrite that statically. 
    (and (pair? xlist) 
      (eq? (car xlist) 'quote) 
      (list? (cadr xlist))) 
    `(list 'case-1 (* ,@(cadr xlist)))) 

    (;; Also, if we see test-macro is being used with "(list ...)" 
    ;; then we can rewrite that statically. 
    (and (pair? xlist) 
      (eq? (car xlist) 'list)) 
    `(list 'case-2 (* ,@(cdr xlist)))) 

    (else 
    ;; Otherwise, do the most generic thing: 
    `(list 'case-3 (apply * ,xlist))))) 



;; This hits the first case: 
(test-macro '(3 4 5)) 

;; ... the second case: 
(test-macro (list 5 6 7)) 

;; ... and the third case: 
(defvar test-list '(1 100 2 200)) 
(test-macro test-list) 

至于你的第二个版本:宏:

(defmacro test-macro (xlist) 
    `(,@xlist)) 

等同于:

(defmacro test-macro (xlist) 
    xlist) 

所以这就是为什么你没有收到您在第一版中收到的错误。

+0

感谢您在这样的细节解释它。在您的代码中使用的一些函数在我使用的Common Lisp实现中不可用。不能说我完全理解您的代码,但没有几个重要的点对我进一步学习Lisp非常有用。似乎我有很长的路要走:)。 – 5Fists 2013-02-27 15:34:48