一般来说,不可以。
您可以使用技巧(如其他答案中所建议的)来使这项工作发挥作用,但它们并不能提供与Haskell typeclass相同的所有保证。具体来说,在Haskell中,我可以定义一个这样的函数:
doublyNegate :: Negatable t => t -> t
doublyNegate v = negate (negate v)
现在已知 的参数和返回值都是 。但 Java 的等价物是:doublyNegate
t
public <T extends Negatable<T>> T doublyNegate (Negatable<T> v)
{
return v.negate().negate();
}
没有,因为可以通过另一种类型实现:Negatable<T>
public class X implements Negatable<SomeNegatableClass> {
public SomeNegatableClass negate () { return new SomeNegatableClass(); }
public static void main (String[] args) {
new X().negate().negate(); // results in a SomeNegatableClass, not an X
}
对于此应用程序来说,这并不是特别严重,但确实会给其他 Haskell 类型类带来麻烦,例如.如果不使用其他对象并将该对象的实例发送到我们需要比较的值的任何位置,就无法实现Java类型类(例如:Equatable
Equatable
public interface Equatable<T> {
boolean equal (T a, T b);
}
public class MyClass
{
String str;
public static class MyClassEquatable implements Equatable<MyClass>
{
public boolean equal (MyClass a, MyClass b) {
return a.str.equals(b.str);
}
}
}
...
public <T> methodThatNeedsToEquateThings (T a, T b, Equatable<T> eq)
{
if (eq.equal (a, b)) { System.out.println ("they're equal!"); }
}
(实际上,这正是Haskell实现类型类的方式,但它隐藏了从您那里传递的参数,因此您无需弄清楚要将哪个实现发送到哪里)
尝试仅使用普通的Java接口来执行此操作会导致一些违反直觉的结果:
public interface Equatable<T extends Equatable<T>>
{
boolean equalTo (T other);
}
public MyClass implements Equatable<MyClass>
{
String str;
public boolean equalTo (MyClass other)
{
return str.equals(other.str);
}
}
public Another implements Equatable<MyClass>
{
public boolean equalTo (MyClass other)
{
return true;
}
}
....
MyClass a = ....;
Another b = ....;
if (b.equalTo(a))
assertTrue (a.equalTo(b));
....
你会期望,由于它确实应该对称地定义,如果那里的语句编译,断言也会编译,但它不会,因为即使相反的方式是正确的,它也不能等同于。但是对于Haskell类型类,我们知道如果有效,那么也是有效的。[1]equalTo
if
MyClass
Another
Equatable
areEqual a b
areEqual b a
接口与类型类的另一个限制是,类型类可以提供一种创建值的方法,该值在没有现有值(例如运算符 for )的情况下实现类型类,而对于接口,您必须已经具有该类型的对象才能调用其方法。return
Monad
你问这个限制是否有名字,但我不知道有一个。这仅仅是因为类型类实际上与面向对象的接口不同,尽管它们相似,因为它们是以这种根本不同的方式实现的:对象是其接口的子类型,因此直接携带接口方法的副本而不修改它们的定义,而类型类是一个单独的函数列表,每个函数都是通过替换类型变量来自定义的。类型和具有该类型实例的类型类之间没有子类型关系(例如,Haskell 不是 的子类型:只要函数需要能够比较其参数,并且这些参数恰好是 Integers),就可以传递一个实例。Integer
Comparable
Comparable
[1]:Haskell 运算符实际上是使用类型类实现的,...我没有使用过这个,因为Haskell中的运算符重载可能会让不熟悉Haskell代码的人感到困惑。==
Eq