Question

Je joue autour avec RankNTypes récemment et je me demande s'il est possible de les utiliser dans 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 les contraintes d'écriture comme (l'évaluation a, évaluation b), mais au fond, je veux juste un écrire quelque chose comme (forall a. Une évaluation). Est-ce même possible?

Cordialement, raichoo

Était-ce utile?

La solution

(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

En outre, dans ce cas, je pense que votre code listant les instances de Evaluation que vous voulez est la bonne chose à faire; ne demande pas plus que vous avez réellement besoin.

Mais il y a certainement des cas où il serait agréable d'être en mesure de quantifier sur les contraintes de classe le long des lignes que vous décrivez, et il est impossible directement. Un exemple est que vous pouvez effectuer automatiquement des instances MonadPlus de Monoid (en utilisant un type d'emballage pour éviter tout problème de 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)

Vous ne pouvez pas écrire, mais en utilisant GADTs ou types existentiels vous pouvez simuler, avec une certaine 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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top