defun宏在lisp中是如何实现的?

How is the defun macro implemented in lisp?

我想了解有关 lisp 宏的更多信息,我想创建 defun 宏的简单实现。 我也对 lisp 在所有实现中的源代码感兴趣。

您可以轻松检查您的特定 CL 实现方式,defun 由 运行

实现
(macroexpand '(defun add2 (x) (+ x 2)))

SBCL 上扩展为:

(PROGN
  (EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'ADD2 NIL T))
  (SB-IMPL::%DEFUN 'ADD2
                   (SB-INT:NAMED-LAMBDA ADD2
                       (X)
                     (BLOCK ADD2 (+ X 2)))
                   (SB-C:SOURCE-LOCATION)))
T

要查看实现的特定源代码,我将使用(在 Emacs 上)M-. 键绑定,然后我将编写 defun 并按回车键。然后Emacs会获取到源码:

(sb!xc:defmacro defun (&environment env name lambda-list &body body)
  #!+sb-doc
  "Define a function at top level."
[...]

我不打算粘贴整个宏,因为它太长了。如果您不使用 Emacs,您可以尝试在存储库中搜索,因为大多数实现都是开源的。

顺便说一句 defun 并没有那么特别。您可以使用 setf-inf a symbol-function 到 lambda 来实现其中的大部分内容。例如:

(setf (symbol-function 'ADD3) #'(lambda (x) (+ x 3)))
; => #<FUNCTION (LAMBDA (X)) {1006E94EBB}>
(add3 4)
; => 7

这是一个棘手的问题,因为 bootstrapping: defun does a lot of things (iow, calls a lot of functions), but to define those functions one needs a working defun. Thus there are three(3!) definitions of defun in clisp/src/init.lisp: 在第

  1. 228
  2. 1789
  3. 1946

defun 的最基本定义可能是这样的:

(defmacro defun (fname lambda-list &rest body)
  `(setf (fdefinition ',fname)
         (lambda ,lambda-list 
           (block ,fname ,@body))))

其实这是CLISP中第一个defun的定义(第228行),只是那个时候还没有defmacro and no backquote ,所以实际代码看起来更丑陋。

另见 我在其中讨论 defun 的宏展开。