Rob*_*ert 1 lisp common-lisp racket
我发现顶级声明顺序似乎并不重要。是否有关于该主题的任何文档?我不太明白。
显示函数可以在未定义的情况下被调用的示例
#lang racket
(define (function-defined-early)
(function-defined-later))
(define (function-defined-later)
1)
(function-defined-early)
> 1
Run Code Online (Sandbox Code Playgroud)
;; Common Lisp
(defun function-defined-early ()
(function-defined-later))
(defun function-defined-later ()
1)
(print (function-defined-early))
> 1
Run Code Online (Sandbox Code Playgroud)
对于 Common Lisp,它有点复杂,因为实现可以使用解释代码、编译代码和高度优化的编译代码。
简单编译代码中的函数调用
例如,SBCL 默认编译所有代码。即使是通过 read-eval-print-loop 输入的代码:
* (defun foo (a) (bar (1+ a)))
; in: DEFUN FOO
; (BAR (1+ A))
;
; caught STYLE-WARNING:
; undefined function: COMMON-LISP-USER::BAR
;
; compilation unit finished
; Undefined function:
; BAR
; caught 1 STYLE-WARNING condition
FOO
Run Code Online (Sandbox Code Playgroud)
由于函数被立即编译,编译器会发现有一个未定义的函数。但这只是警告而不是错误。生成的代码将调用 function bar,即使它是稍后定义的。
符号具有函数值
在 Common Lisp 中,全局函数的函数对象被注册为符号。
* (fboundp 'foo)
T
* (fboundp 'bar)
NIL
Run Code Online (Sandbox Code Playgroud)
bar没有函数定义。如果我们稍后为 定义一个函数bar,那么我们之前定义的函数的代码foo将调用这个新函数。
它是如何工作的?中的代码在foo运行时进行查找以获取符号的函数值bar并调用该函数。
因此,我们也可以重新定义bar并foo调用新函数。
后期绑定
对函数进行运行时查找的概念通常称为后期绑定。这是 1960 年代为 Lisp 描述的。
因此调用全局函数
(bar 1 a)
Run Code Online (Sandbox Code Playgroud)
在概念上基本上与
(if (fbound 'bar)
(funcall (symbol-function 'bar) 1 a)
(error "undefined function BAR"))
Run Code Online (Sandbox Code Playgroud)
请记住,这是一个简单的模型,实际上 Common Lisp文件编译器可能会使用更积极的优化(如内联),其中没有运行时查找。
函数形式的评估
Common Lisp 标准在Conses as Forms 中说:
如果运算符既不是特殊运算符也不是宏名称,则假定它是函数名称(即使没有定义这样的函数)。
| 归档时间: |
|
| 查看次数: |
240 次 |
| 最近记录: |