关于函数nconc的Emacs lisp manual状态:
由于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
等。答案 0 :(得分: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
。)
答案 1 :(得分:2)
通常我会避免创建这样的数据结构,其中最后一个元素是一个cons单元格,在cdr中有一个非NIL的对象...它使调试更难,它是一个黑客,使代码更难以明白,...
答案 2 :(得分:0)
我仍然不确定为什么这是一个好的模式,但是这里有一个简单的方法可以从一个不合适的列表中获取一个正确的列表,而无需复制:
(defun nmake-proper-list (x)
(let ((y (last x)))
(setcdr y nil)
x))