Common Lisp 宏宏扩展时间参数输入

Stu*_*ent 0 lisp macros common-lisp

在下面的函数中,我用 mac-1 替换了宏,它只返回它工作的参数的值,但 mac-2 抛出一个类型错误。有人可以解释会发生什么并导致此错误吗?为什么 x 从 fun-2 传递给 mac-2 是文字符号x而不是整数?

(defmacro mac-1 (x) x)
(defun fun-1 (x) (mac-1 x))
(fun-1 3)               ; => 3

(defmacro mac-2 (x) (+ x 3))
(defun fun-2 (x) (mac-2 x))
(fun-2 3)
Run Code Online (Sandbox Code Playgroud)

执行编译有错误的表单。形式:(MAC-2 X) 编译时错误:在 (MAC-2 X) 的宏扩展期间。使用BREAK-ON-SIGNALS进行拦截。

绑定 SB-KERNEL::X 时,值 X 不是 NUMBER 类型

Rai*_*wig 7

重命名事物:

(defmacro mac-2 (source-code-expression)
  (declare (type (or number list symbol string)  ; actually T,
                                                 ; since all types are allowed
                 source-code-expression))
  (+ source-code-expression 3))  ; here we have a type problem
Run Code Online (Sandbox Code Playgroud)

这仅适用于数字。但是:例如,不能将 3 添加到符号中。

请记住:宏接受任意表达式并创建新表达式。在宏扩展时,应该看到源代码,而不是值。

手段x从传递fun-2mac-2这里的源代码(数据)?并且在评估后x立即使用此数据(符号)扩展宏fun-2,并将扩展放入fun-2? 一步一步我开始明白我还不了解宏!

几乎:宏也可以在评估函数之前展开。例如,当您编译一个函数时,宏会被扩展 --> 显然这是不可能的,如果宏需要运行时值。

宏取代了更多的动态机制,正是因为它们能够编译为高效的代码,在运行时不需要宏扩展。

传递x给宏的函数的心智模型并没有那么有用。

更像是第一个基本思想:宏形式将被宏转换为一些新的表达式 - 在编译期间的编译实现和评估期间的解释版本中。

  • mac-2 是宏的名称
  • (mac-2 x)是一个宏形式,因为它是一个复合形式并且mac-2是一个宏的名称。

通常,所有将被评估的表达式都称为形式:函数形式、宏形式、特殊形式、lambda 形式、符号和自评估对象。

你能解释一下你的宏中的类型声明是做什么的吗?

只是为了明确您可以期望作为参数类型的内容。不要在代码中使用它,check-type而是使用它(见下文)。

(let ((x 100))

  (mac-2 1)         ; the macro sees a number
  (mac-2 x)         ; the macro sees a symbol ! Not a number!
  (mac-2 "x")       ; the macro sees a string
  (mac-2 (+ x 20))  ; the macro sees a list !   Not a number!

  ; and so on for other data objects

 ) 
Run Code Online (Sandbox Code Playgroud)

通常在可移植代码中,当您的宏期望某个参数具有某种类型或形状时,您可能希望添加check-type调用以明确这一点。假设我们想写一个宏来定义一个行星,我们需要一个名字,它应该是一个符号或一个字符串:

(defmacro defplanet (name coordinates)
  (check-type name (or string symbol)
              "The name of the planet must be a symbol or a string.")
  `(intern-planet ,name (check-coordinates ,coordinates)))       
Run Code Online (Sandbox Code Playgroud)

以上将在宏扩展时检查'name'值的类型。


Syl*_*ter 6

(defmacro mac-1 (x) x)有效,因为 fun-1定义时它会扩展xx. 基本上它是一个noop。它适用于任何表达式,因为它在编译时不进行计算。

(defmacro mac-2 (x) (+ x 3))仅当语法x是文字时才有效。例如。(mac-2 3)被转换为6,但在你的函数中你给了它x。记住宏转换语法,所以你正在做(+ 'x 3)(绑定x具有给出的值,fun-2其中是符号x)。x当这种扩展发生时,该变量甚至不存在,因此它甚至没有值。

如果您希望表达式的结果成为数字,则可以mac-2x存在时进行计算。例如。

(defmacro mac-2 (x)
  `(+ ,x 3))
Run Code Online (Sandbox Code Playgroud)

fun2创建将扩展宏,它不会尝试做计算的时候了,但功能被存储为:

(defun fun-2 (x) (+ x 3))
Run Code Online (Sandbox Code Playgroud)

当你然后调用fun-2 x将存在并且(+ x 3)有意义。在做(+ x 3)的时候,你创造功能没有因为当时的宏观得到x,同时x还不存在。