5

我意识到这是一个完全 n00b 的问题,但我很好奇,我想我可能会在这里得到比其他任何地方更好的解释。这是一个列表(我正在使用 Dr. Scheme)

> (list 1 2 3)
(1 2 3)

我认为这只是糖:

> (cons 1 (cons 2 (cons 3 null)))
(1 2 3)

另一方面,这会做其他事情:

> (cons 1 (cons 2 3))
(1 2 . 3)

我的问题是,为什么会有不同?在列表末尾要求 null 有什么意义?

4

4 回答 4

11

列表的定义是递归的。

 1. The null list (empty list) is a list
 2. A list is made up of an item cons a list

所以这些是列表:

1. null  => ()  --read as empty list
2. cons 3 null  =>  (3)
3. cons2 (cons 3 null)  => (2, 3) 

您给出的最后一个示例 cons 2 3 不符合此列表定义,因此它不是列表。那就是 cons 接受一个项目和一个列表。3 不是列表。

于 2009-11-06T19:37:07.000 回答
2

cons将一个新元素添加到列表的开头,所以当你写的时候你在做什么:

(cons 1 (cons 2 (cons 3 null)))

递归地将项目添加到一个不断增长的列表中,从 开始null,它被定义为空列表 ()。当您打电话时,(cons 2 3)您不是从空列表开始,因此不要通过在其开头附加 2 来构造列表。

于 2009-11-06T19:38:00.547 回答
2

Lisp,包括 Scheme,是动态类型的,“lisp 方式”是在单个数据结构上拥有许多功能,而不是针对不同任务使用不同的数据结构。

所以问题是“在列表末尾要求 null 有什么意义?” 不太适合问。

cons函数不需要您提供cons对象或nil作为其第二个参数。如果第二个参数不是cons对象或nil,那么您会得到一对而不是列表,并且运行时不会使用列表表示法而是使用点来打印它。

所以如果你想构造一个形状像列表的东西,那么给cons一个列表作为它的第二个参数。如果你想构造别的东西,那就给cons别的东西作为它的第二个参数。

如果您想要一个其中恰好有两个值的数据结构,则对很有用。使用一对,你不需要在最后的 nil 来标记它的长度,所以它更有效一些。对列表是键值映射的简单实现;common lisp 具有支持此类属性列表的功能,作为其标准库的一部分。

所以真正的问题是“为什么你可以用相同的函数构造对和列表cons?”,而答案是“当你只需要一个数据结构时,为什么还要有两个数据结构?”

于 2009-11-06T20:03:41.317 回答
0

cons 语句用于分配 car 为 obj1 且 cdr 为 obj2 的对

(cons obj1 obj2)

因此,有必要以 null 结束 cons 语句,以便我们知道我们是列表的末尾。

> (cons 1 (cons 2 3))
(1 2 . 3)

在该示例中,cdr 将是一对 <2,3>,其中 2 是汽车,3 是 cdr。不一样:

(list 1 2 3)
于 2009-11-06T19:40:22.180 回答