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.

questionAnswers(2)

yourAnswerToTheQuestion