Diversão com tipos! Resolvendo Declarações de Várias Instâncias

Eu estou tentando escrever algum código Haskell em que existem vários tipos de dados, cada um dos quais pode ter várias implementações. Para fazer isso, eu defino cada tipo de dados como umclass cujos métodos são os construtores e seletores relevantes e, em seguida, implementam todas as operações em membros dessa classe em termos dos construtores e seletores fornecidos.

Por exemplo, talvezA é uma classe polinomial (com métodosgetCoefficients emakePolynomial) que pode ter uma representação comoSparsePoly ou umDensePoly eB é uma classe numérica complexa (com métodosgetReal, getImag emakeComplex), que pode ser representado como umComplexCartesian ou umComplexPolar.

Eu reproduzi um exemplo mínimo abaixo. Eu tenho duas classesA eB cada um dos quais tem uma implementação. Eu quero fazer todas as instâncias de ambas as classes em instâncias deNum automaticamente (isso requer aFlexibleInstances eUndecidableInstances tipo extensões). Isso funciona bem quando eu só tenho um dosA ouB, mas quando tento compilar com ambos, recebo o seguinte erro:

<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>

Eu suponho que a mensagem 'declarações de instâncias duplicadas' é porque um tipo de dados pode ser feito uma instância de ambosA eB. Eu quero ser capaz de fazer uma promessa ao compilador que eu não farei isso, ou possivelmente especificar uma classe padrão para usar no caso em que um tipo é uma instância de ambas as classes.

Existe uma maneira de fazer isso (talvez outra extensão de tipo?) Ou isso é algo que eu estou preso?

Aqui está meu código:

<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>

Editar: Para deixar claro, não estou tentando escrever nenhum código prático usando essa técnica. Eu estou fazendo isso como um exercício para me ajudar a entender melhor o sistema de tipos e as extensões.

questionAnswers(2)

yourAnswerToTheQuestion