在我的大学,我们不得不与Racket合作,因为我很喜欢它,我从No Starch购买了最近出版的书“Realm Of Racket” .
到目前为止它很棒,但是,当他们试图解释eq时,我无法弄清楚它们在第4章中的含义是什么?作品:
-
首先,他们解释了如何平等?比较两个值是否由相同的部分组成 . 好的,没问题,我明白了:平等?与Java的equals(someObject)方法完全相同 . 如果两个对象/结构/任何内容相同,则返回#t .
-
然后,我想,eq?必须等同于Java的==运算符,它不会按内容进行比较,而是基于引用 .
-
这个想法似乎得到了书中以下句子的证实:"eq? compares whether changing one structure changes the other structure..."太棒了!让我们将它与下面的Java代码进行比较:
Point p1 = new Point(5, 5);
Point p2 = p1;
System.out.println(p1 == p2); // true, since the reference has been copied.
System.out.println(p1.x); // 5
System.out.println(p2.x); // 5
p1.x = 42;
System.out.println(p1.x); // 42
System.out.println(p2.x); // Accordingly, 42
让我们在Racket中尝试一下:
(define cons1 (cons 1 empty))
(define cons2 cons1)
(eq? cons1 cons2) ;; #t, since the refernce has been copied.
(set! cons1 (cons 2 empty))
cons1 ;; Returns '(2) - as expected.
cons2 ;; Still returns '(1).
为什么? cons2指向cons1,它本身指向'(2) . 另外,他们不是只是说一改变另一个就等于他们是平等的吗?
显然,现在我没有按照预期行事,因此,我看不到什么样的情况?是在做 . 也许我错了,它与引用没有任何关系......
如果有人知道这一点,请分享你的智慧;)
3 回答
有关
eq?
如何工作的技术解释,请查看当前的specification,您在该主题上获得了't find a more detailed reference. Or simply check Racket' s documentation,特别是程序eq?
,eqv?
和equal?
. 关于你的问题 - 结果与Scheme代码中的预期和正确一样,让我们看看为什么 . 请注意,在Java中的这一行:您正在修改
p1
和p2
指向的同一对象 . 而在这一行:您正在创建一个新的不同对象并将
cons1
设置为指向它,但cons2
仍然指向旧对象 . 您可以在上一行之后确认这一点,比较(eq? cons1 cons2)
将返回#f
.关键是:这些例子并不等同 . Java示例处理由两个不同引用指向的单个对象,而Scheme示例处理两个对象和两个引用 .
为了进行比较,这里是一个与Java代码类似的Scheme示例,并按预期工作,因为在这里我们正在修改一个由两个引用指向的可变对象:
啊:你想确保你改变结构 . 在您的示例中,它实际上不是更改现有值的结构,而是构造一个全新的值并将
cons1
指向它 . 你有这个概念:eq?
几乎是Java的==
.只是为了类比,这里是Java形式的错误,所以你看到出了什么问题:
事实上,在这一点上,你需要检查
eq?
-ness在这结尾:你会看到两个不再是eq?
:它们是两个不同的值 .你真正想要的是在结构上做 mutation ,而不是变量重新绑定 . 在Racket中,由于列表是不可变的,因此您需要使用允许变异的不同数据结构 . 向量是可以演示的一个示例数据类型 . 让我们再次"Rosetta"这样你可以看到这样的比喻:
你是对的,
eq?
比较引用以确定相等性 . 这比equal?
更有效,它必须递归地比较对象 .Racket文档明确定义了每个以及相关的
eqv?
函数: