3.13 点状列表 (Dotted Lists)
调用 list
所构造的列表,这种列表精确地说称之为正规列表(properlist )。一个正规列表可以是 NIL
或是 cdr
是正规列表的 Cons 对象。也就是说,我们可以定义一个只对正规列表返回真的判断式: [3]
(defun proper-list? (x)
(or (null x)
(and (consp x)
(proper-list? (cdr x)))))
至目前为止,我们构造的列表都是正规列表。
然而, cons
不仅是构造列表。无论何时你需要一个具有两个字段 (field)的列表,你可以使用一个 Cons 对象。你能够使用 car
来参照第一个字段,用 cdr
来参照第二个字段。
> (setf pair (cons 'a 'b))
(A . B)
因为这个 Cons 对象不是一个正规列表,它用点状表示法来显示。在点状表示法,每个 Cons 对象的 car
与 cdr
由一个句点隔开来表示。这个 Cons 对象的结构展示在图 3.10 。
图3.10 一个成对的 Cons 对象 (A cons used as a pair)
一个非正规列表的 Cons 对象称之为点状列表 (dotted list)。这不是个好名字,因为非正规列表的 Cons 对象通常不是用来表示列表: (a . b)
只是一个有两部分的数据结构。
你也可以用点状表示法表示正规列表,但当 Lisp 显示一个正规列表时,它会使用普通的列表表示法:
> '(a . (b . (c . nil)))
(A B C)
顺道一提,注意列表由点状表示法与图 3.2 箱子表示法的关联性。
还有一个过渡形式 (intermediate form)的表示法,介于列表表示法及纯点状表示法之间,对于 cdr
是点状列表的 Cons 对象:
> (cons 'a (cons 'b (cons 'c 'd)))
(A B C . D)
图 3.11 一个点状列表 (A dotted list)
这样的 Cons 对象看起来像正规列表,除了最后一个 cdr 前面有一个句点。这个列表的结构展示在图 3.11 ; 注意它跟图3.2 是多么的相似。
所以实际上你可以这么表示列表 (a b)
,
(a . (b . nil))
(a . (b))
(a b . nil)
(a b)
虽然 Lisp 总是使用后面的形式,来显示这个列表。