如何注意NREVERSE可能会改变CAR的事实

Jis*_*Yoo 9 lisp common-lisp

http://www.aiai.ed.ac.uk/~jeff/lisp/cl-pitfalls将此列为Common Lisp陷阱之一

您认为会修改CDR的破坏性功能可能会修改CAR.(例如,NREVERSE.)

我不确定我应该采取什么预防措施.我可以从NREVERSE修改CDR的事实中采取的常规预防措施是仅当列表(参数)不与我的变量稍后可能引用的任何其他列表共享尾部时使用NREVERSE(除了变量我保存返回值)至).我应该从NREVERSE可以修改CAR的事实中采取什么预防措施?这件事需要注意什么?

Rai*_*wig 12

没有任何背景,这很难理解.

例:

(setq list1 (list 1 2 3 4))
Run Code Online (Sandbox Code Playgroud)

我们现在有一个四个数字的列表.变量list1指向第一个缺点.

如果我们看一个破坏性的反向,我们正在讨论一个可能改变缺陷细胞的操作.如何反转此列表有不同的方法.

例如,我们可以采取利弊细胞并将其逆转.然后是第一个cons小区是最后一个.那个cons单元的cdr然后必须改成NIL.

CL-USER 52 > (setq list1 (list 1 2 3 4))
(1 2 3 4)

CL-USER 53 > (nreverse list1)
(4 3 2 1)
Run Code Online (Sandbox Code Playgroud)

现在我们的变量list1仍指向相同的cons单元格,但其cdr已更改:

CL-USER 54 > list1
(1)
Run Code Online (Sandbox Code Playgroud)

为了确保变量指向反转列表,程序员有责任更新变量并将其设置为nreverse操作结果.人们也可能试图利用list1指向最后利弊的可观察结果.

以上是Lisp开发人员通常所期望的.反向的大多数实现似乎都是这样的.但是在ANSI CL标准中没有规定如何nreverse实现.

那么改变CAR是什么意思呢?

让我们看一下另一种实现方式nreverse:

(defun nreverse1 (list)
  (loop for e across (reverse (coerce list 'vector))
        for a on list do
        (setf (car a) e))
  list)
Run Code Online (Sandbox Code Playgroud)

以上功能让cons细胞链保持完整,但改变了汽车.

CL-USER 56 > (setq list1 (list 1 2 3 4))
(1 2 3 4)
Run Code Online (Sandbox Code Playgroud)

现在让我们使用新版本nreverse1.

CL-USER 57 > (nreverse1 list1)
(4 3 2 1)

CL-USER 58 > list1
(4 3 2 1)
Run Code Online (Sandbox Code Playgroud)

现在你看到了不同之处:list1仍然指向整个列表.

总结:需要注意的是,有可能的不同实现nreverse.不要利用通常的行为,然后变量将指向最后的缺点.只需使用结果,nreverse一切都很好.

旁注:第二个版本可以在哪里使用?

Lisp机器上的一些Lisp实现允许一个紧凑的矢量表示列表.如果在这样的Lisp实现上,可以反转这样的列表,则实现者可以提供类似向量的有效向量.

  • @Chris Jester-Young:没有必要*处理它.只是不要利用特定实现的特定副作用.只需使用`nreverse`的返回结果. (6认同)
  • @Chris Jester-Young:当然,nreverse可能会产生可观察到的副作用,导致出现问题.这里的要点是这些副作用可能与预期不同,因为可以使用相对罕见的nreverse实施变体. (4认同)
  • @Chris Jester-Young:Common Lisp中的nreverse不需要不存在.CLHS:*nreverse可能会创建一个新序列,修改参数序列,或两者兼而有之.*创建一个新序列将会出现.只是我们期望在任何自尊的实现中使用逆向反转都有一些优势. (3认同)