2012-02-19 13 views
5

Tengo clases de tipo, para todas las cuales me gustaría tener un comportamiento común. Mi problema se explica en el siguiente código:Haskell No se pudo deducir ... del error de contexto

 
class A a 
class B b 

class X x where 
    method :: (A a, B b) => x -> a -> b 

data T = L | M | N 
data U = P | Q | R 

instance A T 
instance B U 

data Y = ZZZ 

instance X Y where 
    method _ L = P 
    method _ M = Q 
    method _ N = R 

Cuando cargo este módulo, me sale el siguiente error:

 
example.hs:19:14: 
    Could not deduce (a ~ T) 
    from the context (A a, B b) 
     bound by the type signature for method :: (A a, B b) => Y -> a -> b 
     at example.hs:(17,5)-(19,18) 
     `a' is a rigid type variable bound by 
      the type signature for method :: (A a, B b) => Y -> a -> b 
      at example.hs:17:5 
    In the pattern: N 
    In an equation for `method': method _ N = R 
    In the instance declaration for `X Y' 

example.hs:19:18: 
    Could not deduce (b ~ U) 
    from the context (A a, B b) 
     bound by the type signature for method :: (A a, B b) => Y -> a -> b 
     at example.hs:(17,5)-(19,18) 
     `b' is a rigid type variable bound by 
      the type signature for method :: (A a, B b) => Y -> a -> b 
      at example.hs:17:5 
    In the expression: R 
    In an equation for `method': method _ N = R 
    In the instance declaration for `X Y' 
Failed, modules loaded: none. 

estoy a saber qué hacer en este caso. Incluso cuando T y U son instancia de A y B, obtengo este error. Si no puedo devolver un valor de tipo rígido de method, ¿cómo codifico esta parte?

+0

posible duplicado de [listas de tipos de datos: "no se pudo deducir (un ~ SomeType) del contexto (SomeTypeclass a)"] (http://stackoverflow.com/questions/5453514/lists-of-data-types -podría-no-deducir-un-tipo-del-contexto-tipo) – Landei

Respuesta

9

La firma method :: (A a, B b) => x -> a -> b promete que method obras para cada par de tipos(a, b) con a una instancia de A y b una instancia de B, pero usted lo define para trabajar sólo con dos tipos específicos.

Esto es fundamentalmente diferente de las interfaces en Java o similares, donde el destinatario elige qué tipo se utiliza, lo único que la persona que llama sabe que la interfaz X está implementada. En Haskell, dada tal firma, la persona que llama decide qué tipos se utilizan (aquí, qué tipo se pasa como segundo argumento y qué tipo se devolverá) y el destinatario debe ser capaz de proporcionar la funcionalidad demandada (siempre que la demanda los tipos son instancias de las clases requeridas).

Sin ningún tipo de métodos en clases A y B para analizar respectivamente construir valores de una instancia de esa clase, no se puede poner en práctica method sí que con undefined (varios grados de indefinición son posibles debido a seq), por lo que tendría que contar el mundo que de hecho está usando T y U.

Otra forma es hacer una clase X tipo multiparamétrico,

{-# LANGUAGE MultiParamTypeClasses #-} 

class (A a, B b) => X x a b where 
    method :: x -> a -> b 

Sin embargo, eso podría requerir dependencias funcionales para resolver los casos. Otra manera sería utilizar tipos asociados,

{-# LANGUAGE TypeFamilies #-} 

class X x where 
    type AType x 
    type BType x 
    method :: x -> AType x -> BType x 

instance X Y where 
    type AType Y = T 
    type BType Y = U 
    method ... 
+0

Entendí tu punto. Tengo las clases de tipos Y, T, U trabajando juntas. Tengo otro trillizo de clases de tipo Y1, T1, U1 que funcionan juntas. En mi problema, estas clases de tipos forman instancias de un modelo. Me gustaría tener un código común que funcione en estos modelos sin importar cómo se implementan. Sin embargo, gracias por señalar el problema. Este tipo de código también sería un problema en los idiomas java. – mutelogan

+0

Se agregaron posibles alternativas –

+0

Gracias por la explicación. – mutelogan

3

Es muy difícil pensar en una manera de rescatar el ejemplo (por las razones mencionadas por Daniel Fischer). Si tiene dos clases de tipos A y B totalmente independientes, ¿cómo debería establecer una conexión general? Por lo que podría poner los dos juntos, pero dudo que esto es lo que quiere:

{-# LANGUAGE MultiParamTypeClasses #-} 

class A2B a b where 
    convert :: a -> b 

data T = L | M | N 
data U = P | Q | R 

instance A2B T U where 
    convert L = P 
    convert M = Q 
    convert N = R 

data Y = ZZZ 

class X x where 
    method :: (A2B a b) => x -> a -> b 

instance X Y where 
    method _ t = convert t 

Y este diseño no es muy estable, ya sea: Usted obtendrá en problemas cuando usted quiere tener casos como A2B T V junto a A2B T U.

Cuestiones relacionadas