【问题标题】:Rules governing order of macro expansion in Common LispCommon Lisp 中控制宏扩展顺序的规则
【发布时间】:2016-12-05 12:12:52
【问题描述】:

defmacro 记录在http://clhs.lisp.se/Body/m_defmac.htm,但文档并不完全清楚地说明事情发生的确切时间。通过对 Clisp 的实验,我发现了以下内容(假设所有宏和函数都定义在顶层):

  • 直接的顶级代码只能调用之前定义的宏和函数。

  • 宏或函数中的代码,或由宏生成的代码,可以调用它喜欢的任何函数,包括稍后定义的函数(正如预期的那样,需要支持相互递归)。

  • 宏中的代码只能调用在第一个宏的调用位置之前定义的宏。

  • 宏生成的代码可以调用后面定义的宏。

是 Clisp 只是遵循规范,还是在这方面的实现之间有任何差异?

确切的预期规则集及其背后的基本原理是否记录在任何地方?

【问题讨论】:

标签: macros lisp common-lisp clisp


【解决方案1】:

您问的是宏扩展 - 但我想先澄清一下函数是如何处理的。

注意调用和定义实际发生的时间。在您的第二点中,您说函数中的代码可以调用稍后定义的函数。这并不完全正确。

在 C++ 等语言中,您需要声明和定义函数,然后编译您的应用程序。忽略内联、模板、lambdas 和其他魔法......,在编译函数时,该函数使用的所有其他函数的声明都需要存在 - 并且在链接时,编译的定义需要存在 - 都在程序之前开始运行。一旦程序开始运行,所有函数都已经准备就绪,可以调用了。

现在在 Lisp 中,情况有所不同。现在忽略编译 - 让我们考虑一个解释环境。如果你运行:

;; time 1
    (defun a () (b))
;; time 2
    (defun b () 123)
;; time 3
    (a)
    

在时间 1,您的程序没有任何功能。

第一个defun 然后创建一个函数(lambda () (b)),并将它与符号a 相关联。该函数包含对符号b 的引用,但此时它没有调用 ba 只会在 a 本身被调用时调用 b

因此,在时间 2,您的程序有一个函数,与符号 a 相关联,但尚未执行。

现在第二个defun 创建一个函数(lambda () 123),并将它与符号b 关联起来。

在时间 3,您的程序有两个函数,与符号 ab 相关联,但都没有被调用。

现在您拨打a。在执行过程中,它会查找与符号b 关联的函数,发现此时已经存在这样的函数,然后调用它。 b 执行并返回 123。

让我们添加更多代码:

    ;; time 4
        (defun b () 456)
    ;; time 5
        (a)

在时间 4 之后,新的 defun 创建一个返回 456 的函数,并将其与符号 b 相关联。这将替换引用 b 对返回 123 的函数的引用,该函数随后将被垃圾收集(或您实现的任何清除垃圾的操作)。

调用a(或更准确地说,符号a 的函数属性引用的lambda)现在将导致调用返回456 的函数。

如果相反,我们最初是这样写的:

;; time 1
    (defun a () (b))
;; time 2
    (a)
;; time 3
    (defun b () 123)

...这不会起作用,因为在我们调用a 的时间2 之后,它找不到与符号b 关联的函数,因此它将失败。

现在 - compileeval-when、优化和其他魔法可以做与我上面描述的不同的各种时髦的事情,但请确保您首先掌握这些基础知识,然后再担心更高级的东西。

  1. 函数仅在调用defun 时创建。 (解释器不会“在文件中向前看”。)
  2. 符号的属性之一是对函数的引用。 (函数本身实际上没有名称。)
  3. 多个符号可以引用同一个函数。 ((setf (symbol-function 'd) (symbol-function 'b)))
  4. 定义一个调用函数b(通俗地说)的函数a 是可以的,只要符号b 在调用a 时有一个关联函数。 (defunninga时不需要。)
  5. 一个符号可以在不同的时间引用不同的功能。这会影响任何“调用”该符号的函数。

宏的规则不同的(它们的扩展在“读取”时间之后是静态的),但许多原则保持不变(Lisp 不会“在文件中向前看”来查找他们)。了解 Lisp 程序比您可能习惯的大多数(较小的 ;-) )语言更具动态性和“运行时”。了解在 Lisp 程序执行期间发生了什么何时,管理宏扩展的规则将开始有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多