我正在尝试为 EitherT
newtype写一个 Eq
实例,由下式给出:
newtype EitherT e m a = EitherT { runEitherT :: m (Either e a) }
我假设以下 Eq
实例可行:
instance (Eq e, Eq a, Eq m) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
但是,我看到一个错误:
Expected kind '* -> *', but 'm' has kind '*'
我正在从那个错误中读到的是,我的类型类约束 ( ... Eq m) => ...
让编译器误以为我认为 m
是善良的 *
,当我的 EitherT
的newtype声明期望它是善良的 * -> *
时 .
我想知道我需要做什么,声明我想要一个更高的kinded类型 m
的 Eq
实例来为我的 EitherT
newtype实现 Eq
.
Edit: 正如@AlexisKing指出的那样,我可以使用它:
{-# LANGUAGE UndecideableInstances #-}
instance (Eq (m (Either e a))) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
但是,对于我来说,编写这个 Eq
实例需要语言扩展似乎很奇怪 . 在vanilla Haskell中没有其他方法可以表达这样的类型类约束吗?如果没有,为什么?
2 回答
你正在寻找
Eq1
,它位于Data.Functor.Classes,因为基数为4.9.0.0 . 在此之前它是-extras
包中的一个或transformers
? (这是in transformers now since 0.4.0.0)Eq1 f
表示你可以比较f
只要你有办法比较它们的内容在你的情况下,你会像它一样使用它
liftEq f
将使用Eq1
的现有Eq1
实例 .并且可以将
Eq
实例定义为旧的
Eq1
是在你的情况下,你会像它一样使用它
值得注意的是,这个实例已经存在于
either
包的当前版本中(尽管不是旧的EitherT
包,它被认为是过时的):当然,正如@Alexis King所说,它需要
UndecidableInstances
,但either
包是由Edward Kmett创作的,他是臭名昭着的dilettante和业余爱好者,他们不能像我们真正的程序员那样编写适当的Haskell98 . ;)