rai*_*hoo 5 haskell types type-systems higher-rank-types
我最近一直在玩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
Run Code Online (Sandbox Code Playgroud)
在这里,我必须编写约束(评估a,评估b),但基本上我只想写一些像(forall a.评估a).这甚至可能吗?
问候,raichoo
(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)
Run Code Online (Sandbox Code Playgroud)
你不能写这个,但使用 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)
Run Code Online (Sandbox Code Playgroud)