我最近一直在玩RankNTypes并想知道是否可以使用它们 在实例声明中。
这是一个使用open数据类型的简单示例
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),但基本上我只想写一些像(forall a。评估a)。这甚至可能吗?
此致 raichoo
答案 0 :(得分:4)
(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)