私は、それぞれが複数の実装を持つことができる複数のデータ型があるHaskellコードを書き込もうとしています。これを行うには、各データ型を、class
そのメソッドが関連するコンストラクターとセレクターであるとして定義し、次に、指定されたコンストラクターとセレクターに関して、そのクラスのメンバーに対するすべての操作を実装します。
たとえば、おそらくは、aまたはaとして表現できるA
多項式クラス(メソッドgetCoefficients
およびmakePolynomial
)であり、aまたはaとして表現できる複素数クラスSparsePoly
(メソッドおよび)です。DensePoly
B
getReal
getImag
makeComplex
ComplexCartesian
ComplexPolar
以下に最小限の例を再現しました。私には2つのクラスがA
あり、B
それぞれに実装があります。両方のクラスのすべてのインスタンスをNum
自動的にのインスタンスにしたい(これにはFlexibleInstances
とUndecidableInstances
タイプの拡張子が必要です)。A
これは、またはの1つしかない場合は正常に機能B
しますが、両方を使用してコンパイルしようとすると、次のエラーが発生します。
Duplicate instance declarations:
instance [overlap ok] (A a, Num x, Show (a x), Eq (a x)) =>
Num (a x)
-- Defined at test.hs:13:10-56
instance [overlap ok] (B b, Num x, Show (b x), Eq (b x)) =>
Num (b x)
-- Defined at test.hs:27:10-56
'重複インスタンス宣言'メッセージは、データ型がとの両方のインスタンスになる可能性があるためだと思いA
ますB
。コンパイラーにそうしないことを約束できるようにしたい、または型が両方のクラスのインスタンスである場合に使用するデフォルトのクラスを指定できるようにしたい。
これを行う方法はありますか(おそらく別のタイプの拡張機能ですか?)、またはこれは私が立ち往生しているものですか?
これが私のコードです:
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
class A a where
fa :: a x -> x
ga :: x -> a x
data AImpl x = AImpl x deriving (Eq,Show)
instance A AImpl where
fa (AImpl x) = x
ga x = AImpl x
instance (A a, Num x, Show (a x), Eq (a x)) => Num (a x) where
a1 + a2 = ga (fa a1 + fa a2)
-- other implementations go here
class B b where
fb :: b x -> x
gb :: x -> b x
data BImpl x = BImpl x deriving (Eq,Show)
instance B BImpl where
fb (BImpl x) = x
gb x = BImpl x
instance (B b, Num x, Show (b x), Eq (b x)) => Num (b x) where
-- implementations go here
編集:明確にするために、私はこの手法を使用して実用的なコードを作成しようとはしていません。型システムと拡張機能をよりよく理解するための演習として行っています。