Cons 对象提供了一个方便的表示法,来表示任何类型的对象。一个 Cons 对象里的一对指针,可以指向任何类型的对象,包括 Cons 对象本身。它利用到我们之后可以用 cons
来构造列表的可能性。
我们往往不会把列表想成是成对的,但它们可以这样被定义。任何非空的列表,都可以被视为一对由列表第一个元素及列表其余元素所组成的列表。 Lisp 列表体现了这个概念。我们使用 Cons 的一半来指向列表的第一个元素,然后用另一半指向列表其余的元素(可能是别的 Cons 或 nil
)。 Lisp 的惯例是使用 car
代表列表的第一个元素,而用 cdr
代表列表的其余的元素。所以现在 car
是列表的第一个元素的同义词,而 cdr
是列表的其余的元素的同义词。列表不是不同的对象,而是像 Cons 这样的方式连结起来。
当我们想在 上面建立东西时,
图 3.1 一个元素的列表
> (car x)
A
NIL
当我们构造一个多元素的列表时,我们得到一串 Cons (a chain of conses):
产生的结构见图 3.2。现在当我们想得到列表的 cdr
时,它是一个两个元素的列表。
图 3.2 三个元素的列表
> (cdr y)
在一个有多个元素的列表中, 指针让你取得元素,而 cdr
让你取得列表内其余的东西。
当这种情况发生时,它的结构如图 3.3 所示;第二个 Cons 的 car
指针也指向一个列表:
> (car (cdr z))
(B C)
图 3.3 嵌套列表
前两个我们构造的列表都有三个元素;只不过 z
列表的第二个元素也刚好是一个列表。像这样的列表称为嵌套列表,而像 y
这样的列表称之为平坦列表 (flatlist)。
如果参数是一个 Cons 对象,函数 consp
返回真。所以我们可以这样定义 listp
:
注意, nil
既是一个原子,也是一个列表。