Zabawa z typami! Rozwiązywanie wielu deklaracji instancji
Próbuję napisać kod Haskella, w którym istnieje wiele typów danych, z których każdy może mieć wiele implementacji. Aby to zrobić, definiuję każdy typ danych jakoclass
których metody są odpowiednimi konstruktorami i selektorami, a następnie implementują wszystkie operacje na elementach tej klasy w kategoriach podanych konstruktorów i selektorów.
Może na przykładA
jest klasą wielomianową (metodamigetCoefficients
imakePolynomial
), który może mieć reprezentację jakoSparsePoly
lub aDensePoly
iB
to klasa liczb zespolonych (z metodamigetReal
, getImag
imakeComplex
), który może być reprezentowany jakoComplexCartesian
lub aComplexPolar
.
Poniżej przedstawiłem minimalny przykład. Mam dwie klasyA
iB
każdy z nich ma implementację. Chcę, aby wszystkie instancje obu klas były instancjamiNum
automatycznie (to wymagaFlexibleInstances
iUndecidableInstances
wpisz rozszerzenia). To działa dobrze, gdy mam tylko jednąA
lubB
, ale gdy próbuję się skompilować za pomocą obu, pojawia się następujący błąd:
<code>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 </code>
Przypuszczam, że komunikat „zduplikowane deklaracje instancji” jest taki, że typ danych może być instancją obuA
iB
. Chcę być w stanie obiecać kompilatorowi, że tego nie zrobię, lub ewentualnie określić domyślną klasę, której należy użyć w przypadku, gdy typ jest instancją obu klas.
Czy jest jakiś sposób, aby to zrobić (może inne rozszerzenie typu?) Lub czy jest to coś, z czym utknąłem?
Oto mój kod:
<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 </code>
Edytować: Aby jasno wyrazić się, nie próbuję pisać żadnego praktycznego kodu przy użyciu tej techniki. Robię to, aby lepiej zrozumieć system typów i rozszerzenia.