Зачем нам "ноль"? - PullRequest
       47

Зачем нам "ноль"?

4 голосов
/ 30 января 2012

Я не понимаю, зачем нам nil [1], когда cons последовательность (так называемый правильный список) предметов.Мне кажется, мы можем достичь той же цели, используя только так называемый неправильный список (пары cons без конца 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 ]

20 голосов
/ 30 января 2012

Работа со списками без 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, который всегда другой список, определенный таким же образом. Уберите пустой список, и теперь у вас есть тип данных, где rest может быть другим списком или может быть последним элементом списка. Мы не можем сказать, кроме как, передав его pair?, что приводит к проблеме с вложенным листингом выше. Сохранение nil позволяет нам иметь в качестве элементов списка все, что нам нравится, и позволяет различать 1, '(1), '((1)) и т. Д.

1 голос
/ 31 января 2012

Вам нужно это, чтобы представлять "Ничто".

...