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

时间:2022-02-27 17:04:14

While I am learning Haskell, I noticed its type class, which is supposed to be a great invention that originated from Haskell.

在我学习Haskell的时候,我注意到了它的type class,它应该是一个源自Haskell的伟大发明。

However, in the Wikipedia page on type class:

但是,在*关于类型类的页面:

The programmer defines a type class by specifying a set of function or constant names, together with their respective types, that must exist for every type that belongs to the class.

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

Which seems rather close to Java's Interface to me (quoting Wikipedia's Interface(Java) page):

在我看来,这与Java的接口非常接近(引用Wikipedia的接口(Java)页面):

An interface in the Java programming language is an abstract type that is used to specify an interface (in the generic sense of the term) that classes must implement.

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

These two looks rather similar: type class limit a type's behavior, while interface limit a class' behavior.

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

I wonder what are the differences and similarities between type class in Haskell and interface in Java, or maybe they are fundamentally different?

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

EDIT: I noticed even haskell.org admits that they are similar. If they are so similar (or are they?), then why type class is treated with such hype?

编辑:我注意到甚至连haskell.org都承认他们是相似的。如果他们是如此相似(或者是吗?),那么为什么类型类会被如此夸大?

MORE EDIT: Wow, so many great answers! I guess I'll have to let the community decide which is the best one. However, while reading the answers, all of them seem to just say that "there are many things typeclass can do while interface cannot or have to cope with generics". I cannot help but wondering, are there anything interfaces can do while typeclasses cannot? Also, I noticed that Wikipedia claims that typeclass was originally invented in the 1989 paper *"How to make ad-hoc polymorphism less ad hoc", while Haskell is still in its cradle, while Java project was started in 1991 and first released in 1995. So maybe instead of typeclass being similar to interfaces, its the other way around, that interfaces were influenced by typeclass? Are there any documents/papers support or disprove this? Thanks for all the answers, they are all very enlightening!

更多编辑:哇,这么多很棒的答案!我想我得让社区决定哪个是最好的。然而,在阅读答案时,他们似乎都在说:“类型化可以做很多事情,而接口不能或必须处理泛型”。我不禁要问,在类型化不能做的时候,接口还有什么作用吗?另外,我注意到*声称类型类最初是在1989年的一篇论文*“如何使特别的多态性变得不那么特别”中发明的,而Haskell还在摇篮中,而Java项目是在1991年开始的,第一次发布是在1995年。因此,也许不是类型化类与接口相似,而是相反,接口受到类型化类的影响?是否有文件/文件支持或证明这一点?谢谢所有的答案,它们都很有启发性!

Thanks for all the inputs!

感谢所有输入!

10 个解决方案

#1


35  

I would say that an interface is kind of like a type class SomeInterface t where all of the values have the type t -> whatever (where whatever does not contain t). This is because with the kind of inheritance relationship in Java and similar languages, the method called depends on the type of object they are called on, and nothing else.

我想说一个接口有点像类型类SomeInterface t的所有值类型t - >不管(不包含t)。这是因为在Java的继承关系和类似的语言,调用的方法取决于类型的对象他们呼吁,而不是其它。

That means it's really hard to make things like add :: t -> t -> t with an interface, where it is polymorphic on more than one parameter, because there's no way for the interface to specify that the argument type and return type of the method is the same type as the type of the object it is called on (i.e. the "self" type). With Generics, there are kinda ways to fake this by making an interface with generic parameter that is expected to be the same type as the object itself, like how Comparable<T> does it, where you are expected to use Foo implements Comparable<Foo> so that the compareTo(T otherobject) kind of has type t -> t -> Ordering. But that still requires the programmer to follow this rule, and also causes headaches when people want to make a function that uses this interface, they have to have recursive generic type parameters.

