2010-10-18 3 views
5

Ich habe kürzlich mit RankNTypes gespielt und frage mich, ob es möglich ist, sie in Instanz Deklarationen zu verwenden.RankNTypes für Instanzdeklarationen?

Hier ist ein einfaches Beispiel offene Datentypen mit

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 

Hier muss ich wie Einschränkungen schreiben (Bewertung a, Bewertung b), aber im Grunde will ich schreiben gerade so etwas wie (forall a. Auswertung a). Ist das überhaupt möglich?

Grüße, raichoo

Antwort

4

(forall a . Evaluation a) nicht wirklich Sinn: es würde bedeuten, dass jede einzelne Art (einschließlich aller künftigen Typ könnte jemand machen) eine Instanz von Evaluation war.

Auch in diesem Fall denke ich, dass Ihr Code die Instanzen von Evaluation, die Sie wollen, ist das Richtige zu tun; fordere nicht mehr, als du wirklich brauchst.

Aber es gibt sicherlich Fälle, in denen es gut wäre, Klassenbeschränkungen entlang der von Ihnen beschriebenen Grenzen zu quantifizieren, und dies ist nicht direkt möglich. Ein Beispiel dafür ist, dass Sie automatisch wünschen konnten MonadPlus Instanzen von Monoid (mit einem Wrapper OverlappingInstances Probleme zu vermeiden) machen:

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) 

du nicht schreiben kann, aber unter Verwendung von GADTs oder existentielle Typen, die Sie simulieren können, mit ein paar syntaktischen Schmerzen:

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

Danke, ich werde ein wenig damit spielen :) – raichoo

Verwandte Themen