3.13 点状列表 (Dotted Lists)

调用 list 所构造的列表,这种列表精确地说称之为正规列表(properlist )。一个正规列表可以是 NIL 或是 cdr 是正规列表的 Cons 对象。也就是说,我们可以定义一个只对正规列表返回真的判断式: [3]

  1. (defun proper-list? (x)
  2. (or (null x)
  3. (and (consp x)
  4. (proper-list? (cdr x)))))

至目前为止,我们构造的列表都是正规列表。

然而, cons 不仅是构造列表。无论何时你需要一个具有两个字段 (field)的列表,你可以使用一个 Cons 对象。你能够使用 car 来参照第一个字段,用 cdr 来参照第二个字段。

  1. > (setf pair (cons 'a 'b))
  2. (A . B)

因为这个 Cons 对象不是一个正规列表,它用点状表示法来显示。在点状表示法,每个 Cons 对象的 carcdr 由一个句点隔开来表示。这个 Cons 对象的结构展示在图 3.10 。

../_images/Figure-3.10.png

图3.10 一个成对的 Cons 对象 (A cons used as a pair)

一个非正规列表的 Cons 对象称之为点状列表 (dotted list)。这不是个好名字,因为非正规列表的 Cons 对象通常不是用来表示列表: (a . b) 只是一个有两部分的数据结构。

你也可以用点状表示法表示正规列表,但当 Lisp 显示一个正规列表时,它会使用普通的列表表示法:

  1. > '(a . (b . (c . nil)))
  2. (A B C)

顺道一提,注意列表由点状表示法与图 3.2 箱子表示法的关联性。

还有一个过渡形式 (intermediate form)的表示法,介于列表表示法及纯点状表示法之间,对于 cdr 是点状列表的 Cons 对象:

  1. > (cons 'a (cons 'b (cons 'c 'd)))
  2. (A B C . D)

../_images/Figure-3.11.png

图 3.11 一个点状列表 (A dotted list)

这样的 Cons 对象看起来像正规列表,除了最后一个 cdr 前面有一个句点。这个列表的结构展示在图 3.11 ; 注意它跟图3.2 是多么的相似。

所以实际上你可以这么表示列表 (a b)

  1. (a . (b . nil))
  2. (a . (b))
  3. (a b . nil)
  4. (a b)

虽然 Lisp 总是使用后面的形式,来显示这个列表。