这意味着真的很难让事情像添加::t - > - > t和一个接口,它是多态在一个以上的参数,因为没有办法接口指定方法的参数类型和返回类型是相同的类型为对象的类型是呼吁(即“自我”)。与泛型方法有有点假这通过一个接口与泛型参数,将相同类型的对象本身,像类似< T >如何,您将使用Foo实现类似< Foo >,以便compareTo(T otherobject)的类型T - > - >排序。但是这仍然需要程序员遵循这个规则,并且当人们想要创建一个使用这个接口的函数时,他们必须有递归的泛型参数。

Also, you won't have things like empty :: t because you're not calling a function here, so it isn't a method.

同样,也不会有empty:: t这样的函数,因为这里没有调用函数,所以它不是一个方法。

#2


31  

What is similar between interfaces and type classes is that they name and describe a set of related operations. The operations themselves are described via their names, inputs, and outputs. Likewise there may be many implementations of these operations that will likely differ in their implementation.

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

With that out of the way, here are some notable differences:

有了这些,这里有一些明显的区别:

  • Interfaces methods are always associated with an object instance. In other words, there is always an implied 'this' parameter that is the object on which the method is called. All inputs to a type class function are explicit.
  • 接口方法总是与一个对象实例相关联。换句话说,始终存在一个隐含的“this”参数,它是调用该方法的对象。类型类函数的所有输入都是显式的。
  • An interface implementation must be defined as part of the class that implements the interface. Conversely, a type class 'instance' can be defined completely seperate from its associated type...even in another module.
  • 接口实现必须定义为实现接口的类的一部分。相反,类型类“实例”可以从其关联类型中完全分离出来……即使是在另一个模块。
  • A type class allows you to define a 'default' implementation for any of the defined operations. Interfaces are strictly type specifications only, no implementation.
  • 类型类允许您为任何已定义的操作定义“默认”实现。接口是严格的类型规范,没有实现。

In general, I think its fair to say that type classes are more powerful and flexible than interfaces. How would you define an interface for converting a string to some value or instance of the implementing type? It's certainly not impossible, but the result would not be intuitive or elegant. Have you ever wished it was possible to implement an interface for a type in some compiled library? These are both easy to accomplish with type classes.

总的来说,我认为可以说类型类比接口更强大、更灵活。如何定义将字符串转换为实现类型的值或实例的接口?这当然不是不可能的,但结果不会是直观的或优雅的。您是否曾经希望在某些已编译的库中实现类型的接口?这些都很容易通过类型类实现。

#3


18  

Type classes were created as a structured way to express "ad-hoc polymorphism", which is basically the technical term for overloaded functions. A type class definition looks something like this:

类型类是作为一种表示“ad-hoc多态性”的结构化方式创建的,“ad-hoc多态性”基本上是重载函数的技术术语。类型类定义如下:

class Foobar a where
    foo :: a -> a -> Bool
    bar :: String -> a

What this means is that, when you use apply the function foo to some arguments of a type that belong to the class Foobar, it looks up an implementation of foo specific to that type, and uses that. This is very similar to the situation with operator overloading in languages like C, except more flexible and generalized.

这意味着,当您对属于类Foobar的类型的参数应用函数foo时,它会查找特定于该类型的foo的实现,并使用它。这与C语言中操作符重载的情况非常相似,除了更灵活和一般化。

Interfaces serve a similar purpose in OO languages, but the underlying concept is somewhat different; OO languages come with a built-in notion of type hierarchies that Haskell simply doesn't have, which complicates matters in some ways because interfaces can involve both overloading by subtyping (i.e., calling methods on appropriate instances, subtypes implementing interfaces their supertypes do) and by flat type-based dispatch (since two classes implementing an interface may not have a common superclass that also implements it). Given the huge additional complexity introduced by subtyping, I suggest it's more helpful to think of type classes as an improved version of overloaded functions in a non-OO language.

