Common Lisp 排序函数从原始列表中删除一个元素

Sre*_*r R 1 lisp sbcl common-lisp

我正在使用SBCL,当我使用sort如下功能时,

CL-USER> (defparameter y '(5 7 2 9 4 6))
Y
CL-USER> y
(5 7 2 9 4 6)
CL-USER> (sort y #'>)
(9 7 6 5 4 2)
CL-USER> y
(7 6 5 4 2)
Run Code Online (Sandbox Code Playgroud)

最大的元素(在本例中为 9)从原始列表中删除。

想知道发生了什么?

Ren*_*nzo 7

sort,根据手册

根据谓词函数确定的顺序对序列进行破坏性排序。

换句话说,它可以修改它的参数,你应该得到作为排序操作结果的返回值。

CL-USER> (defvar y (list 5 7 2 9 4 6))
Y
CL-USER> (setf y (sort y #'>))
(9 7 6 5 4 2)
CL-USER> y
(9 7 6 5 4 2)
Run Code Online (Sandbox Code Playgroud)

请注意,由于它可以修改其参数,copy-list如果我们想避免这种修改,应该调用它:

CL-USER> (defparameter y '(5 7 2 9 4 6))
Y
CL-USER> (sort (copy-list y) #'<)
(2 4 5 6 7 9)
CL-USER> y
(5 7 2 9 4 6)
Run Code Online (Sandbox Code Playgroud)

最后,请注意修改文字值(如'(5 7 2 9 4 6))会产生未定义的行为,应避免。


Rai*_*wig 5

(defvar *y* '(1 2 3))
Run Code Online (Sandbox Code Playgroud)

所以*y*指向(1 2 3). 像这样。

 *y*--->[*|*]--->[*|*]--->[*|*]---> NIL
          |        |        |
          v        v        v
          1        2        3
Run Code Online (Sandbox Code Playgroud)

现在,如果您评估(sort *y* #'>),则*y*首先评估并将内容传递给sort. 不是变量,是内容!在函数内部sort,没有对*y*可用的引用。什么sort得到的是在第一利弊单元格的引用。

现在,当sort将 移到3前面时,它可以通过将一个新的 cons 单元放在前面来实现(这是实现排序的一种方法)。但是sort永远不能更新*y*以引用不同的对象,因为它没有对*y*自身的引用,而是对(1 2 3).

因此,sort返回一个排序列表,并且应该使用它作为结果,而不是使用指向原始参数的引用。原始参数列表可能已更改:

sort也可能是破坏性的

注意:Common Lisp 中未指定破坏性排序的确切行为

因此,实现可能会显示不同的副作用。参见例如CLISP实现:

[1]> (defvar *y* '(1 2 3))
*Y*
[2]> (sort *y* #'>)
(3 2 1)
[3]> *y*
(3 2 1)
Run Code Online (Sandbox Code Playgroud)