为什么 (nil . nil) 在 SBCL 中计算结果为 (nil) 而不是 nil?

Gal*_*ite 2 lisp sbcl common-lisp

在 SBCL REPL 中,为什么输入的'(nil . nil)计算结果为(nil)而不仅仅是nil

如果空列表是 cons 单元的两个“元素”所在的列表nil,为什么它们不一样?

我对此的假设是 SBCL 做出以下评估:

(car '()) => nil
(cdr '()) => nil
(car '(nil . nil)) => nil
(cdr '(nil . nil)) => nil
Run Code Online (Sandbox Code Playgroud)

但是:

'() => nil
'(nil . nil) => (nil)
Run Code Online (Sandbox Code Playgroud)

Sil*_*olo 7

car如果作为参数给出cdr则返回。让我们先了解一下这个词,看看您实际看到的值是什么。nilnilnil

(car '()) == '()
(cdr '()) => nil
Run Code Online (Sandbox Code Playgroud)

carcdr得到一个空列表,所以我们返回nil, 或()

(car '(nil . nil)) => nil
(cdr '(nil . nil)) => nil
Run Code Online (Sandbox Code Playgroud)

现在(nil . nil)(() . ())。也就是说,它是一个 cons cell,其 car 和 cdr 均为nil

. ()当cons 单元格末尾有 a 时,我们可以通过省略尾随的 来在符号上缩短它nil。这只是符号上的方便,所以通过我们的符号(() . ())可以写成(()), 或(nil)。请注意,这确实改变该值。最明确的书写方式仍然是(() . ()),但我们也可以将其写得更短以提高可读性。

如果一个空列表是 cons 单元的两个“元素”都为零的列表,为什么它们不一样?

这是不正确的。空列表根本不是缺点单元格。空列表是原子nil。它是一个符号,就像'fooor'pizza或 一样'common-lisp。这只是我们选择用于此目的的一个符号。但nil没有汽车或 cdr 细胞碰巧的是,让(car nil)(cdr nil)benil作为算法的极端情况通常很方便,因此函数 carcdr在 上有特殊的行为nil。但nil不是一个缺点细胞。

> (consp nil)
nil
> (consp '())
nil
> (consp '(1 . 2))
T
Run Code Online (Sandbox Code Playgroud)

根据系统类别LISTlist类型可以描述为

类型consnull形成类型列表的详尽分区。

因此Common Lisp 中的列表被定义为“cons 单元格或特殊值nil”。值得注意的是,nil它本身并不是一个缺点细胞。