RankNTypes для объявлений экземпляров? - PullRequest
5 голосов
/ 18 октября 2010

Я недавно поигрался с RankNTypes и думаю, можно ли их использовать? в объявлениях экземпляров.

Вот простой пример использования открытых типов данных

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

Здесь я должен написать такие ограничения, как (Оценка a, Оценка b), но в основном я просто хочу написать что-то вроде (далее a. Оценка a). Это вообще возможно?

С уважением, raichoo

1 Ответ

4 голосов
/ 18 октября 2010

(forall a . Evaluation a) на самом деле не имеет смысла: это будет означать, что каждый отдельный тип (включая любой будущий тип, который кто-то может создать) был экземпляром Evaluation.

Кроме того, в этом случае я думаю, что ваш код, в котором перечислены экземпляры Evaluation, которые вы хотите, является правильным решением; не требуй больше, чем нужно на самом деле.

Но, безусловно, бывают случаи, когда было бы неплохо иметь возможность количественно определить ограничения классов в соответствии с описанными вами линиями, и это невозможно сделать напрямую. Одним из примеров является то, что вы можете автоматически создать MonadPlus экземпляров из Monoid (используя тип оболочки, чтобы избежать проблем 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)

Вы не можете написать это, но используя GADT или экзистенциальные типы, вы можете смоделировать это с некоторой синтаксической болью:

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)
...