gpt4 book ai didi

macros - 控制Common Lisp中宏扩展顺序的规则

转载 作者:太空宇宙 更新时间:2023-11-03 18:58:34 27 4
gpt4 key购买 nike

defmacrohttp://clhs.lisp.se/Body/m_defmac.htm有文档记录,但文档并不完全清楚事情发生的确切时间通过对Clisp的实验,我发现了以下内容(假设所有宏和函数都是在顶层定义的):
直接的顶层代码只能调用前面定义的宏和函数。
宏或函数中的代码,或由宏生成的代码,可以调用它喜欢的任何函数,包括稍后定义的函数(正如支持相互递归的需要所期望的那样)。
宏中的代码只能调用比第一个宏的调用位置更早定义的宏。
由宏生成的代码可以调用稍后定义的宏。
是Clisp只是在遵循规范,还是在这方面实现之间存在任何差异?
确切的一套规则及其背后的原理是否在任何地方都有记录?

最佳答案

你问的是宏扩展,但我想先澄清函数是如何处理的。
注意何时调用和定义实际发生在第二点中,您说函数中的代码可以调用稍后定义的函数严格来说这不是真的。
在C++语言中,你可以声明和定义函数,然后编译你的应用程序。忽略内联、模板、lambdas和其他魔术…,当编译一个函数时,该函数使用的所有其他函数的声明都必须存在-并且在链接时,编译的定义必须存在-所有这些都必须在程序开始运行之前存在一旦程序开始运行,所有函数都已经准备好并准备好被调用。
现在在Lisp中,情况不同了。暂时忽略编译-让我们考虑一下解释环境如果你跑步:

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

在时间1,你的程序没有任何功能。
第一个 defun然后创建一个函数 (lambda () (b)),并将其与符号 a关联。此函数包含对符号 b的引用,但此时它不调用 b a只在调用 b自身时调用 a
所以,在时间2,你的程序有一个与符号相关联的函数,但是它还没有被执行。
现在,第二个 a创建一个函数 defun,并将其与符号 (lambda () 123)关联。
在时间3,您的程序有两个函数,与符号 ba相关,但这两个函数都尚未调用。
现在您可以调用 b在执行过程中,它查找与符号 a相关联的函数,发现这样的函数在这个时间点已经存在,并调用它。 b执行并返回123。
让我们添加更多代码:
;时间4
德丰B(456)
;时间5
(一)
在时间4之后,一个新的 b创建一个返回456的函数,并将其与符号 defun关联这将替换对返回123的函数的引用 b,该函数随后将被垃圾回收(或者无论您的实现如何清除垃圾)。
调用 b(或者更正确地说,符号 a的function属性引用的lambda)现在将导致调用返回456的函数。
相反,如果我们最初写的是:
;; time 1
(defun a () (b))
;; time 2
(a)
;; time 3
(defun b () 123)

... 这不起作用,因为在调用 a的时间2之后,它找不到与符号 a关联的函数,因此它将失败。
现在- bcompile,优化和其他魔法可以做各种不同于我上面描述的有趣的事情,但是在担心更高级的东西之前,首先要确保你掌握了这些基本知识。
函数仅在调用 eval-when时创建(解释器不会“在文件中向前看”。)
符号的属性之一是对函数的引用(函数本身实际上没有名称。)
多个符号可以引用同一个函数( defun
定义一个调用函数 (setf (symbol-function 'd) (symbol-function 'b))(通俗地说)的函数 a是可以的,只要符号 b在调用 b时有关联的函数(在 aning defun时不需要)
符号可以在不同的时间引用不同的功能这会影响“调用”该符号的任何函数。
宏的规则是不同的(它们的扩展在“读取”时间之后是静态的),但是许多原则保持不变(Lisp不会“在文件中向前看”来查找它们)要知道,Lisp程序比您可能习惯的大多数(较小的;-)语言更具动态性和“运行时”性了解在执行lisp程序时会发生什么,并且控制宏扩展的规则将开始有意义。

关于macros - 控制Common Lisp中宏扩展顺序的规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40974039/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com