3

让我们假设:

(defmacro testing (&optional var)
    `(list 'this 'is  
       ,@(when (consp var) `('a 'list))))

调用时:

>(testing 2)
(THIS IS)

>(testing (list 1 2))
(THIS IS A LIST)

这就是我想要的。但是现在,当我传递一个列表参数时:

>(defparameter bla (list 1 2 3))
BLA
>(testing bla)
(THIS IS)

我想这是因为宏会检查(consp bla)bla 是符号的位置,而不是列表?我该如何防止这种情况?

谢谢

4

2 回答 2

5

您可以执行以下操作:

(defmacro testing (&optional var)
   `(if (consp ,var)
        '(this is a list)
        '(this is)))

所以var将在运行时(而不是编译时)进行评估。var在宏的扩展中只出现一次,但如果出现多次,则必须使用 gensym。

编辑:如果您不想输入'(this is)两次,请执行以下操作:

(defmacro testing (&optional var)
  `(append '(this is) (when (consp ,var) '(a list))))

不要使用eval,它很慢,而且完全没有必要。通过代var入宏展开,它自然会在运行时被求值。如果您使用 eval,您将执行以下操作:

(eval (append '(list 'this 'is) (when (consp 'bla) '('a 'list))))

每次执行时,它都会建立一个代表代码的列表并在运行之前对其进行编译。(希望这不是循环!)如果您只使用生成简单代码(不带eval)的宏,它只会编译一次。

于 2012-02-09T18:24:22.097 回答
0

这里的问题是表达式

,@(when (consp var) `('a 'list))))

在编译时评估,当您只有文字(未评估)参数值时。在您的情况下:2(list 1 2)bla

我知道的唯一解决方案是使用eval. 这个特定的例子可以改变如下:

(defmacro testing (&optional var)
  `(eval (append '(list 'this 'is)  
                 (when (consp ',var)
                   '('a 'list))))

但是,我认为,你会同意,它真的很丑。如果你想使用词法变量,它就行不通了。通常,有办法重新表述问题,这样就不需要这种变态。

于 2012-02-09T17:07:32.667 回答