Diversión con los tipos! Resolviendo declaraciones de múltiples instancias

Estoy tratando de escribir un código Haskell en el que hay varios tipos de datos, cada uno de los cuales puede tener varias implementaciones. Para ello, defino cada tipo de datos comoclass cuyos métodos son los constructores y selectores relevantes, y luego implementar todas las operaciones en los miembros de esa clase en términos de los constructores y selectores dados.

Por ejemplo, tal vezA Es una clase polinomial (con métodosgetCoefficients ymakePolynomial) que puede tener una representación comoSparsePoly o unDensePoly yB es una clase de número complejo (con métodosgetReal, getImag ymakeComplex) que se puede representar como unComplexCartesian o unComplexPolar.

He reproducido un ejemplo mínimo a continuación. Tengo dos clasesA yB Cada uno de los cuales tiene una implementación. Quiero convertir todas las instancias de ambas clases en instancias deNum automáticamente (esto requiere laFlexibleInstances yUndecidableInstances extensiones de tipo). Esto funciona bien cuando solo tengo uno deA oB, pero cuando intento compilar con ambos, aparece el siguiente error:

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

Supongo que el mensaje 'declaraciones de instancia duplicadas' se debe a que un tipo de datos podría convertirse en una instancia de ambosA yB. Quiero poder prometerle al compilador que no lo haré, o posiblemente especificar una clase predeterminada para usar en el caso de que un tipo sea una instancia de ambas clases.

¿Hay alguna forma de hacer esto (quizás otra extensión de tipo?) O es algo con lo que estoy atrapado?

Aquí está mi 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 aclararme, no estoy tratando de escribir ningún código práctico utilizando esta técnica. Lo hago como un ejercicio para ayudarme a entender mejor el sistema de tipos y las extensiones.

Respuestas a la pregunta(2)

Su respuesta a la pregunta