接口在面向对象语言中有类似的用途,但是底层的概念有些不同;OO语言内置了Haskell所没有的类型层次结构概念,这在某些方面使问题变得复杂,因为接口可以通过子类型(例如,,在适当的实例上调用方法,子类型实现它们的超类型所做的接口)和通过基于平面类型的分派(因为实现接口的两个类可能没有同样实现它的公共超类)。考虑到子类型带来的巨大的额外复杂性,我建议将类型类看作非oo语言重载函数的改进版本会更有帮助。

Also worth noting is that type classes have vastly more flexible means of dispatch--interfaces generally apply only to the single class implementing it, whereas type classes are defined for a type, which can appear anywhere in the signature of the class's functions. The equivalent of this in OO interfaces would be allowing the interface to define ways to pass an object of that class to other classes, define static methods and constructors that would select an implementation based on what return type is required in calling context, define methods that take arguments of the same type as the class implementing the interface, and various other things that don't really translate at all.

同样值得注意的是,类型类具有更灵活的调度方法——接口通常只应用于实现它的单个类,而类型类定义为类型,它可以出现在类函数的签名中任何地方。相当于在OO接口将允许接口定义的方法将该类的一个对象传递给其他类,定义静态方法和构造函数,选择一个实现基于返回类型需要在调用上下文中,相同类型的方法,把参数定义为类实现的接口,和其他各种事情真的不翻译。

In short: They serve similar purposes, but the way they work is somewhat different, and type classes are both significantly more expressive and, in some cases, simpler to use because of working on fixed types rather that pieces of an inheritance hierarchy.

简而言之:它们服务于类似的目的,但它们的工作方式有所不同,而且类型类的表达性都显著提高,而且在某些情况下,由于使用固定类型而不是继承层次结构的片段,使用起来更简单。

#4


7  

In Master minds of Programming, there's an interview about Haskell with Phil Wadler, the inventor of type classes, who explain the similarities between interfaces in Java and type classes in Haskell:

在《编程大师头脑》(Master of Programming)一书中,有一篇关于Haskell的采访,作者是type类的发明人Phil Wadler,他解释了Java中的接口和Haskell中的type类之间的相似性:

A Java method like:

Java方法:

   public static <T extends Comparable<T>> T min (T x, T y) 
   {
      if (x.compare(y) < 0)
            x; 
      else
            y; 
   }

is very similar to the Haskell method:

与Haskell方法非常相似:

   min :: Ord a => a -> a -> a
   min x y  = if x < y then x else y

So, type classes are related to interfaces, but the real correspondance would be a static method parametrized with a type as above.

因此,类型类与接口有关,但真正的对应关系将是一个静态方法,该方法会用上面的类型进行参数化。

#5


7  

I've read the above answers. I feel I can answer slightly more clearly:

我读过上面的答案。我觉得我可以更清楚地回答:

A Haskell "type class" and a Java/C# "interface" or a Scala "trait" are basically analogous. There is no conceptual distinction between them but there are implementation differences:

Haskell“type类”和Java/ c#“interface”或Scala“trait”基本上是相似的。它们之间没有概念上的区别,但有执行上的区别:

  • Haskell type classes are implemented with "instances" that are separate from the data type definition. In C#/Java/Scala, the interfaces/traits must be implemented in the class definition.
  • Haskell类型类是用与数据类型定义分离的“实例”实现的。在c# /Java/Scala中,接口/特性必须在类定义中实现。
  • Haskell type classes allow you to return a this type or self type. Scala traits do as well (this.type). Note that "self types" in Scala are a completely unrelated feature. Java/C# require a messy workaround with generics to approximate this behavior.
  • Haskell类型类允许您返回此类型或自类型。Scala特性也很好(this.type)。注意,Scala中的“自类型”是一个完全不相关的特性。Java/ c#需要使用泛型进行混乱的处理,以近似这种行为。
  • Haskell type classes let you define functions (including constants) without an input "this" type parameter. Java/C# interfaces and Scala traits require a "this" input parameter on all functions.
  • Haskell类型类允许您定义函数(包括常量),而无需输入“this”类型参数。Java/ c#接口和Scala特性要求所有函数都有一个“this”输入参数。
  • Haskell type classes let you define default implementations for functions. So do Scala traits and Java 8+ interfaces. C# can approximate something like this with extensions methods.
  • Haskell类型类允许定义函数的默认实现。Scala特性和Java 8+接口也是如此。c#可以使用扩展方法来近似这样的东西。

