为什么我们需要`nil`?

时间:2012-01-30 09:55:11

标签: lisp scheme s-expression

我不明白为什么我们需要nil [1]到cons一个序列(所谓的正确列表)的项目。在我看来,我们可以通过单独使用所谓的不正确列表(cons - ed对而没有结束nil)来实现相同的目标。由于Lisps [2]已经提供了一个原始过程来区分pair?和一个原子(某些实现甚至提供atom?),因此在列表上定义过程时,例如length ,我可以用虚线对做同样的事情,如下所示:

(define len
  (lambda (l)
    (cond ((pair? l) (+ 1 (len (cdr l))))
          (else 1) ) ) )

很明显,我们可以将此程序应用于'(1 . (2 . 3))这样的不正确的列表,以获得预期的答案3,而不是传统的(length '(1 2 3))

我希望听到任何捍卫nil必要性的意见。提前谢谢。

[1]让我们忽略nil / NIL'()()之间的争论。

[2]这意味着Lisp系列语言。

2 个答案:

答案 0 :(得分:20)

使用没有nil(或'())的列表就像在没有零的情况下进行算术一样。仅使用没有nil的对,我们如何表示空列表或单个列表'(1)

情况变得更糟:因为列表不必是原子列表,但可以包含其他列表,我们如何表示嵌套列表'(1 2 (3 4))?如果我们进行以下转换:

'(3 4) => '(3 . 4)
'(1 2 x) => '(1 . (2 . x)) == '(1 2 . x)

我们得到:

'(1 2 (3 4)) => '(1 . (2 . (3 . 4))) == '(1 2 3 . 4)

但是:

'(1 2 3 4) => '(1 . (2 . (3 . 4))) == '(1 2 3 . 4)

因此,仅使用对而不使用nil构建列表会阻止我们区分嵌套列表结构和平面列表,至少在列表的末尾。您仍然可以将嵌套列表作为除最后一个元素之外的任何元素包含在内,因此现在对列表的元素可能存在奇怪且任意的限制。

理论上,正确的列表是一个归纳定义的数据类型:列表是空列表,或者它有一个first元素,可以是任何东西,而rest,是< em>总是以相同方式定义的另一个列表。拿走空列表,现在你有一个数据类型,其中rest 可能是另一个列表,或者它可能是列表的最后一个元素。除非将其传递给pair?,否则我们无法判断,这会导致上面嵌套列表出现问题。保持nil让我们拥有任何我们喜欢的列表元素,并允许我们区分1'(1)'((1))等等。

答案 1 :(得分:1)

你需要它代表“没什么”。