考虑缺点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
其他功能示例可以显示x1
和x2
之间的链接。
(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 }}被称为“共享链接”,x2
,x1
以图形方式显示(略微适应):
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中有隐式指针,但没有人愿意讲述它们。))
答案 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))
当您致电cons
或list
时,您会收到 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
是一个等式谓词(eq
或equal
)而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
单元格是一个非常小的容器:它包含两个元素,并具有访问器car
和cdr
以便将这些元素取回。
在大多数面向对象的编程语言中,当您将对象放入容器时,不会自动复制对象。例如,在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
来反转它,因为你知道没有其他人有对它的引用。