Ich versuche, einen Haskell-Code zu schreiben, in dem es mehrere Datentypen gibt, von denen jeder mehrere Implementierungen haben kann. Um dies zu tun, definiere ich jeden Datentyp als class
, deren Methoden die relevanten Konstruktoren und Selektoren sind, und dann alle Operationen auf Mitgliedern dieser Klasse in Bezug auf die gegebenen Konstruktoren und Selektoren implementieren.Spaß mit Typen! Auflösen mehrerer Instanzdeklarationen
beispielsweise vielleicht A
ein Polynom Klasse (mit Methoden getCoefficients
und makePolynomial
), die eine Darstellung als SparsePoly
oder DensePoly
und B
ist eine komplexe Zahl Klasse (getReal
mit Methoden, getImag
und makeComplex
) aufweisen kann, der sein kann, dargestellt als ComplexCartesian
oder ComplexPolar
.
Ich habe ein minimales Beispiel unten wiedergegeben. Ich habe zwei Klassen A
und B
von denen jede eine Implementierung hat. Ich möchte alle Instanzen beider Klassen automatisch in Instanzen von Num
setzen (dies erfordert die Typenerweiterungen und). Das funktioniert gut, wenn ich nur eine von A
oder B
habe, aber wenn ich versuche, mit beiden zu kompilieren, erhalte ich folgende Fehlermeldung:
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
Ich nehme an, dass die ‚doppelte Instanz Erklärungen‘ Nachricht ist, weil ein Datentyp könnte eine Instanz von A
und B
gemacht werden. Ich möchte dem Compiler versprechen können, dass ich das nicht tun werde, oder möglicherweise eine Standardklasse angeben, die verwendet werden soll, wenn ein Typ eine Instanz beider Klassen ist.
Gibt es eine Möglichkeit, dies zu tun (vielleicht eine andere Art Erweiterung?) Oder ist das etwas, mit dem ich festhalte?
Hier ist mein Code:
{-# 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
Edit: Um mich klar, ich versuche, keinen praktischen Code zu schreiben, mit dieser Technik. Ich mache es als eine Übung, um mir zu helfen, das Typsystem und Erweiterungen besser zu verstehen.
Verwandte: [Wie schreibe ich, "wenn Typklasse A, dann ist auch eine Instanz von b durch diese Definition."] (Http://StackOverflow.com/a/3216937/98117). – hammar