Emacs Lisp共享结构和共享链接

时间:2014-02-09 14:52:52

标签: emacs lisp elisp cons cdr

考虑缺点x1

(setq x1 '(a . (b c))) => (a b c)

或列表符号:

(setq x1 '(a b c)) => (a b c)

以及x2构建的利弊x1

(setq x2 (cons 'A (cdr x1))) => (A b c)

cons帮助(在Emacs中)说该函数会创建新缺点,为其提供参数'A(cdr x1),作为组件和< em>返回它。没有任何内容表明新返回的利弊的生命将链接与其生成组件的生命。

无论如何,如果修改了副本,x2,原始利弊,(a . (b c))也会被修改:

(setcar (cdr x2) 'B) => B
x2 => (A B c)  ; as from the assignment 
x1 => (a B c)  ; x1 and x2 are linked

其他功能示例可以显示x1x2之间的链接。

(setq x1 '(a . (b c))) => (a b c)
(setq x2 (cons 'A (cdr x1))) => (A b c)
(nreverse x2) => (c b A)
x1 => (a b A)

我从Emacs Lisp参考手册中的setcar文档中获取了这个示例,该文档指出“cons单元是共享结构的一部分”以及x1和{{1的cdr }}被称为“共享链接”,x2x1以图形方式显示(略微适应):

x2

这让人想起C指针,因为x1: -------------- -------------- -------------- | car | cdr | | car | cdr | | car | cdr | | a | o------->| b | o------->| c | nil | | | | -->| | | | | | -------------- | -------------- -------------- | x2: | -------------- | | car | cdr | | | A | o---- | | | -------------- 的cdr不是副本,而是“指向”x2的cdr。很清楚,但我想知道这种情况何时会出现,也就是说,我怎么知道一个利弊(一个元素)指向另一个或者是一个自我生活的副本?更一般地说是什么(在哪里)是共享结构共享链接的正式定义?

在Emacs Lisp参考手册中没有明确提及它们。事实上,在索引中搜索“共享”或“链接”只返回(共享结构,读取语法)的间接引用,处理它们的表示,而不是它们是什么。
奇怪地在PDF中搜索“共享”区域,作为第一次出现,到“循环对象的读语法”部分,从“表示共享或循环结构......”开始。不幸的是,之前没有提到共享和循环(结构)这两个词!下一个出现的是提到的x1文档。

所以似乎Lisp / Elisp中有隐式指针,但没有人愿意讲述它们。))

3 个答案:

答案 0 :(得分:4)

你的朋友是eq and equal的职能。

eq比较物理身份,equal检查对象是否相似&#34;。

在你的情况下:

(defvar a (list 1 2 3))
(defvar b (cons 1 (cdr a)))
(equal a b)
==> t
(eq a b)
==> nil
(eq (cdr a) (cdr b))
==> t

编辑:请注意list is equivalent to a few cons calls

(list x y) == (cons x (cons y nil))

当您致电conslist时,您会收到 eq 其他其他内容。

继续上面的例子:

(defvar c (list 4 (cdr a)))
(defvar d (list 4 (cdr b)))
(equal c d)
==> t
(eq c d)
==> nil
(eq (cdr c) (cdr d))
==> nil
(eq (cadr c) (cadr d))
==> t
(eq (cadr c) (cdr a))
==> t
(eq (cadr d) (cdr b))
==> t

PS。有必要认识到(E x y) ==> (E (F x) (F y))其中E是一个等式谓词(eqequal)而F是一个访问者(例如car }或cdr)。

PPS。 equal的反之亦然:

(and (equal (car x) (car y)) 
     (equal (cdr x) (cdr y)))

暗示(事实上,相当于)(equal x y);但 eq

答案 1 :(得分:0)

要添加@sds的答案,因为他没有明确提及,你问过这个问题:

请参阅Elisp手册,节点Modifying Lists及其子节点。您询问的示例在节点Setcar中明确提及:

 ;; Create two lists that are partly shared.
 (setq x1 '(a b c))
      => (a b c)
 (setq x2 (cons 'z (cdr x1)))
      => (z b c)

是的,您的问题并非专门针对setcar和其他列表结构修改功能。但是Elisp手册中关于 缺点单元 的演示文稿提供了您正在寻找的答案,除了这里给出的关于如何在Lisp中传递参数的注释和答案

答案 2 :(得分:0)

这里有一些其他答案可以更详细地解释这一点,但也可能有助于实现一个非常小的类比。 cons单元格是一个非常小的容器:它包含两个元素,并具有访问器carcdr以便将这些元素取回。

在大多数面向对象的编程语言中,当您将对象放入容器时,不会自动复制对象。例如,在Java中,如果你有:

Object a = new Object();
Object b = new Object();

Object[] cons1 = new Object[] { a, b };
Object[] cons2 = new Object[] { a, b };

你应该期待

cons1 == cons2 

是假的,但是

( cons1[0] == cons2[1] ) && ( cons1[1] == cons2[1] )

是真的。 容器对象是不同的,但它们包含的对象是相同的。

这只是一种惯例,列表是使用缺点单元构建的,其中列表是空列表(nil),或者是car是列表的第一个元素且其列表为cdr是列表的其余部分。

  

这让人想起C指针,因为x2的cdr是   不是副本,而是“指向”x1的cdr。清楚,但我想知道什么时候   实际上会出现这种情况,也就是说,我怎么知道(一个   一个缺点指向另一个或是一个自我生活的副本?   更一般地说,(where)是共享结构的正式定义   和共享链接?

这不仅仅是让人想起,它几乎是一回事。记忆中有物体,你可以得到它们。有时,不止一件事可能会引用内存中的同一对象。您可以使用cons测试eq单元格的相等性,但这不是关于共享结构的一般答案,因为您无法知道 else 有谁引用一个对象。通常,您将遵循以下规则:“不要修改您未创建的结构,除非您在文档中明确提及它,即使这样,返回重要值。 “因此reverse不会修改其参数,但允许nreverse(但仍返回反转列表; nreverse不保证列表就地反转)。如果你正在构建一个属于你的函数的本地列表,那么可以使用nreverse来反转它,因为你知道没有其他人有对它的引用。