#6


6  

Watch Phillip Wadler's talk Faith, Evolution, and Programming Languages. Wadler worked on Haskell and was a major contributor to Java Generics.

看Phillip Wadler的谈话信仰,进化和编程语言。Wadler研究Haskell,并且是Java泛型的主要贡献者。

#7


6  

Read Software Extension and Integration with Type Classes where examples are given of how type classes can solve a number of problems that interfaces cannot.

阅读软件扩展和与类型类的集成,其中给出了类型类如何解决接口无法解决的许多问题的示例。

Examples listed in the paper are: the expression problem, the framework integration problem, the problem of independent extensibility, the tyranny of the dominant decomposition, scattering and tangling.

本文列举的例子有:表达式问题、框架集成问题、独立可扩展性问题、主导分解的专制问题、分散问题和纠缠问题。

#8


5  

I can't speak to the "hype"-level, if it seems that way fine. But yes type classes are similar in lots of ways. One difference that I can think of is that it Haskell you can provide behavior for some of the type class's operations:

我不能用“炒作”这个词来形容,如果它看起来不错的话。但是yes类型类在很多方面是相似的。我能想到的一个区别是Haskell可以为类型类的一些操作提供行为:

class  Eq a  where
  (==), (/=) :: a -> a -> Bool
  x /= y     = not (x == y)
  x == y     = not (x /= y)

