2

Emacs lisp 手册中关于函数 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之类的。
4

3 回答 3

5

它们不是“损坏”的列表;它们实际上被称为不正确的列表(与 -nil终止的列表相反,后者是正确的列表)。许多列表函数,例如您刚刚命名的length和,都需要正确的列表,并且仅对正确的列表返回 true。butlastlistp

不正确的列表用于关联列表(关联通常不正确;尽管 alist 本身必须正确)。


如果您想正确列出不正确的列表,您有两种选择:

  • 删除“不适当”的元素。
  • 将不正确的元素视为正确列表的最后一个元素。

这是我编写的一个称为properise前者的程序:

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

(如果您想要后一种行为,请(unless (null x) (push x r))在该行之前添加nreverse。)

于 2015-02-18T00:23:29.900 回答
2

一般来说,我会避免创建这样的数据结构,其中最后一个元素是一个 cons 单元格,其中包含 cdr 中的 NIL 以外的其他对象......它使调试变得更加困难,这是一种 hack,使代码更难以理解,......

于 2015-02-18T05:32:53.720 回答
0

我仍然不确定为什么这是一个好的模式,但这是一种从不正确的列表中获取正确列表的简单方法,而无需复制:

(defun nmake-proper-list (x)
  (let ((y (last x)))
    (setcdr y nil)
    x))
于 2015-02-18T13:42:22.657 回答