tipos reales por pantalla numero mostrar modulos leer impresion funciones declarar crear como haskell ghc typeclass type-systems

haskell - reales - ¿Por qué no puedo hacer que String sea una instancia de una clase de letra?



string en haskell (4)

Además de estas respuestas, si no se siente cómodo con el levantamiento de las restricciones, puede haber casos en los que podría tener sentido ajustar su Cadena en un nuevo tipo, que puede ser una instancia de una clase. La compensación sería una fealdad potencial, tener que envolver y desenvolver en su código.

Dado :

data Foo = FooString String … class Fooable a where --(is this a good way to name this?) toFoo :: a -> Foo

Quiero hacer de String una instancia de Fooable :

instance Fooable String where toFoo = FooString

GHC luego se queja:

Illegal instance declaration for `Fooable String'' (All instance types must be of the form (T t1 ... tn) where T is not a synonym. Use -XTypeSynonymInstances if you want to disable this.) In the instance declaration for `Fooable String''

Si, en cambio, uso [Char] :

instance Fooable [Char] where toFoo = FooString

GHC se queja:

Illegal instance declaration for `Fooable [Char]'' (All instance types must be of the form (T a1 ... an) where a1 ... an are type *variables*, and each type variable appears at most once in the instance head. Use -XFlexibleInstances if you want to disable this.) In the instance declaration for `Fooable [Char]''

Pregunta :

  • ¿Por qué no puedo hacer Cadena e instancia de una clase de letra?
  • GHC parece dispuesto a dejarme salir con esto si agrego una bandera extra. ¿Es esta una buena idea?

Esto se debe a que String es solo un alias de tipo para [Char] , que es solo la aplicación del constructor de tipo [] en el tipo Char , por lo que sería de la forma ([] Char) . que no es de la forma (T a1 .. an) porque Char no es una variable de tipo.

El motivo de esta restricción es evitar la superposición de instancias. Por ejemplo, supongamos que tienes una instance Fooable [Char] , y luego alguien apareció y definió una instance Fooable [a] . Ahora el compilador no podrá determinar cuál quiere usar y le dará un error.

Al usar -XFlexibleInstances , básicamente le está prometiendo al compilador que no definirá ninguna de esas instancias.

Dependiendo de lo que intente lograr, podría ser mejor definir un contenedor:

newtype Wrapper = Wrapper String instance Fooable Wrapper where ...


Las instancias flexibles no son una buena respuesta en la mayoría de los casos. Mejores alternativas son envolver el String en un newtype o introducir una clase de ayuda como sigue:

class Element a where listToFoo :: [a] -> Foo instance Element Char where listToFoo = FooString instance Element a => Fooable [a] where toFoo = listToFoo

Ver también: http://www.haskell.org/haskellwiki/List_instance


Te encuentras con dos limitaciones de las clases de tipos Haskell98 clásicos:

  • deshabilitan el tipo de sinónimos en instancias
  • deshabilitan los tipos anidados que, a su vez, no contienen variables de tipo.

Estas restricciones onerosas son levantadas por dos extensiones de idioma:

  • -XTypeSynonymInstances

que le permite usar synoyms tipo (como String para [Char] ), y:

  • -XFlexibleInstances

que levantan las restricciones sobre los tipos de instancia que son de la forma T ab .. donde los parámetros son variables de tipo. El -XFlexibleInstances permite al jefe de la declaración de instancia mencionar tipos anidados arbitrarios.

Tenga en cuenta que el levantamiento de estas restricciones a veces puede llevar a la superposición de instancias , en cuyo caso , podría necesitarse una extensión de lenguaje adicional para resolver la ambigüedad, permitiendo a GHC elegir una instancia para usted.

Referencias :