![](/img/trans.png)
[英]How to define typeclass instance for higher kinded types in Scala?
[英]Typeclass constraints with higher kinded types
我正在尝试为以下给出的EitherT
编写一个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
声明期望它善良* -> *
。
我想知道我需要做什么,声明我想要一个更高的kinded类型m
的Eq
实例来为我的EitherT
实现Eq
。
编辑:正如@AlexisKing所指出的,我可以使用它:
{-# LANGUAGE UndecideableInstances #-}
instance (Eq (m (Either e a))) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
但是,对于我来说,编写此Eq
实例需要语言扩展似乎很奇怪。 在vanilla Haskell中没有其他方法可以表达这样的类型类约束吗? 如果没有,为什么?
您正在寻找Eq1
,它位于Data.Functor.Classes
因为它基于4.9.0.0。 在此之前它是在-extras
包或transformers
? ( 自0.4.0.0起,它现在在变形金刚中 )
Eq1 f
表示你可以比较f
s,只要你有办法比较它们的内容
class Eq1 f where
liftEq :: (a -> b -> Bool) -> f a -> f b -> Bool
在你的情况下,你会像它一样使用它
instance (Eq e, Eq1 m) => Eq1 (EitherT e m) where
liftEq f a b = liftEq (liftEq f) (runEitherT a) (runEitherT b)
liftEq f
是将现有的Eq1
实例用于Either
。
并且可以将Eq
实例定义为
instance (Eq e, Eq a, Eq1 m) => Eq (EitherT e m a) where
(==) = liftEq (==)
旧的Eq1
是
class Eq1 f where
eq1 :: (Eq a) => f a -> f a -> Bool
在你的情况下,你会像它一样使用它
instance (Eq e, Eq1 m) => Eq1 (EitherT e m) where
eq1 a b = eq1 (runEitherT a) (runEitherT b)
instance (Eq e, Eq a, Eq1 m) => Eq1 (EitherT e m) where
a == b = eq1 (runEitherT a) (runEitherT b)
值得注意的是,这个实例已经存在于either
包的当前版本中(尽管不是旧的EitherT
包,它被认为是过时的):
instance Eq (m (Either e a)) => Eq (EitherT e m a) where
(==) = (==) on runEitherT
当然,正如@Alexis King所指出的那样,它需要UndecidableInstances
,但这either
包都是由Edward Kmett创作的,他是臭名昭着的dilettante和业余爱好者,他们不能像我们真正的程序员那样编写适当的Haskell98。 ;)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.