Java的Interport和Haskell的类型类:差异和相似之处?

2022-08-31 08:33:05

当我学习Haskell时,我注意到它的类型类,这应该是起源于Haskell的伟大发明。

但是,在维基百科页面中的类型类

程序员通过指定一组函数或常量名称及其各自的类型来定义类型类,这些函数或常量名称必须存在于属于该类的每个类型中。

这对我来说似乎与Java的接口相当接近(引用维基百科的接口(Java)页面):

Java 编程语言中的接口是一种抽象类型,用于指定类必须实现的接口(在术语的泛型意义上)。

这两者看起来非常相似:类型类限制类型的行为,而接口限制类的行为。

我想知道Haskell中的类型类和Java中的接口之间有什么区别和相似之处,或者它们根本不同?

编辑:我注意到,即使 haskell.org 承认它们是相似的。如果它们如此相似(或者它们是如此相似?),那么为什么类型类被如此炒作对待呢?

更多编辑:哇,这么多很棒的答案!我想我必须让社区决定哪个是最好的。然而,在阅读答案时,他们似乎都只是说“typeclass可以做很多事情,而接口不能或必须处理泛型”。我不禁想知道,接口可以做些什么,而类型类却不能?另外,我注意到维基百科声称typeclass最初是在1989年的论文*“如何使临时多态性不那么临时”中发明的,而Haskell仍然处于摇篮中,而Java项目始于1991年,并于1995年首次发布。因此,也许不是类型类类似于接口,而是相反,接口受到类型类的影响?是否有任何文件/论文支持或反驳这一点?感谢所有的答案,它们都非常有启发性!

感谢所有输入!


答案 1

我会说接口有点像类型类,其中所有值都具有类型(其中不包含 )。这是因为在Java和类似语言中,使用这种继承关系,调用的方法取决于调用它们的对象的类型,而不是其他任何类型。SomeInterface tt -> whateverwhatevert

这意味着很难像使用接口那样制作东西,因为它在多个参数上是多态的,因为接口无法指定方法的参数类型和返回类型与调用它的对象的类型(即“self”类型)的类型相同。使用泛型,有一些方法可以通过制作一个具有泛型参数的接口来伪造这一点,该参数应与对象本身的类型相同,就像它一样,您希望在其中使用,以便该类型具有类型 。但这仍然需要程序员遵循这个规则,并且当人们想要制作一个使用这个接口的函数时,他们也会引起头痛,他们必须有递归泛型类型参数。add :: t -> t -> tComparable<T>Foo implements Comparable<Foo>compareTo(T otherobject)t -> t -> Ordering

此外,你不会有这样的东西,因为你不在这里调用一个函数,所以它不是一个方法。empty :: t


答案 2

接口和类型类之间的相似之处在于,它们命名并描述了一组相关操作。操作本身通过其名称、输入和输出进行描述。同样,这些操作的许多实现可能在实现上有所不同。

有了这个,这里有一些值得注意的区别:

  • 接口方法始终与对象实例相关联。换句话说,始终存在一个隐含的“this”参数,该参数是调用方法的对象。类型类函数的所有输入都是显式的。
  • 接口实现必须定义为实现接口的类的一部分。相反,类型类“实例”可以与其关联类型完全分开定义...即使在另一个模块中。

总的来说,我认为公平地说,类型类比接口更强大、更灵活。如何定义用于将字符串转换为实现类型的某个值或实例的接口?这当然不是不可能,但结果不会是直观或优雅的。你有没有想过可以在一些编译的库中实现一个类型的接口?这些都很容易用类型类完成。