2015-02-17 6 views
2

В Emacs lisp manual состояния о функции nconc, что:Какой смысл строить список с хвостом без списка?

Так как последний аргумент nconc сам по себе не изменяется, то целесообразно использовать постоянный список, например, «(4 5), как и в приведенном выше примере , По той же причине, последний аргумент не должен быть список

И действительно, я могу написать

(setq x '(1 2 3)) 
=> (1 2 3) 

(nconc x 0) 
=> (1 2 3 . 0) 

но дает совершенно разбитое список:

(length x) 
=> eval: Wrong type argument: listp, 0 

(butlast x) 
=> butlast: Wrong type argument: listp, 0 
  • Как может Я извлекаю исходный список? (reverse (cdr (reverse '(1 2 3 . 0)))) также не разрезает его.
  • В каких контекстах это полезный шаблон? В стандартном распределении используются некоторые функции в minibuffer.el, в частности completion-all-completions и тому подобное.
+1

BTW, используя буквальное геодезическую, как ''(1 2 3)', поскольку не последний аргумент для 'nconc' технически не подходит. Буквенные данные считаются постоянными. –

ответ

5

Это не «сломанные» списки; они на самом деле известны как неправильных списков (в отличие от nil) - перечни списков, которые соответствуют списков). Многие функции списка, такие как length и butlast, которые вы только что назвали, ожидают правильные списки, а listp возвращает true только для правильных списков.

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


Если вы хотите, чтобы несобственный список собственно, у вас есть два варианта:

  • удалить «неправильный» элемент.
  • Относитесь к несобственному элементу как к последнему элементу соответствующего списка.

Вот процедура, которую я написал называется properise, который будет делать бывший:

(defun properise (x) 
    (let ((r nil)) 
    (while (consp x) 
     (push (pop x) r)) 
    (nreverse r))) 

(. Если вы хотите, последнее поведение, добавьте (unless (null x) (push x r)) непосредственно перед nreverse линии)

+0

Спасибо за ответ! Есть ли простой эквивалент 'butlast' для неправильных списков? –

+0

Нет, но я отредактировал сообщение, чтобы добавить процедуру 'properize', которая превратит ваш неправильный список в правильный список. Затем вы можете называть 'butlast'. –

+0

Спасибо. Это довольно сложная процедура. Интересно, почему «завершение-все-завершения» возвращает такие результаты. –

2

Вообще, я бы избегайте создания таких структур данных, в которых последний элемент является ячейкой cons с некоторым объектом, отличным от NIL в cdr ... Это делает отладку сложнее, это взломать, затрудняет понимание кода, ...

+0

Согласен, как и OP. Фактически, ОП пытается понять, почему «завершение-все-завершения» в Emacs (иногда) возвращает неправильные списки .... –

+1

@ ChrisJester-Young: Право, и это трудно понять, еще больше показывает что чего-то возможно «умного», подобного этому, следует избегать. На самом деле я не могу сразу вспомнить любое программное обеспечение Lisp, которое использует что-то подобное ... –

+0

Я полностью согласен. У многих лизгов есть такие типы подводных камней. В некоторых случаях наличие '(setq x '(1 2 3)) может вызвать проблемы, поскольку оно не является * правильным * списком, и вы должны сделать (setq x (список 1 2 3)) вместо –

0

Я все еще не уверен, почему это хорошая картина, но вот простой способ получить надлежащий список из несобственной, без создания копии:

(defun nmake-proper-list (x) 
    (let ((y (last x))) 
    (setcdr y nil) 
    x)) 

 Смежные вопросы

  • Нет связанных вопросов^_^