6.2 局部函数 (Local Functions)

通过 defunsymbol-function 搭配 setf 定义的函数是全局函数。你可以像存取全局变量那样,在任何地方存取它们。定义局部函数也是有可能的,局部函数和局部变量一样,只在某些上下文内可以访问。

局部函数可以使用 labels 来定义,它是一种像是给函数使用的 let 。它的第一个实参是一个新局部函数的定义列表,而不是一个变量规格说明的列表。列表中的元素为如下形式:

  1. (name parameters . body)

labels 表达式剩余的部份,调用 name 就等于调用 (lambda parameters . body)

  1. > (labels ((add10 (x) (+ x 10))
  2. (consa (x) (cons 'a x)))
  3. (consa (add10 3)))
  4. (A . 13)

labelslet 的类比在一个方面上被打破了。由 labels 表达式所定义的局部函数,可以被其他任何在此定义的函数引用,包括自己。所以这样定义一个递归的局部函数是可能的:

  1. > (labels ((len (lst)
  2. (if (null lst)
  3. 0
  4. (+ (len (cdr lst)) 1))))
  5. (len '(a b c)))
  6. 3

5.2 节展示了 let 表达式如何被理解成函数调用。 do 表达式同样可以被解释成调用递归函数。这样形式的 do :

  1. (do ((x a (b x))
  2. (y c (d y)))
  3. ((test x y) (z x y))
  4. (f x y))

等同于

  1. (labels ((rec (x y)
  2. (cond ((test x y)
  3. (z x y))
  4. (t
  5. (f x y)
  6. (rec (b x) (d y))))))
  7. (rec a c))

这个模型可以用来解决,任何你对于 do 行为仍有疑惑的问题。