6.1 全局函数 (Global Functions)

谓词 fboundp 告诉我们,是否有个函数的名字与给定的符号绑定。如果一个符号是函数的名字,则 symbol-function 会返回它:

  1. > (fboundp '+)
  2. T
  3. > (symbol-function '+)
  4. #<Compiled-function + 17BA4E>

可通过 symbol-function 给函数配置某个名字:

  1. (setf (symbol-function 'add2)
  2. #'(lambda (x) (+ x 2)))

新的全局函数可以这样定义,用起来和 defun 所定义的函数一样:

  1. > (add2 1)
  2. 3

实际上 defun 做了稍微多的工作,将某些像是

  1. (defun add2 (x) (+ x 2))

翻译成上述的 setf 表达式。使用 defun 让程序看起来更美观,并或多或少帮助了编译器,但严格来说,没有 defun 也能写程序。

通过把 defun 的第一个实参变成这种形式的列表 (setf f) ,你定义了当 setf 第一个实参是 f 的函数调用时,所会发生的事情。下面这对函数把 primo 定义成 car 的同义词:

  1. (defun primo (lst) (car lst))
  2. (defun (setf primo) (val lst)
  3. (setf (car lst) val))

在函数名是这种形式 (setf f) 的函数定义中,第一个实参代表新的数值,而剩余的实参代表了传给 f 的参数。

现在任何 primosetf ,会是上面后者的函数调用:

  1. > (let ((x (list 'a 'b 'c)))
  2. (setf (primo x) 480)
  3. x)
  4. (480 b c)

不需要为了定义 (setf primo) 而定义 primo ,但这样的定义通常是成对的。

由于字符串是 Lisp 表达式,没有理由它们不能出现在代码的主体。字符串本身是没有副作用的,除非它是最后一个表达式,否则不会造成任何差别。如果让字符串成为 defun 定义的函数主体的第一个表达式,

  1. (defun foo (x)
  2. "Implements an enhanced paradigm of diversity"
  3. x)

那么这个字符串会变成函数的文档字符串(documentation string)。要取得函数的文档字符串,可以通过调用 documentation 来取得:

  1. > (documentation 'foo 'function)
  2. "Implements an enhanced paradigm of diversity"