6.8 编译 (Compilation)

Common Lisp 函数可以独立被编译或挨个文件编译。如果你只是在顶层输入一个 defun 表达式:

  1. > (defun foo (x) (+ x 1))
  2. FOO

许多实现会创建一个直译的函数(interpreted function)。你可以将函数传给 compiled-function-p 来检查一个函数是否有被编译:

  1. > (compiled-function-p #'foo)
  2. NIL

若你将 foo 函数名传给 compile :

  1. > (compile 'foo)
  2. FOO

则这个函数会被编译,而直译的定义会被编译出来的取代。编译与直译函数的行为一样,只不过对 compiled-function-p 来说不一样。

你可以把列表作为参数传给 compile 。这种 compile 的用法在 161 页 (译注: 10.1 小节)。

有一种函数你不能作为参数传给 compile :一个像是 stamp 或是 reset 这种,在顶层明确使用词法上下文输入的函数 (即 let ) [3] 在一个文件里面定义这些函数,接着编译然后载入文件是可以的。这么限制直译的代码的是实作的原因,而不是因为在词法上下文里明确定义函数有什么问题。

通常要编译 Lisp 代码不是挨个函数编译,而是使用 compile-file 编译整个文件。这个函数接受一个文件名,并创建一个原始码的编译版本 ── 通常会有同样的名称,但不同的扩展名。当编译过的文件被载入时, compiled-function-p 应给所有定义在文件内的函数返回真。

当一个函数包含在另一个函数内时,包含它的函数会被编译,而且内部的函数也会被编译。所以 make-adder (108 页)被编译时,它会返回编译的函数:

  1. > (compile 'make-adder)
  2. MAKE-ADDER
  3. > (compiled-function-p (make-adder 2))
  4. T