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