lisp宏使用部分求值展开

lisp宏使用部分求值展开,lisp,expand,ccl,Lisp,Expand,Ccl,我有下面的代码,这让我很困惑,我希望有人能告诉我区别,以及如何解决这个问题 (defmacro tm(a) `(concat ,(symbol-name a))) (defun tf(a) (list (quote concat) (symbol-name a))) 我只是认为它们应该是相同的效果,但实际上它们似乎不是。 我试着打以下电话: CL-USER> (tf 'foo) (CONCAT "FOO") CL-USER> (tm 'foo) value

我有下面的代码,这让我很困惑,我希望有人能告诉我区别,以及如何解决这个问题

(defmacro tm(a)
   `(concat ,(symbol-name a)))

(defun tf(a)
       (list (quote concat) (symbol-name a)))
我只是认为它们应该是相同的效果,但实际上它们似乎不是。
我试着打以下电话:

CL-USER> (tf 'foo)
(CONCAT "FOO")

CL-USER> (tm 'foo)
value 'FOO is not of the expected type SYMBOL.
[Condition of type TYPE-ERROR]
那么,有什么问题

我想要的是:

(tm 'foo)  ==>  (CONCAT "FOO")

第一个问题是读者将
'foo
扩展为
(quote foo)
,它不是一个符号,而是一个列表。宏尝试展开
(tm(quote foo))
。列表
(quote foo)
作为参数
a
传递给宏扩展函数,宏扩展函数尝试获取其
符号名称。列表不是
符号名称
的有效参数。因此,宏扩展失败


第二个问题是,虽然
(tm foo)
(注意:没有引号)确实扩展到
(concat“foo”)
,但该表单随后将由REPL执行,因此这与
tf
函数也不相同。当然,这并不奇怪,因为宏做的事情与函数不同。

第一个问题是读者将
'foo
扩展为
(quote foo)
,它不是符号,而是列表。宏尝试展开
(tm(quote foo))
。列表
(quote foo)
作为参数
a
传递给宏扩展函数,宏扩展函数尝试获取其
符号名称。列表不是
符号名称
的有效参数。因此,宏扩展失败

第二个问题是,虽然
(tm foo)
(注意:没有引号)确实扩展到
(concat“foo”)
,但该表单随后将由REPL执行,因此这与
tf
函数也不相同。当然,这并不奇怪,因为宏做的事情与函数不同。

首先,请注意

`(concat ,(symbol-name a))

做同样的事情。它们是等价的代码片段(反引号语法并不局限于宏体!):它们都构造了一个列表,其第一个元素是symbol
CONCAT
,第二个元素是变量
a
所指的符号名

显然,这只有在
A
引用符号时才有意义,正如斯万特所指出的,在宏调用示例中并非如此

当然,您可以从列表中提取符号
(QUOTE FOO)
,但这会阻止您像这样调用宏:

(let ((x 'foo))
  (tm x))
这就提出了一个问题:为什么事件要强制宏的用户显式引用符号,而符号无论如何都必须是文字常量

其次,宏的工作方式是这样的:它们将代码片段(例如
(QUOTE FOO)
)作为参数,并生成一段新代码,在宏扩展时,(或多或少)替换源代码中的宏调用。在生成的代码中重用宏参数通常很有用,方法是将宏参数放在以后要对其求值的位置,例如

(defmacro tm2 (a)
  `(print (symbol-name ,a)))
考虑一下这段代码的作用,以及上面的
let
示例现在是否起作用。这会让你走上正轨

最后,一条建议:当函数可以执行时,避免使用宏。它将使实施者和用户的生活更加轻松。

首先,请注意

`(concat ,(symbol-name a))

做同样的事情。它们是等价的代码片段(反引号语法并不局限于宏体!):它们都构造了一个列表,其第一个元素是symbol
CONCAT
,第二个元素是变量
a
所指的符号名

显然,这只有在
A
引用符号时才有意义,正如斯万特所指出的,在宏调用示例中并非如此

当然,您可以从列表中提取符号
(QUOTE FOO)
,但这会阻止您像这样调用宏:

(let ((x 'foo))
  (tm x))
这就提出了一个问题:为什么事件要强制宏的用户显式引用符号,而符号无论如何都必须是文字常量

其次,宏的工作方式是这样的:它们将代码片段(例如
(QUOTE FOO)
)作为参数,并生成一段新代码,在宏扩展时,(或多或少)替换源代码中的宏调用。在生成的代码中重用宏参数通常很有用,方法是将宏参数放在以后要对其求值的位置,例如

(defmacro tm2 (a)
  `(print (symbol-name ,a)))
考虑一下这段代码的作用,以及上面的
let
示例现在是否起作用。这会让你走上正轨


最后,一条建议:当函数可以执行时,避免使用宏。它将使实现者和用户的生活更加轻松。

当然
'FOO
(它是
(QUOTE FOO)
的缩写)不是一个符号。它是一个列表。当然,
'FOO
(是
(QUOTE FOO)
的缩写形式)不是一个符号。这是一张单子。谢谢你的解释。另一方面,是否可以将tm称为(tm'foo)并导致(concat“foo”)?winterTTr:是的,但你为什么要这样做?谢谢你的解释。另一方面,是否可以将tm称为(tm'foo)并生成(concat“foo”)?winterTTr:是的,但你为什么要这样做?是的,我想也许我应该首先选择函数而不是宏。谢谢你的建议和回答。是的,我想我应该先选择函数而不是宏。谢谢你的建议和回答。