构建带有非列表尾部的列表有什么意义?
What's the point of building a list with a non-list tail?
Emacs lisp manual 关于函数 nconc 的说明:
Since the last argument of nconc is not itself modified, it is reasonable to use a constant list, such as '(4 5), as in the above example. For the same reason, the last argument need not be a list
我确实会写
(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
等。
它们不是 "broken" 列表;它们实际上被称为 不正确的 列表(与 nil
终止的列表相反,后者是 正确的 列表)。许多列表函数,例如您刚刚命名的 length
和 butlast
,需要正确的列表,而 listp
returns 仅适用于正确的列表。
关联列表中使用了不正确的列表(其中关联通常不正确;尽管列表本身必须正确)。
如果你想把一个不正确的列表变成正确的,你有两个选择:
- 删除 "improper" 元素。
- 将不正确的元素视为正确列表的最后一个元素。
这是我编写的一个名为 properise
的过程,它将执行前者:
(defun properise (x)
(let ((r nil))
(while (consp x)
(push (pop x) r))
(nreverse r)))
(如果您想要后一种行为,请在 nreverse
行之前添加 (unless (null x) (push x r))
。)
通常我会避免创建这样的数据结构,其中最后一个元素是一个 cons 单元格,其中包含 cdr 中 NIL 以外的某些对象...这会使调试变得更加困难,这是一种 hack,使代码更难以理解, ...
我仍然不确定为什么这是一个好的模式,但这里有一种简单的方法可以从不正确的列表中获取正确的列表,而无需复制:
(defun nmake-proper-list (x)
(let ((y (last x)))
(setcdr y nil)
x))
Emacs lisp manual 关于函数 nconc 的说明:
Since the last argument of nconc is not itself modified, it is reasonable to use a constant list, such as '(4 5), as in the above example. For the same reason, the last argument need not be a list
我确实会写
(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
等。
它们不是 "broken" 列表;它们实际上被称为 不正确的 列表(与 nil
终止的列表相反,后者是 正确的 列表)。许多列表函数,例如您刚刚命名的 length
和 butlast
,需要正确的列表,而 listp
returns 仅适用于正确的列表。
关联列表中使用了不正确的列表(其中关联通常不正确;尽管列表本身必须正确)。
如果你想把一个不正确的列表变成正确的,你有两个选择:
- 删除 "improper" 元素。
- 将不正确的元素视为正确列表的最后一个元素。
这是我编写的一个名为 properise
的过程,它将执行前者:
(defun properise (x)
(let ((r nil))
(while (consp x)
(push (pop x) r))
(nreverse r)))
(如果您想要后一种行为,请在 nreverse
行之前添加 (unless (null x) (push x r))
。)
通常我会避免创建这样的数据结构,其中最后一个元素是一个 cons 单元格,其中包含 cdr 中 NIL 以外的某些对象...这会使调试变得更加困难,这是一种 hack,使代码更难以理解, ...
我仍然不确定为什么这是一个好的模式,但这里有一种简单的方法可以从不正确的列表中获取正确的列表,而无需复制:
(defun nmake-proper-list (x)
(let ((y (last x)))
(setcdr y nil)
x))