我在 Scheme(使用 DrRacket)中获得了一项任务,要求我使用 cons 从组件 1、2、3 和 () 创建列表 ((1 2) 3)
我已经设法达到 ((1 2) . 3) 使用:
(cons (cons '1 (cons '2 '())) '3)
然而,这是同一回事吗?
注意:这是从我对Recursive range in Lisp 添加句点的回答中蚕食的? 问题是不同的(所以不是重复的),但是关于如何从 cons 单元构造列表以及如何打印它们的背景说明是相同的。结局有点不同。
Scheme 中的列表要么是空列表(在某些 Lisps 中()
也称为),要么是一个 cons 单元格,其(也称为)是列表的一个元素,其(也称为)是列表的其余部分(即,另一个列表),或终止列表的原子。常规的终止符是空列表;被终止的列表被称为“正确的列表”。由任何其他原子终止的列表称为“不适当的列表”。该列表包含元素 1、2、3、4 和 5,并以 . 结尾。您可以通过以下方式构建它nil
car
first
cdr
rest
()
()
(1 2 3 4 5)
()
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 ())))))
现在,当系统打印一个 cons 单元格时,一般情况是通过
(car . cdr)
例如,结果(cons 1 2)
打印为
(1 . 2)
由于列表是由 cons 单元格构建的,因此您也可以将这种表示法用于列表:
'(1 2 3 4 5) ; ==
'(1 . (2 . (3 . (4 . (5 . ())))))
不过,这相当笨拙,所以大多数 lisps(据我所知)都有一个打印 cons 单元格的特殊情况:如果cdr
是一个列表(另一个 cons 单元格或()
),那么不要打印.
,也不要打印周围的括号cdr
(否则它会有,因为它是一个列表)。
有了对列表和 cons 单元的这种理解,我们就可以考虑具体情况((1 2) 3)
和((1 2) . 3)
. 让我们将这些分解为缺点单元格。
((1 2) 3) ; ==
((1 . (2 . ()) . (3 . ())) ; ==
(cons (cons 1 (cons 2 ()) (cons 3 ()))
((1 2) . 3) ; ==
((1 . (2 . ())) . 3) ; ==
(cons (cons 1 (cons 2 ())) 3)
每种情况下的最后几行都是不同的,因此((1 2) 3)
也不((1 2) . 3)
相同。
不,正如其他人所提到的,((1 2) 3)
与 相同((1 2) 3 . ())
,当然您可以使用 (cons '3 '())
而不是文字来构建'3
:
(cons (cons '1 (cons '2 '())) (cons '3 '()))
不。
的“顶级”元素(A . B)
是单个cons
单元格:(cons A B)
. car
缺点单元格的是A
和cdr
是B
。在正确列表中,cdr
元素始终()
是非空正确列表或其他非空正确列表。
相比之下,(A B)
是一个包含两个元素的列表,每个元素都有一个 cons 单元格:(cons A (cons B ()))
它们是不同的:
(equal? '((1 2) 3) '((1 2) . 3))
=> #f
因为'((1 2) 3)
等价于这个:
(cons (cons 1 (cons 2 '())) (cons 3 '()))
而'((1 2) . 3)
等价于:
(cons (cons 1 (cons 2 '())) 3)
所以你看,它们有不同的cons
细胞结构。第一个版本是正确的列表- 意思是:它以空列表结尾'()
,而第二个版本以 结尾3
,使其成为不正确的列表。
它们不一样。((1 2) 3)
是一个'()
终止列表,而((1 2) . 3)
只是一个“对”。尝试替换 '3
为(cons '3 '())