Работа со списками без 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))
и т. Д.