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.