如果列表的第一个元素是一个符号,那么在求值时会检查该符号的函数单元格,并使用其中的内容替代原来的符号。如果该内容仍然是另一个符号,这个被称为 符号函数间接引用(symbol function indirection) 的过程会被重复执行,直到得到一个非符号对象为止。See 函数命名,了解更多关于符号函数间接引用的信息。 我们最终会得到一个非符号对象,它应当是一个函数或其他合适的对象。
更精确地说,此时我们应该得到以下对象之一:Lisp 函数(lambda 表达式)、字节码函数、原语函数、Lisp 宏、特殊形式,或是自动加载对象。这些类型将在后续章节中分别介绍。如果该对象不属于上述任何一种类型,Emacs 将会抛出一个 invalid-function(无效函数)错误。
下面的例子演示了符号间接引用的过程。我们使用 fset 来设置符号的函数单元格,并用 symbol-function 获取函数单元格的内容(see 访问函数单元内容)。具体来说:我们将符号 car 存入符号 first 的函数单元格,再将符号 first 存入符号 erste 的函数单元格。
;; Build this function cell linkage:
;; ------------- ----- ------- -------
;; | #<subr car> | <-- | car | <-- | first | <-- | erste |
;; ------------- ----- ------- -------
(symbol-function 'car)
⇒ #<subr car>
(fset 'first 'car)
⇒ car
(fset 'erste 'first)
⇒ first
(erste '(1 2 3)) ; Call the function referenced by erste.
⇒ 1
与之相反,下面这个示例在调用函数时不会发生任何符号函数间接引用,因为列表的第一个元素是一个匿名 Lisp 函数,而不是符号。
((lambda (arg) (erste arg))
'(1 2 3))
⇒ 1
执行函数本身会对其函数体进行求值;在调用 erste 时,这一过程仍然会触发符号函数间接引用。
这种写法很少使用,现已被废弃。你应当改用下面的写法:
(funcall (lambda (arg) (erste arg))
'(1 2 3))
or just
(let ((arg '(1 2 3))) (erste arg))
内置函数 indirect-function 提供了一种便捷的方式,可显式地执行符号函数间接引用操作。
该函数返回 function 作为函数的实际指向(语义)。若 function 是一个符号,则函数会先查找该符号的函数定义,并以该定义值为起点重新执行上述查找过程;若 function 不是符号,则直接返回 function 本身。
如果最终查找的符号未绑定函数(unbound),该函数会返回 nil。
该函数还有第二个可选参数,但此参数已被废弃(obsolete),且无任何实际作用。
以下是如何用 Lisp 语言自定义实现 indirect-function 的示例:
(defun indirect-function (function)
(if (and function
(symbolp function))
(indirect-function (symbol-function function))
function))