本質的に問題は、 の型を設定しても、a
の型が何であるかがコンパイラに通知されないことb
です。クラスのインスタンスは 1 つしかないため ( isとis )、誰でもいつでも新しいインスタンスを追加できると思うかもしれません。したがって、インスタンスが1 つしかないという事実は、コンパイラが必要な型を決定するのに役立ちません。a
MyString
b
Char
これに対する解決策は、Functional Dependencies または Type Families を使用することです。後者は新しいソリューションであり、最終的には前者を「置き換える」ことを意図していますが、現時点では両方とも完全にサポートされています。FDがなくなるかどうかはまだわかりません。とにかく、FDの場合:
class Listy a b | a -> b where ...
基本的に、これは「それぞれに対して1つのクラスインスタンスしか存在できない」ことを示していますa
。つまり、 がわかれば、a
いつでも を決定できますb
。(しかし、その逆ではありません。) クラスの残りの部分は、以前と同じように見えます。
代替手段は TF です。
class Listy a where
type Element a :: *
...
instance Listy MyString where
type Element MyString = Char
...
2 番目のタイプが と呼ばれる代わりに、 と呼ばれるようb
になりElement a
ました。この単語Element
は、listy 型を受け取り、対応する要素型を返すクラス メソッドのように機能します。その後、次のことができます
instance Listy ByteString where
type Element ByteString = Word8
...
instance Listy [x] where
type Element [x] = x
...
instance Ord x => Listy (Set x) where
type Element (Set x) = x
...
等々。(Listy
必ずしも上記のすべての型に意味があるわけではありません。これらは、クラスを定義する方法の単なる例です。)