2008-11-20 13 views
21

Por lo tanto, tengo un par de clases de tipos que usaré mucho, y quiero evitar especificar ambas cada vez. Básicamente, en lugar de ponerTaquigrafía de Haskell Typeclass

:: (Ord a, Fractional a, Ord b, Fractional b, ... Ord z, Fractional z) => 

al comienzo de todos mis especificaciones de tipo, prefiero poner

:: (OrdFractional a, OrdFractional b, ... OrdFractional z) 

lo tanto, mi primera idea sobre cómo hacer esto fue declarar que una nueva clase de tipos

module Example where 

class (Fractional a, Ord a) => OrdFractional a 

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool 
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3) 

Pero esto no funcionó como automagicamente como yo deseaba que lo haría:

% ghci 
Prelude> :l Example.hs 
Ok, modules loaded: Example. 
Prelude Example> example (1::Float,3::Float) (2,2) (3,1) 

<interactive>:1:0: 
    No instance for (OrdFractional Float) 
     arising from a use of `example' at <interactive>:1:0-39 
    Possible fix: 
     add an instance declaration for (OrdFractional Float) 
    In the expression: example (1 :: Float, 3 :: Float) (2, 2) (3, 1) 
    In the definition of `it': 
     it = example (1 :: Float, 3 :: Float) (2, 2) (3, 1) 

Creación manual de casos parece como un lastre por lo que, al lado, pensé que podría tratar de crear automáticamente instancias:

module Example where 

class OrdFractional a 
instance (Fractional a, Ord a) => OrdFractional a 

example :: (OrdFractional a, OrdFractional b) => (a,b) -> (a,b) -> (a,b) -> Bool 
example (x1,y1) (x2,y2) (x3,y3) = (x1/x2 < x2/x3) && (y1/y2 < y2/y3) 

Pero el compilador no lo hicieron así:

ghc -c Example.hs 

Example.hs:4:0: 
    Illegal instance declaration for `OrdFractional a' 
     (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 `OrdFractional a' 

Así es Hay una forma en que puedo hacer esto?

Respuesta

32

Con la extensión ConstraintKinds introducido en GHC 7.4, las limitaciones son ahora tipos de clase Constraint, para que pueda utilizar sinónimos tipo ordinario para obtener lo que quiere:

{-# LANGUAGE ConstraintKinds #-} 

type OrdFractional a = (Ord a, Fractional a) 
10

Cuando el compilador dice "Use -XFlexibleInstances", usted debe tratar de añadir

{-# LANGUAGE FlexibleInstances #-} 

a la parte superior de su fuente (y vaya leer la documentación para aprender lo que se lo hace, por supuesto!).

En este caso específico, esto hará que su código de trabajo: se requieren

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} 

casos flexibles con el fin de permitir que el contexto => en la cabeza instancia, y se requieren instancias undecidable porque el compilador, al manejar un contexto OrdFractional a, puede terminar agregando Fractional a y Ord a al contexto, lo que no ayuda directamente a determinar finalmente a, y en circunstancias horriblemente adecuadas, la verificación de tipo puede divergir; al compilador realmente no le gusta eso. (Es probable que no le gustaría que si el compilador se encendió para siempre o se quedó sin memoria, tampoco.)

3

Su solución de una superclase implica las otras clases es el más cercano a lo que usted quiere que es posible en Haskell. Aunque eso requiere instancias manuales de esa nueva clase, a veces se usa, por ejemplo, en la biblioteca rewriting.

Como CesarB mencionó los alias de clases hacen lo que quieren (y más), pero son solo una propuesta que ha existido desde hace años y nunca se han implementado, probablemente porque hay numerosos problemas con ella. En cambio, varias otras propuestas han surgido, pero ninguna de ellas se implementó tampoco. (Para obtener una lista de esas propuestas, consulte este Haskellwiki page). Uno de los proyectos en Hac5 fue modificar el GHC para incluir un pequeño subconjunto de alias de clase llamados sinónimos de contexto (que hacen exactamente lo que está pidiendo aquí y nada más), pero lamentablemente nunca se terminó.

+3

La nueva extensión ConstraintKinds debe permitir que los sinónimos de contexto. –

Cuestiones relacionadas