使用非列表尾部构建列表有什么意义?

Clé*_*ent 2 lisp emacs elisp list cons

的Emacs Lisp手册关于nconc的功能状态:

由于nconc的最后一个参数本身并未修改,因此使用常量列表是合理的,例如'(4 5),如上例所示.出于同样的原因,最后一个参数不必是一个列表

事实上,我可以写

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

(nconc x 0)
=> (1 2 3 . 0)
Run Code Online (Sandbox Code Playgroud)

但这会产生一个完全破碎的清单:

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

(butlast x)
=> butlast: Wrong type argument: listp, 0
Run Code Online (Sandbox Code Playgroud)
  • 如何检索原始列表?(reverse (cdr (reverse '(1 2 3 . 0))))也不削减它.
  • 在哪种情况下,这是一种有用的模式?在标准分发中,一些功能在minibuffer.el使用它,特别completion-all-completions是等.

Chr*_*ung 5

他们不是"破碎"的名单; 它们实际上被称为不正确的列表(与 - nil终止列表相对应,这是正确的列表).许多列表功能,如lengthbutlast你刚刚任命,期待适当的名单,并listp只用于适当列表返回true.

不正确的列表用在关联列表中(其中关联通常不合适;尽管alist本身必须正确).


如果您想正确制作一个不正确的清单,您有两种选择:

  • 删除"不正确"元素.
  • 将不正确的元素视为正确列表的最后一个元素.

这是我写的一个程序properise,它将执行前者:

(defun properise (x)
  (let ((r nil))
    (while (consp x)
      (push (pop x) r))
    (nreverse r)))
Run Code Online (Sandbox Code Playgroud)

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