2010-10-18 5 views
5

J'ai récemment joué avec RankNTypes et je me demande s'il est possible de les utiliser dans les déclarations d'instance.RankNTypes pour les déclarations d'instance?

Voici un exemple simple en utilisant des types de données ouvertes

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 

Ici, je dois écrire des contraintes comme (l'évaluation a, évaluation b), mais au fond, je veux juste un écrire quelque chose comme (forall a. Une évaluation). Est-ce seulement possible?

Cordialement, raichoo

Répondre

4

(forall a . Evaluation a) ne fait pas vraiment de sens: cela voudrait dire que chaque type simple (y compris toute personne de type avenir pourrait faire) est une instance de Evaluation.

Aussi, dans ce cas, je pense que votre code listant les instances de Evaluation que vous voulez est la bonne chose à faire; Ne demandez pas plus que ce dont vous avez réellement besoin.

Mais il y a certainement des cas où il serait bien de pouvoir quantifier les contraintes de classe selon les lignes que vous décrivez, et ce n'est pas possible directement. Un exemple est que vous voudrez peut-être faire automatiquement MonadPlus instances de Monoid (en utilisant un type d'emballage pour éviter OverlappingInstances problèmes):

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) 

Vous ne pouvez pas écrire, mais en utilisant GADTs ou types existentiels vous pouvez simuler, avec un peu de douleur syntaxique:

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

Merci, je vais jouer un peu avec ça :) – raichoo

Questions connexes