Пустой список в Lisp построен из ячейки минусов?

Я пытаюсь эмулировать Lisp-подобный список в JavaScript (просто упражнение без практической причины), но я изо всех сил пытаюсь понять, как лучше всего представлять пустой список.

- пустой список просто nil значение или оно под капотом хранится в ячейке минусов?

Я:

(car '())
NIL
(cdr '())
NIL

но пустой список наверняка не может быть (cons nil nil), потому что это было бы неотличимо от списка, хранящего один nil. Он должен был бы хранить некоторые другие специальные значение.

С другой стороны, если пустой список не строится из минусов клетки, кажется, невозможно иметь последовательный интерфейс высокого уровня для добавления одного значения к существующему списку. Функция типа:

(defun append-value (list value) ...

изменить свой аргумент, но только если это не пустой список, который выглядит некрасиво.

4 ответов


пустой список-это просто nil символ (а символы, по определению, не являются минусами). car и cdr определены для возврата nil Если дано nil.

Что касается функций list-mutation, они возвращают значение, которое вы должны переназначить своей переменной. Например, посмотрите на спецификацию для nreverse функция: он может изменить данный список или нет, и вы должны использовать возвращаемое значение, а не полагаться на него для изменения на месте.

даже nconc, квинтэссенция деструктивной функции добавления, работает таким образом: ее возвращаемое значение-это добавленный список, который вы должны использовать. Это и указано для изменения заданных списков (кроме последнего) на месте, но если вы дадите его nil в качестве первого аргумента, он не может изменить, поэтому вам все равно придется использовать возвращаемое значение.


Верьте или нет, это на самом деле религиозный вопрос.

есть диалекты, которые люди осмеливаются называть какой-то шепелявостью, в которой пустые списки являются conses или агрегатными объектами какого-то рода, а не просто атомом, как nil.

например, в" MatzLisp " (более известный как Ruby) списки на самом деле массивы.

в NewLisp списки-это контейнеры: объекты типа list, которые содержат связанный список элементов, поэтому пустые списки пустой контейнер. [ссылка].

в языках Lisp, которые не являются впечатляющими кластерами, пустые списки-это атомы, а непустые списки-двоичные ячейки с полем, которое содержит первый элемент, и другое поле, которое содержит остальную часть списка. Списки могут совместно использовать суффиксы. Учитывая список, как (1 2 3) можно использовать cons создать (a 1 2 3) и (b c 1 2 3) оба из которых разделяют хранения (1 2 3).

(в ANSI Common Lisp, пустой список atom () это тот же объект, что и символ nil, который оценивает сам по себе, а также служит логическим false. В Схеме,() не является символом и отличается от логического false


NIL несколько странный зверь В общем шепелявит, потому что

  • это символ (что означает, что symbolp возвращает T)
  • список
  • не является ячейкой минусов (consp возвращает NIL)
  • вы можете взять CAR и CDR все равно

обратите внимание, что причины этого, вероятно, также исторические, и вы не должны думать, что это единственное разумное решение. Другие диалекты Lisp сделаны различных вариантов.


попробуйте с помощью интерпретатора Lisp:

(eq nil '())
=> t

несколько операций являются специальными, чтобы делать неортогональные (или даже любопытные :-) вещи при работе на nil / пустой список. Поведение car и cdr вы расследовали одну из этих вещей.

идентичность nil поскольку пустой список является одной из первых вещей, которые вы узнаете о Lisp. Я попытался придумать хороший хит Google, но я просто выберу один, потому что их так много: http://www.cs.sfu.ca/CourseCentral/310/pwfong/Lisp/1/tutorial1.html