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))
及
做同样的事情。它们是等价的代码片段(反引号语法并不局限于宏体!):它们都构造了一个列表,其第一个元素是symbolCONCAT
,第二个元素是变量a
所指的符号名
显然,这只有在A
引用符号时才有意义,正如斯万特所指出的,在宏调用示例中并非如此
当然,您可以从列表中提取符号(QUOTE FOO)
,但这会阻止您像这样调用宏:
(let ((x 'foo))
(tm x))
这就提出了一个问题:为什么事件要强制宏的用户显式引用符号,而符号无论如何都必须是文字常量
其次,宏的工作方式是这样的:它们将代码片段(例如(QUOTE FOO)
)作为参数,并生成一段新代码,在宏扩展时,(或多或少)替换源代码中的宏调用。在生成的代码中重用宏参数通常很有用,方法是将宏参数放在以后要对其求值的位置,例如
(defmacro tm2 (a)
`(print (symbol-name ,a)))
考虑一下这段代码的作用,以及上面的let
示例现在是否起作用。这会让你走上正轨
最后,一条建议:当函数可以执行时,避免使用宏。它将使实施者和用户的生活更加轻松。首先,请注意
`(concat ,(symbol-name a))
及
做同样的事情。它们是等价的代码片段(反引号语法并不局限于宏体!):它们都构造了一个列表,其第一个元素是symbolCONCAT
,第二个元素是变量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:是的,但你为什么要这样做?是的,我想也许我应该首先选择函数而不是宏。谢谢你的建议和回答。是的,我想我应该先选择函数而不是宏。谢谢你的建议和回答。