which shows that there are two operations, equal (==), and not-equal (/=), for things that are instances of the Eq type class. But the not-equal operation is defined in terms of equals (so that you'd only have to provide one), and vice versa.

这表明对于属于Eq类型类的实例,有两个操作,即equal(=)和not equal(/=)。但是,不平等的操作是用equals(所以你只需要提供一个)来定义的,反之亦然。

So in probably-not-legal-Java that would be something like:

所以在可能不合法的java中

interface Equal<T> {
    bool isEqual(T other) {
        return !isNotEqual(other); 
    }

    bool isNotEqual(T other) {
        return !isEqual(other); 
    }
}

and the way that it would work is that you'd only need to provide one of those methods to implement the interface. So I'd say that the ability to provide a sort of partial implemention of the behavior you want at the interface level is a difference.

它的工作方式是你只需要提供其中一个方法来实现接口。我想说的是,在接口层提供某种行为部分实现的能力是不同的。

#9


4  

They are similar (read: have similar use), and probably implemented similarly: polymorphic functions in Haskell take under the hood a 'vtable' listing the functions associated with the typeclass.

它们是相似的(read: have similar use),并且可能实现类似:Haskell中的多态函数在引擎盖下有一个“vtable”,列出了与类型类相关的函数。

This table can often be deduced at compile time. This is probably less true in Java.

这张表通常可以在编译时推导出来。这在Java中可能不那么正确。

But this is a table of functions, not methods. Methods are bound to an object, Haskell typeclasses are not.

但这是一个函数表,不是方法表。方法绑定到一个对象,Haskell类型转换不是。

See them rather like Java's generics.

更像Java的泛型。

#10


2  

As Daniel says, interface implementations are defined seperately from data declarations. And as others have pointed out, there's a straightforward way to define operations that use the same free type in more than one place. So its easy to define Num as a typeclass. Thus in Haskell we get the syntactic benefits of operator overloading without actually having any magic overloaded operators -- just standard typeclasses.

正如Daniel所说,接口实现是与数据声明分开定义的。正如其他人指出的,有一种简单的方法可以定义在多个地方使用相同*类型的操作。因此很容易将Num定义为一个类型类。因此,在Haskell中,我们获得了操作符重载的语法优势,而实际上没有任何神奇的重载操作符——只是标准类型。

Another difference is that you can use methods based on a type, even when you don't have a concrete value of that type hanging around yet!

另一个区别是,您可以使用基于类型的方法,即使您还没有该类型的具体值!

For example, read :: Read a => String -> a. So if you have enough other type information hanging around about how you'll use the result of a "read", you can let the compiler figure out which dictionary to use for you.

例如,read:: read a => String -> a.因此,如果您有足够多的其他类型信息,关于如何使用“read”的结果,您可以让编译器找到要使用的字典。

You can also do things like instance (Read a) => Read [a] where... which lets you define a read instance for any list of readable things. I don't think that's quite possible in Java.

您还可以执行实例(Read a) => Read [a]等操作。它允许您为任何可读的内容定义一个读实例。我认为这在Java中不太可能实现。

And all this is just standard single-parameter typeclasses with no trickery going on. Once we introduce multi-parameter typeclasses, then a whole new world of possibilities opens up, and even more so with functional dependencies and type families, which let you embed much more information and computation in the type system.

所有这些只是标准的单参数类型的类型,没有任何欺骗。一旦我们引入了多参数类型转换,那么就会出现一个全新的可能性世界,而功能依赖项和类型族就更是如此,这使您可以在类型系统中嵌入更多的信息和计算。

#1


35  

I would say that an interface is kind of like a type class SomeInterface t where all of the values have the type t -> whatever (where whatever does not contain t). This is because with the kind of inheritance relationship in Java and similar languages, the method called depends on the type of object they are called on, and nothing else.

我想说一个接口有点像类型类SomeInterface t的所有值类型t - >不管(不包含t)。这是因为在Java的继承关系和类似的语言,调用的方法取决于类型的对象他们呼吁,而不是其它。

That means it's really hard to make things like add :: t -> t -> t with an interface, where it is polymorphic on more than one parameter, because there's no way for the interface to specify that the argument type and return type of the method is the same type as the type of the object it is called on (i.e. the "self" type). With Generics, there are kinda ways to fake this by making an interface with generic parameter that is expected to be the same type as the object itself, like how Comparable<T> does it, where you are expected to use Foo implements Comparable<Foo> so that the compareTo(T otherobject) kind of has type t -> t -> Ordering. But that still requires the programmer to follow this rule, and also causes headaches when people want to make a function that uses this interface, they have to have recursive generic type parameters.

这意味着真的很难让事情像添加::t - > - > t和一个接口,它是多态在一个以上的参数,因为没有办法接口指定方法的参数类型和返回类型是相同的类型为对象的类型是呼吁(即“自我”)。与泛型方法有有点假这通过一个接口与泛型参数,将相同类型的对象本身,像类似< T >如何,您将使用Foo实现类似< Foo >,以便compareTo(T otherobject)的类型T - > - >排序。但是这仍然需要程序员遵循这个规则,并且当人们想要创建一个使用这个接口的函数时,他们必须有递归的泛型参数。

Also, you won't have things like empty :: t because you're not calling a function here, so it isn't a method.

同样,也不会有empty:: t这样的函数,因为这里没有调用函数,所以它不是一个方法。

#2


31  

What is similar between interfaces and type classes is that they name and describe a set of related operations. The operations themselves are described via their names, inputs, and outputs. Likewise there may be many implementations of these operations that will likely differ in their implementation.

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

With that out of the way, here are some notable differences:

有了这些,这里有一些明显的区别:

  • Interfaces methods are always associated with an object instance. In other words, there is always an implied 'this' parameter that is the object on which the method is called. All inputs to a type class function are explicit.
  • 接口方法总是与一个对象实例相关联。换句话说,始终存在一个隐含的“this”参数,它是调用该方法的对象。类型类函数的所有输入都是显式的。
  • An interface implementation must be defined as part of the class that implements the interface. Conversely, a type class 'instance' can be defined completely seperate from its associated type...even in another module.
  • 接口实现必须定义为实现接口的类的一部分。相反,类型类“实例”可以从其关联类型中完全分离出来……即使是在另一个模块。
  • A type class allows you to define a 'default' implementation for any of the defined operations. Interfaces are strictly type specifications only, no implementation.
  • 类型类允许您为任何已定义的操作定义“默认”实现。接口是严格的类型规范,没有实现。

In general, I think its fair to say that type classes are more powerful and flexible than interfaces. How would you define an interface for converting a string to some value or instance of the implementing type? It's certainly not impossible, but the result would not be intuitive or elegant. Have you ever wished it was possible to implement an interface for a type in some compiled library? These are both easy to accomplish with type classes.

总的来说,我认为可以说类型类比接口更强大、更灵活。如何定义将字符串转换为实现类型的值或实例的接口?这当然不是不可能的,但结果不会是直观的或优雅的。您是否曾经希望在某些已编译的库中实现类型的接口?这些都很容易通过类型类实现。

#3


18  

Type classes were created as a structured way to express "ad-hoc polymorphism", which is basically the technical term for overloaded functions. A type class definition looks something like this:

类型类是作为一种表示“ad-hoc多态性”的结构化方式创建的,“ad-hoc多态性”基本上是重载函数的技术术语。类型类定义如下:

class Foobar a where
    foo :: a -> a -> Bool
    bar :: String -> a

What this means is that, when you use apply the function foo to some arguments of a type that belong to the class Foobar, it looks up an implementation of foo specific to that type, and uses that. This is very similar to the situation with operator overloading in languages like C, except more flexible and generalized.

这意味着,当您对属于类Foobar的类型的参数应用函数foo时,它会查找特定于该类型的foo的实现,并使用它。这与C语言中操作符重载的情况非常相似,除了更灵活和一般化。

Interfaces serve a similar purpose in OO languages, but the underlying concept is somewhat different; OO languages come with a built-in notion of type hierarchies that Haskell simply doesn't have, which complicates matters in some ways because interfaces can involve both overloading by subtyping (i.e., calling methods on appropriate instances, subtypes implementing interfaces their supertypes do) and by flat type-based dispatch (since two classes implementing an interface may not have a common superclass that also implements it). Given the huge additional complexity introduced by subtyping, I suggest it's more helpful to think of type classes as an improved version of overloaded functions in a non-OO language.

接口在面向对象语言中有类似的用途,但是底层的概念有些不同;OO语言内置了Haskell所没有的类型层次结构概念,这在某些方面使问题变得复杂,因为接口可以通过子类型(例如,,在适当的实例上调用方法,子类型实现它们的超类型所做的接口)和通过基于平面类型的分派(因为实现接口的两个类可能没有同样实现它的公共超类)。考虑到子类型带来的巨大的额外复杂性,我建议将类型类看作非oo语言重载函数的改进版本会更有帮助。

Also worth noting is that type classes have vastly more flexible means of dispatch--interfaces generally apply only to the single class implementing it, whereas type classes are defined for a type, which can appear anywhere in the signature of the class's functions. The equivalent of this in OO interfaces would be allowing the interface to define ways to pass an object of that class to other classes, define static methods and constructors that would select an implementation based on what return type is required in calling context, define methods that take arguments of the same type as the class implementing the interface, and various other things that don't really translate at all.

同样值得注意的是,类型类具有更灵活的调度方法——接口通常只应用于实现它的单个类,而类型类定义为类型,它可以出现在类函数的签名中任何地方。相当于在OO接口将允许接口定义的方法将该类的一个对象传递给其他类,定义静态方法和构造函数,选择一个实现基于返回类型需要在调用上下文中,相同类型的方法,把参数定义为类实现的接口,和其他各种事情真的不翻译。

In short: They serve similar purposes, but the way they work is somewhat different, and type classes are both significantly more expressive and, in some cases, simpler to use because of working on fixed types rather that pieces of an inheritance hierarchy.

简而言之:它们服务于类似的目的,但它们的工作方式有所不同,而且类型类的表达性都显著提高,而且在某些情况下,由于使用固定类型而不是继承层次结构的片段,使用起来更简单。

#4


7  

In Master minds of Programming, there's an interview about Haskell with Phil Wadler, the inventor of type classes, who explain the similarities between interfaces in Java and type classes in Haskell:

在《编程大师头脑》(Master of Programming)一书中,有一篇关于Haskell的采访,作者是type类的发明人Phil Wadler,他解释了Java中的接口和Haskell中的type类之间的相似性:

A Java method like:

Java方法:

   public static <T extends Comparable<T>> T min (T x, T y) 
   {
      if (x.compare(y) < 0)
            x; 
      else
            y; 
   }

is very similar to the Haskell method:

与Haskell方法非常相似:

   min :: Ord a => a -> a -> a
   min x y  = if x < y then x else y

So, type classes are related to interfaces, but the real correspondance would be a static method parametrized with a type as above.

因此,类型类与接口有关,但真正的对应关系将是一个静态方法,该方法会用上面的类型进行参数化。

#5


7  

I've read the above answers. I feel I can answer slightly more clearly:

我读过上面的答案。我觉得我可以更清楚地回答:

A Haskell "type class" and a Java/C# "interface" or a Scala "trait" are basically analogous. There is no conceptual distinction between them but there are implementation differences:

Haskell“type类”和Java/ c#“interface”或Scala“trait”基本上是相似的。它们之间没有概念上的区别,但有执行上的区别:

  • Haskell type classes are implemented with "instances" that are separate from the data type definition. In C#/Java/Scala, the interfaces/traits must be implemented in the class definition.
  • Haskell类型类是用与数据类型定义分离的“实例”实现的。在c# /Java/Scala中,接口/特性必须在类定义中实现。
  • Haskell type classes allow you to return a this type or self type. Scala traits do as well (this.type). Note that "self types" in Scala are a completely unrelated feature. Java/C# require a messy workaround with generics to approximate this behavior.
  • Haskell类型类允许您返回此类型或自类型。Scala特性也很好(this.type)。注意,Scala中的“自类型”是一个完全不相关的特性。Java/ c#需要使用泛型进行混乱的处理,以近似这种行为。
  • Haskell type classes let you define functions (including constants) without an input "this" type parameter. Java/C# interfaces and Scala traits require a "this" input parameter on all functions.
  • Haskell类型类允许您定义函数(包括常量),而无需输入“this”类型参数。Java/ c#接口和Scala特性要求所有函数都有一个“this”输入参数。
  • Haskell type classes let you define default implementations for functions. So do Scala traits and Java 8+ interfaces. C# can approximate something like this with extensions methods.
  • Haskell类型类允许定义函数的默认实现。Scala特性和Java 8+接口也是如此。c#可以使用扩展方法来近似这样的东西。

#6


6  

Watch Phillip Wadler's talk Faith, Evolution, and Programming Languages. Wadler worked on Haskell and was a major contributor to Java Generics.

看Phillip Wadler的谈话信仰,进化和编程语言。Wadler研究Haskell,并且是Java泛型的主要贡献者。

#7


6  

Read Software Extension and Integration with Type Classes where examples are given of how type classes can solve a number of problems that interfaces cannot.

阅读软件扩展和与类型类的集成,其中给出了类型类如何解决接口无法解决的许多问题的示例。

Examples listed in the paper are: the expression problem, the framework integration problem, the problem of independent extensibility, the tyranny of the dominant decomposition, scattering and tangling.

本文列举的例子有:表达式问题、框架集成问题、独立可扩展性问题、主导分解的专制问题、分散问题和纠缠问题。

#8


5  

I can't speak to the "hype"-level, if it seems that way fine. But yes type classes are similar in lots of ways. One difference that I can think of is that it Haskell you can provide behavior for some of the type class's operations:

我不能用“炒作”这个词来形容,如果它看起来不错的话。但是yes类型类在很多方面是相似的。我能想到的一个区别是Haskell可以为类型类的一些操作提供行为:

class  Eq a  where
  (==), (/=) :: a -> a -> Bool
  x /= y     = not (x == y)
  x == y     = not (x /= y)

which shows that there are two operations, equal (==), and not-equal (/=), for things that are instances of the Eq type class. But the not-equal operation is defined in terms of equals (so that you'd only have to provide one), and vice versa.

这表明对于属于Eq类型类的实例,有两个操作,即equal(=)和not equal(/=)。但是,不平等的操作是用equals(所以你只需要提供一个)来定义的,反之亦然。

So in probably-not-legal-Java that would be something like:

所以在可能不合法的java中

interface Equal<T> {
    bool isEqual(T other) {
        return !isNotEqual(other); 
    }

    bool isNotEqual(T other) {
        return !isEqual(other); 
    }
}

and the way that it would work is that you'd only need to provide one of those methods to implement the interface. So I'd say that the ability to provide a sort of partial implemention of the behavior you want at the interface level is a difference.

它的工作方式是你只需要提供其中一个方法来实现接口。我想说的是,在接口层提供某种行为部分实现的能力是不同的。

#9


4  

They are similar (read: have similar use), and probably implemented similarly: polymorphic functions in Haskell take under the hood a 'vtable' listing the functions associated with the typeclass.

它们是相似的(read: have similar use),并且可能实现类似:Haskell中的多态函数在引擎盖下有一个“vtable”,列出了与类型类相关的函数。

This table can often be deduced at compile time. This is probably less true in Java.

这张表通常可以在编译时推导出来。这在Java中可能不那么正确。

But this is a table of functions, not methods. Methods are bound to an object, Haskell typeclasses are not.

但这是一个函数表,不是方法表。方法绑定到一个对象,Haskell类型转换不是。

See them rather like Java's generics.

更像Java的泛型。

#10


2  

As Daniel says, interface implementations are defined seperately from data declarations. And as others have pointed out, there's a straightforward way to define operations that use the same free type in more than one place. So its easy to define Num as a typeclass. Thus in Haskell we get the syntactic benefits of operator overloading without actually having any magic overloaded operators -- just standard typeclasses.

正如Daniel所说,接口实现是与数据声明分开定义的。正如其他人指出的,有一种简单的方法可以定义在多个地方使用相同*类型的操作。因此很容易将Num定义为一个类型类。因此,在Haskell中,我们获得了操作符重载的语法优势,而实际上没有任何神奇的重载操作符——只是标准类型。

Another difference is that you can use methods based on a type, even when you don't have a concrete value of that type hanging around yet!

另一个区别是,您可以使用基于类型的方法,即使您还没有该类型的具体值!

For example, read :: Read a => String -> a. So if you have enough other type information hanging around about how you'll use the result of a "read", you can let the compiler figure out which dictionary to use for you.

例如,read:: read a => String -> a.因此,如果您有足够多的其他类型信息,关于如何使用“read”的结果,您可以让编译器找到要使用的字典。

You can also do things like instance (Read a) => Read [a] where... which lets you define a read instance for any list of readable things. I don't think that's quite possible in Java.

您还可以执行实例(Read a) => Read [a]等操作。它允许您为任何可读的内容定义一个读实例。我认为这在Java中不太可能实现。

And all this is just standard single-parameter typeclasses with no trickery going on. Once we introduce multi-parameter typeclasses, then a whole new world of possibilities opens up, and even more so with functional dependencies and type families, which let you embed much more information and computation in the type system.

所有这些只是标准的单参数类型的类型,没有任何欺骗。一旦我们引入了多参数类型转换,那么就会出现一个全新的可能性世界,而功能依赖项和类型族就更是如此,这使您可以在类型系统中嵌入更多的信息和计算。