繁体   English   中英

具有更高kinded类型的类型类约束

[英]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类型mEq实例来为我的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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM