如何理解Lisp宏定义中的参数绑定?

如何理解Lisp宏定义中的参数绑定?,lisp,common-lisp,Lisp,Common Lisp,如下面的Lisp代码所示 (defvar a 1) (defvar b 2) (defmacro macro-add (c d) `(+ ,c ,d)) (macro-add a b) 调用宏binds宏参数c的最后一行传入,这是指c绑定到符号a还是绑定到符号a的值?更具体地说,在宏上下文中c的计算结果是a还是1?它绑定到符号“a”。宏的参数基本上是不计算的,而函数的参数是计算的。它绑定到符号“a”。与函数相比,宏的参数基本上不进行计算。宏基本上是代码转换器。它们将代码作为输入、解

如下面的Lisp代码所示

(defvar a 1)
(defvar b 2)

(defmacro macro-add (c d)
    `(+ ,c ,d))

(macro-add a b)

调用宏binds宏参数c的最后一行传入,这是指c绑定到符号a还是绑定到符号a的值?更具体地说,在宏上下文中c的计算结果是a还是1?

它绑定到符号“a”。宏的参数基本上是不计算的,而函数的参数是计算的。

它绑定到符号“a”。与函数相比,宏的参数基本上不进行计算。

宏基本上是代码转换器。它们将代码作为输入、解构并绑定到宏参数。他们使用任意计算生成新代码。对于简单的模板式代码生成,倒引号列表很受欢迎

Lisp is中的源代码有两种不同的外观:文本s表达式和内部所谓的表单,它们已经是Lisp数据。这种转换是由Lisp阅读器完成的

然后在这些Lisp表单上执行宏转换。这种转变的结果是一种新的形式。最终,在展开所有宏之后,将对生成的源代码进行求值。这幅图有点错误,但它有助于想象有三个独立的阶段:读取、宏扩展和执行

在您的情况下,源表单是三个符号的列表:
(宏添加a b)
。第一个符号命名宏,因此窗体将被宏展开。列表被分解:第一个符号是宏名称,第二个符号将绑定到
C
,第三个符号将绑定到
D
。有了这个参数,宏现在就可以执行了。结果,它产生了一个新的表单:一个包含三个项目的列表。第一项是符号
+
,第二项是
C
的值,符号
A
,第三项是
D
的值,符号
B
<代码>(+AB)是宏扩展的结果


如果需要,宏展开的结果现在将再次进行宏展开。由于代码中的
+
不是宏,因此不会进行宏扩展<代码>+是一个函数。现在进行普通的计算:计算
A
的值,计算
B
的值,然后用这两个值调用
+
来计算新的结果值。

宏基本上是代码转换器。它们将代码作为输入、解构并绑定到宏参数。他们使用任意计算生成新代码。对于简单的模板式代码生成,倒引号列表很受欢迎

Lisp is中的源代码有两种不同的外观:文本s表达式和内部所谓的表单,它们已经是Lisp数据。这种转换是由Lisp阅读器完成的

然后在这些Lisp表单上执行宏转换。这种转变的结果是一种新的形式。最终,在展开所有宏之后,将对生成的源代码进行求值。这幅图有点错误,但它有助于想象有三个独立的阶段:读取、宏扩展和执行

在您的情况下,源表单是三个符号的列表:
(宏添加a b)
。第一个符号命名宏,因此窗体将被宏展开。列表被分解:第一个符号是宏名称,第二个符号将绑定到
C
,第三个符号将绑定到
D
。有了这个参数,宏现在就可以执行了。结果,它产生了一个新的表单:一个包含三个项目的列表。第一项是符号
+
,第二项是
C
的值,符号
A
,第三项是
D
的值,符号
B
<代码>(+AB)是宏扩展的结果


如果需要,宏展开的结果现在将再次进行宏展开。由于代码中的
+
不是宏,因此不会进行宏扩展<代码>+是一个函数。现在进行普通计算:计算
A
的值,计算
B
的值,然后用这两个值调用
+
来计算新的结果值。

宏是词法替换,因此c将被a和d替换为B。使用函数
macroexpand
macroexpand-1
可以帮助您了解宏是如何工作的以及它们扩展到什么。宏是词汇替换,因此c将被a替换,d将被b替换。使用函数
macroexpand
macroexpand-1
可以帮助您了解宏是如何工作的以及它们的扩展方向。谢谢您的解释。你的回答中的下列句子仍然有点混乱。1.“第二个符号将绑定到C”,这是否意味着符号C在宏上下文中将具有值A(第二个参数)?2.宏体
~(+,C,D)
看起来也有点奇怪,如果宏扩展只是表单替换,为什么不
(+cd)
?读卡器宏不应该计算宏体,对吗?那为什么还需要引用呢?谢谢你的解释。你的回答中的下列句子仍然有点混乱。1.“第二个符号将绑定到C”,这是否意味着符号C在宏上下文中将具有值A(第二个参数)?2.宏体
~(+,C,D)
看起来也有点奇怪,如果宏扩展只是表单替换,为什么不
(+cd)
?读卡器宏不应该计算宏体,对吗?那为什么还需要引用呢?