我在Scheme(使用DrRacket)中获得了一项任务,要求我使用cons从组件1,2,3和()创建列表((1 2)3)
我设法得到((1 2).3)使用:
(cons (cons '1 (cons '2 '())) '3)
Run Code Online (Sandbox Code Playgroud)
但是,那是一回事吗?
注意:这是从我对Recursive range in Lisp 添加一个句点的回答中提取出来的? 问题是不同的(所以不是重复的),但是关于如何从 cons 单元构造列表以及如何打印列表的背景解释是相同的。结局有点不同。
方案A列表要么是空列表()(也称为nil在一些的Lisp)或cons单元,其car(也称为first)是与所述列表的一个元件,其cdr(也称为rest)或者是列表的其余部分(即,另一个列表),或终止列表的原子。常规终止符是空列表();被终止的列表()被称为“适当的列表”。由任何其他原子终止的列表称为“不正确的列表”。该列表(1 2 3 4 5)包含元素 1、2、3、4 和 5,并以 结尾()。你可以构造它
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 ())))))
Run Code Online (Sandbox Code Playgroud)
现在,当系统打印一个 cons 单元格时,一般情况是通过
(car . cdr)
Run Code Online (Sandbox Code Playgroud)
例如,结果(cons 1 2)打印为
(1 . 2)
Run Code Online (Sandbox Code Playgroud)
由于列表是由 cons 单元构建的,因此您也可以对列表使用此表示法:
'(1 2 3 4 5) ; ==
'(1 . (2 . (3 . (4 . (5 . ())))))
Run Code Online (Sandbox Code Playgroud)
不过,这相当笨重,所以大多数 lisps(我所知道的所有内容)都有一个打印 cons 单元格的特殊情况:如果cdr是一个列表(另一个 cons 单元格或()),则不要打印.,并且不要打印周围的括号cdr(否则它会具有,因为它是一个列表)。
有了对列表和 cons 单元格的理解,我们就可以考虑具体的情况((1 2) 3)和((1 2) . 3). 让我们将其中的每一个分解为 cons 单元格。
((1 2) 3) ; ==
((1 . (2 . ()) . (3 . ())) ; ==
(cons (cons 1 (cons 2 ()) (cons 3 ()))
Run Code Online (Sandbox Code Playgroud)
((1 2) . 3) ; ==
((1 . (2 . ())) . 3) ; ==
(cons (cons 1 (cons 2 ())) 3)
Run Code Online (Sandbox Code Playgroud)
在每种情况下的最后几行是不同的,所以((1 2) 3)并((1 2) . 3)是不一样的。