#emacs #lisp #elisp
#emacs #lisp #elisp
Вопрос:
В Emacs Lisp кажется, что я не могу удалить последний элемент из списка.
;; This works.
(setq list1 '(alpha beta))
(delete 'alpha list1) ;; => (beta)
;; list1 => (beta)
;; NOPE.
(setq list1 '(alpha))
(delete 'alpha list1) ;; => nil
;; list1 => (alpha)
Почему?
Также, если это возможно сделать, как мне это сделать?
Ответ №1:
Хотя delete
для удаления элемента списка используются побочные эффекты, это не гарантировано. Правильный способ его использования — присвоить результат обратно переменной:
(setq list1 (delete 'alpha list1))
Фактически, когда я пробую ваш первый пример, list1
также остается неизменным:
ELISP> (setq list1 '(alpha beta))
(alpha beta)
ELISP> (delete 'alpha list1)
(beta)
ELISP> list1
(alpha beta)
Это потому, что delete
это функция, а не макрос или специальная форма. Это означает, что он не может изменить привязку переменной list1
; он может изменить только содержимое ячейки cons, на которую list1
указывает. Если элемент списка, который должен быть удален, является первым элементом в списке, самый простой способ удалить его — просто вернуть конец (он же cdr) списка. Если удаляемый элемент является единственным элементом в списке, правильным возвращаемым значением будет nil
(пустой список), и нет способа изменить ячейку cons, чтобы она стала nil
.
Вы заметите, что это действительно работает, если вы удалите второй элемент:
ELISP> (setq list1 '(alpha beta))
(alpha beta)
ELISP> (delete 'beta list1)
(alpha)
ELISP> list1
(alpha)
В этом случае delete
заканчивается выполнение (setcdr list1 nil)
, которое требует изменения только ячейки cons, а не привязки list1
.
Комментарии:
1. Я понял свой первый пример совершенно неправильно. Спасибо за подробное объяснение. На «удаление использует побочные эффекты», вы подразумеваете, что я должен делать это по-другому?
2. Нет, это просто для того, чтобы объяснить, почему это иногда работает, а иногда нет.
remove
выполняет то же самое, что и delete , за исключением того, что не использует побочные эффекты для изменения аргумента, но возвращает копию списка с удаленными соответствующими элементами, так что без этого он никогда бы не работалsetq
.
Ответ №2:
От C-h v delete
:
Напишите
(setq foo (delete element foo))' to be sure of correctly
foo’.
changing the value of a sequence
И, по-видимому, '()
вычисляется как nil
.
Как это сделать тогда:
(setq list1 '(alpha))
(setq list1 (delete 'alpha list1))