0

Scheme知道三种不同的等价运算符:eq?, eqv?, equal?。请参阅此处了解详细信息。简而言之:eq?测试引用,eqv?测试值并equal?递归测试列表的值。我想编写一个需要 Scheme 功能的 Java 泛型equal?

我尝试使用 Java 的equals()方法,因为我认为它会进行值比较,因为对于引用比较,==运算符存在并且不需equals要这样做。但是这个假设是完全错误的,因为equals在 Java 中是完全不可靠的。有时它会进行值比较,有时会进行参考比较。并且不能确定哪个类进行引用比较,哪个类进行值比较。

这意味着equals不能在泛型中使用,因为泛型不会对所有类型都执行相同的操作。而且也不可能以只接受实现正确值比较的类型的方式限制泛型类型。

所以问题是:如何在泛型中进行可靠的值比较?我必须从头开始自己编写吗?

顺便说一句:我认为 Java 的同样失败并不是从Array开始的。它已经从 Object 开始。我认为equals对于两个对象返回是错误的false。它必须返回true,因为如果您对没有值的东西进行值比较,则值不能不同,因此它们必须相同。Scheme 就是这样做的,而且是完全合理的:(equal? (vector) (vector)) -> #t.

4

1 回答 1

0

在 Scheme 中,列表等价完全基于项目的结构。

相比之下,在 Java 中,相等取决于对象的类型,并且可能在其等价计算中使用部分或全部内部结构。相同类型的两个对象“相等”意味着什么取决于对象类型来确定,只要满足相等的一般约定(最值得注意的是,它与所有其他对象形成等价关系)。

假设程序中使用的所有类型都有一个合理的equals定义,它们应该有一个“可靠的”值比较,至少在面向对象范式的意义上是这样。

回到类似的 Javaequal?实现。从问题的措辞中拼凑起来有点困难,但从上下文线索来看,这似乎也在尝试对项目列表进行操作。equalsJava类型的方法List已经实现了直接类似于 Schemeequals?操作的行为:

比较指定对象与此列表是否相等。true当且仅当指定对象也是一个列表时返回,两个列表具有相同的大小,并且两个列表中所有对应的元素对都相等。(如果 ,则两个元素 e1 和 e2相等Objects.equals(e1, e2)。)换句话说,如果两个列表以相同的顺序包含相同的元素,则它们被定义为相等。

这个定义也意味着递归列表结构也以与 Scheme 的equals?操作类似的方式工作。

请注意,该List行为与 Java 的数组类型(您在问题中提到的)明显不同。Java 中的数组是一种相当低级的类型,不支持人们可能期望的许多典型的面向对象的功能。特别要注意的是,对于相等性,数组是通过对象引用而不是通过数组中项目的结构比较来比较的。有一些方法可以使用Arrays类中的方法(例如Arrays.equalsArrays.deepEquals)对数组进行合理的相等比较。


顺便说一句,要解决您关于两个裸Objects 相等性的后记。

assert !(new Object().equals(new Object()))

从面向对象的角度来看,只有当它们是相同的引用时,两个裸对象才相等是明智的。首先,如上所述,对象的内部结构与其相等性之间没有直接关系,因此它们不需要相等。从对象建模的角度来看,实际上没有关于两个不同实例Object代表什么的上下文,因此没有固有的概念方式来说明这两个对象在逻辑上是“相同”的东西。


总之,假设列表中的所有类型都有一个根据对象类型定义的合理版本equals(),Java 的List.equals()行为直接类似于 Scheme 的equals?操作。

于 2021-01-04T07:05:49.987 回答