2010-10-18 12 views
5

He estado jugando con RankNTypes recientemente y me pregunto si es posible usarlos en declaraciones de instancias.RankNTypes para declaraciones de instancia?

Aquí está un ejemplo simple que utiliza tipos de datos abiertos

data (Expr a, Expr b) => Add a b = Add a b deriving(Show)       

instance (Expr a, Expr b) => Expr (Add a b) 

instance (Evaluation a, Evaluation b) => Evaluation (Add a b) where 
    eval (Add x y) = eval x + eval y 

Aquí tengo que escribir restricciones similares (evaluación a, Evaluación b), pero básicamente sólo quiero un escribir algo como (forall a. Evaluación de una) ¿Esto es posible?

Saludos, raichoo

Respuesta

4

(forall a . Evaluation a) no tiene mucho sentido: eso significaría que cada solo tipo (incluyendo cualquier tipo de futuro que alguien podría hacer) era una instancia de Evaluation.

Además, en este caso, creo que su código que enumera las instancias de Evaluation que desea es lo correcto; no exija más de lo que realmente necesita.

Pero ciertamente hay casos en los que sería bueno poder cuantificar las restricciones de clase a lo largo de las líneas que describe, y no es posible directamente. Un ejemplo es que es posible que desee realizar de forma automática MonadPlus casos de Monoid (utilizando un tipo de envoltorio para evitar problemas OverlappingInstances):

newtype MonoidWrapper m a = MonoidWrapper { unMonoidWrapper :: m a } 

instance Monad m => Monad (MonoidWrapper m) where ... 

instance (Monad m, forall a . Monoid (m a)) => MonadPlus (MonoidWrapper m) where 
    mzero = MonoidWrapper mempty 
    mplus (MonoidWrapper a) (MonoidWrapper b) = MonoidWrapper (mappend a b) 

no se puede escribir esto, pero utilizando GADTs o tipos existenciales puede simular que, con un poco de dolor sintáctico:

data MonoidDict a where 
    MonoidDict :: Monoid a => MonoidDict a 

class AlwaysMonoid m where 
    alwaysMonoidDict :: MonoidDict (m a) -- note the implicit forall a here 

instance Monad m => Monad (MonoidWrapper m) 

instance (Monad m, AlwaysMonoid m) => MonadPlus (MonoidWrapper m) where 
    mzero = mymzero 
    where 
     -- needed to give name to 'a' for ScopedTypeVariables 
     mymzero :: forall a . MonoidWrapper m a 
     mymzero = case (alwaysMonoidDict :: MonoidDict (m a)) of 
        MonoidDict -> MonoidWrapper mempty 
    mplus = mymplus 
    where 
     mymplus :: forall a . MonoidWrapper m a 
       -> MonoidWrapper m a -> MonoidWrapper m a 
     mymplus (MonoidWrapper a) (MonoidWrapper b) 
     = case (alwaysMonoidDict :: MonoidDict (m a)) of 
      MonoidDict -> MonoidWrapper (mappend a b) 
+0

Gracias, jugaré un poco con esto :) – raichoo

Cuestiones relacionadas