Scheme知道三种不同的等价运算符:eq?
,eqv?
,equal?
。有关详细信息,请参阅here。简而言之:eq?
测试引用,eqv?
测试值,equal?
递归测试列表的值。我想编写一个Java泛型,它需要Scheme的equal?
。
我尝试使用Java的equals()方法,因为我认为它进行了值比较,因为对于参考比较,==
运算符存在且不需要equals
做同样的事。但是这个假设是完全错误的,因为Java中的equals
完全不可靠。有时它会进行值比较,有时它会进行参考比较。并且不能确定哪个类进行参考比较以及哪个类进行值比较。
这意味着equals
不能在通用中使用,因为通用对所有类型都不会这样做。并且也不可能以只接受类型的方式限制泛型类型,以实现正确的值比较。
所以问题是:如何在通用中进行可靠的价值比较?我是否必须自己从头开始写它?
顺便说一句:我认为Java的同等失败不是以Array开头的。它已经开始使用Object。我认为equals
两个对象返回false
是错误的。它必须返回true
,因为如果对某些没有值的值进行值比较,则值不能相同,因此它们必须相同。 Scheme以这种方式完成它并且完全合理:(equal? (vector) (vector)) -> #t
。
答案 0 :(得分:0)
在 Scheme 中,列表等价完全基于项目的结构。
相比之下,在 Java 中,相等性取决于对象的类型,并且在其等价性计算中可能会使用部分或全部内部结构。两个相同类型的对象“相等”意味着什么取决于对象类型来确定,只要满足 general contract for equals(最值得注意的是它与所有其他对象形成一个 equivalence relation对象)。
假设程序中使用的所有类型都具有合理的 equals
定义,它们应该具有“可靠”的值比较,至少在面向对象范式的意义上是这样。 >
回到类似的 Java equal?
实现。从问题的措辞中拼凑起来有点困难,但从上下文线索来看,这似乎也试图对项目列表进行操作。 Java 的 equals
类型上的 List
方法已经实现了直接类似于 Scheme 的 equals?
操作的行为:
比较指定的对象与此列表是否相等。返回 true
当且仅当指定的对象也是一个列表,两个列表的大小相同,并且两个列表中所有对应的元素对相等。 (如果 Objects.equals(e1, e2)
,两个元素 e1 和 e2 相等。)换句话说,如果两个列表以相同的顺序包含相同的元素,则它们被定义为相等。
这个定义也意味着递归列表结构的工作方式与 Scheme 的 equals?
操作类似。
请注意,List
的行为与 Java 的数组类型(您在问题中提到的)的行为明显不同。 Java 中的数组是一种相当低级的类型,不支持人们可能期望的许多典型的面向对象功能。特别要注意的是,对于相等性,数组是通过对象引用而不是通过数组中项目的结构比较来比较的。有一些方法可以使用 Arrays
类中的方法(例如 Arrays.equals
和 Arrays.deepEquals
)对数组进行合理的相等比较。
顺便说一句,解决您关于两个裸 Object
相等的后记。
assert !(new Object().equals(new Object()))
从面向对象的角度来看,两个裸对象只有在它们是相同的引用时才相等是明智的。首先,如上所述,对象的内部结构与其相等性之间没有直接关系,因此它们没有需要相等。从对象建模的角度来看,几乎没有关于 Object
的两个不同实例代表什么的上下文,因此没有内在的概念方法来说明这两个对象在逻辑上是“相同”的东西。
总而言之,假设您列表中的所有类型都有一个合理版本的 equals()
,根据它们的对象类型定义,Java 的 List.equals()
的行为直接类似于 Scheme 的 {{1 }} 操作。