2010-02-22 9 views
11

El propósito de esta parte del código en particular es hacer que la función size sea más eficiente que simplemente contar todos los elementos en elems. Me he decidido a sumar los dos tipos que componen la lista, pero parece que no puedo crear la firma de la función de tamaño.¿Cómo se puede comparar con el tipo "O bien una b"?

instance (Finite a, Finite b) => Finite (Either a b) where 
    elems = combineLists [Left x | x <- elems] [Right x | x <-elems] 
    size ??? = (size a) + (size b) 

De Preludio, sabemos que Either a b = Left a | Right b.

Lo primero que probé fue hacer coincidir Either, pero por supuesto es un tipo, por lo que no funciona. A continuación, intenté ((Left a) | (Right b)), pero tampoco voy a eso. Nada más parece coincidir con el tipo Either a b.

que era capaz de conseguir size (Left a) para compilar, pero desde que le falta el componente b, recibo el error:

Ambiguous type variable `b' in the constraint: 
    `Finite b' arising from a use of `size' at <interactive>:1:0-12 

que por supuesto tiene sentido en el contexto, pero realmente no tengo idea de cómo partido Either a b.

¿Alguien tiene alguna idea?

+1

Parece un poco confundido acerca de la diferencia entre un tipo y un constructor. "O bien un b" es un tipo con dos constructores, "Izquierda" y "Derecha". Los tipos van en firmas de tipo, mientras que los constructores entran en código. Esta es una confusión común porque muchos tipos usan el mismo nombre para el tipo y el constructor, como en "datos Foo = Foo Int String"; el primer "Foo" es el tipo, mientras que el segundo es el constructor. –

Respuesta

25

Algo del tipo Either a b es o bien un Left a o una Right b, por lo que tiene dos casos que se pueden manejar por separado:

size (Left x) = size x 
size (Right x) = size x 

El error acerca de la variable de tipo ambigua es un tema aparte. Si escribe algo como size (Left 1) en el intérprete, el sistema no puede deducir cuál sería el valor "Left 1". Podría ser Either Int anything y mientras no se sepa qué tipo es anything, no se puede verificar si está en la clase Finite (que es requerido por size).

Puede evitar este problema mediante la especificación de un tipo de firma explícita:

size (Left 1 :: Either Int String) 
0

El problema parece ser que necesita un argumento ficticio para size, pero no se puede pasar maniquíes para ambos tipos a y b en un solo Either a b. Tal vez se puede utilizar el elems para obtener un maniquí de cada tipo:

size _ = (size . head) (elems :: [a]) + (size . head) (elems :: [b]) 
0

creo que la raíz del problema que está teniendo es que quieres un tipo que representa un dato de cada uno de otros dos tipos al mismo tiempo. Either a b solo puede ser uno de a o b en un momento dado.

Un tipo de datos simple que representa un a y un b al mismo tiempo es un 2-tupla.La firma de tipo para que tal cosa es (a, b), que es también la expresión de la creación de uno, y por lo tanto el patrón maching uno:

> :type (4,5) 
(4,5) :: (Num t, Num t1) => (t, t1) 
> let f (a, b) = 2*a + b 
> f (4,5) 
13 

Debe tener en cuenta la escritura de su primera línea con una 2-tupla, así:

instance (Finite a, Finite b) => Finite (a, b) where 

¿Qué significa esto Finite (a, b)? ¿Cuáles serían las definiciones de funciones miembro?

+0

En realidad, ya he escrito la definición de eso, es el producto de ayb, creando un mapeo de todas las a para todas las b – Fry

Cuestiones relacionadas