在 SBCL REPL 中,为什么输入 (nil . nil) 计算结果为 (nil) 而不仅仅是 nil?
如果空列表是 cons 单元的两个“元素”都为零的列表,为什么它们不一样?
我对此的假设是 SBCL 做出以下评估:
(car '()) => nil
(cdr '()) => nil
(car '(nil . nil)) => nil
(cdr '(nil . nil)) => nil
然而:
'() => nil
'(nil . nil) => (nil)
car
作为参数,则
cdr
和 nil
返回 nil
。让我们先了解一下 nil
这个词,看看您实际上正在看什么值。
(car '()) == '()
(cdr '()) => nil
car
和 cdr
得到一个空列表,所以我们返回 nil
,或 ()
。
(car '(nil . nil)) => nil
(cdr '(nil . nil)) => nil
现在,
(nil . nil)
是(() . ())
。也就是说,这是一个 cons cell,其 car 和 cdr 都是nil
。
当 cons 单元格末尾有
. ()
时,我们可以通过省略尾随的 nil
来在符号上缩短它。这只是为了符号方便,所以根据我们的符号,(() . ())
可以写成(())
或(nil)
。请注意,这不会改变该值。最明确的写法仍然是(() . ())
,但为了便于阅读,我们也可以写得更短。
如果空列表是 cons 单元的两个“元素”都为零的列表,为什么它们不一样?这是不正确的。空列表根本不是 cons 单元格。空列表是原子
nil
。它是一个符号,就像'foo
或
'pizza
或'common-lisp
一样。这只是我们选择用于此目的的一个符号。但是nil
没有有汽车或CDR单元。碰巧的是,让
(car nil)
和 (cdr nil)
成为 nil
作为算法的极端情况通常很方便,因此 函数
car
和 cdr
在 nil
上有特殊的行为。但 nil
不是一个缺点细胞。
> (consp nil)
nil
> (consp '())
nil
> (consp '(1 . 2))
T
根据系统类LIST
,list
类型可以描述为
类型
cons
和 null
形成类型列表的详尽分区。
因此 Common Lisp 中的list 被定义为“cons cell 或特殊值
nil
”。值得注意的是,nil
本身并不是一个缺点细胞。