型クラスと高いkinded種類の私の理解を明確にするために、この質問を、私はJavaでの回避策を探していませんよ。
Haskellでは、私のような何かを書くことができ
class Negatable t where
negate :: t -> t
normalize :: (Negatable t) => t -> t
normalize x = negate (negate x)
次に仮定は、Bool
のインスタンスを有しNegatable
、
v :: Bool
v = normalize True
そして、すべてが正常に動作します。
Javaでは、適切に宣言することはできていないようNegatable
インターフェイスを。私たちは書くことができます:
interface Negatable {
Negatable negate();
}
Negatable normalize(Negatable a) {
a.negate().negate();
}
しかし、その後、Haskellのとは異なり、次のようにキャスト(前提とせずにコンパイルされないでしょうMyBoolean
が実装しますNegatable
):
MyBoolean val = normalize(new MyBoolean()); // does not compile; val is a Negatable, not a MyBoolean
Javaインタフェースに実装するタイプを参照する方法はありますか、これはJavaの型システムの基本的な限界ですか?それは制限がある場合、それはより高いkindedタイプのサポートに関連していますか?私はそうは思いません:これは制限の別の一種であるように見えます。もしそうなら、それは名前を持っていますか?
おかげで、と質問が不明瞭であるなら、私に教えてください!
一般的には、ノー。
あなたは、することができます。この作業を行いますトリックを(他の回答で提案されているように)使用していますが、彼らはHaskellの型クラスが行うのと同じ保証のすべてを提供していません。具体的には、Haskellで、私はこのような関数を定義することができます。
doublyNegate :: Negatable t => t -> t
doublyNegate v = negate (negate v)
今の引数と戻り値があることが知られているdoublyNegate
の両方ですt
。しかし、Javaの同等:
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の型クラス、例えばの原因のトラブルを行いますEquatable
。Java実装の方法はありません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));
....
あなたは、その事実による期待equalTo
本当にあればという、対称的に定義されるべきであるif
ため、ステートメントがコンパイル、アサーションもコンパイルだろうが、そうでないMyClass
とequatableではないAnother
他の方法は、周りの真であるにもかかわらず、 。しかし、HaskellのとEquatable
型クラス、私たちは、場合ことを知っているareEqual a b
作品は、その後areEqual b a
も有効です。[1]
型クラスに対するインターフェースの別の制限は、型クラスは、既存の値(例えばなく型クラスを実装値を作成する手段を提供することができるということであるreturn
ため、オペレータのMonad
インタフェースのためにすでにタイプのオブジェクトを有していなければならないのに対し、)そのメソッドを呼び出すことができるようにするためです。
あなたはこの制限の名前があるかどうかを尋ねるが、私は1つを認識していませんよ。それは彼らがこの根本的に異なる方法で実装されているので、型クラスは、それらの類似性にもかかわらず、実際にオブジェクト指向インターフェースに異なるため、単純だ:オブジェクトは、そのインターフェイスのサブタイプであり、従って直接それらを変更することなく、インターフェースのメソッドのコピーの周りに運びます定義、型クラスは、型変数を代入することにより、カスタマイズされた各々が機能の別のリストです。タイプとタイプのインスタンスを有する型クラスの間にはサブタイプ関係が存在しない(HaskellはInteger
のサブタイプではないComparable
、単にAが存在する:例えば、Comparable
関数がそのパラメータを比較できるようにする必要があり、これらのパラメータは整数ことが起こるたび周りに渡すことができるインスタンス)。
[1]:Haskellの==
演算子は、実際に型クラスを使用して実装され、Eq
Haskellで演算子オーバーロードは、Haskellのコードを読むに精通していない人々に混乱することができますので...私はこれを使用していません。