我正在尝试为Eq
新类型编写EitherT
个实例,其中包含:
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
的声明预计它是* -> *
。{/ p>
我想知道我需要做什么,声明我想要一个Eq
实例用于某些更高级别的m
类型Eq
来为EitherT
实现{-# LANGUAGE UndecideableInstances #-}
instance (Eq (m (Either e a))) => Eq (EitherT e m a) where
a == b = (runEitherT a) == (runEitherT b)
} newtype。
编辑正如@AlexisKing所指出的,我可以使用它:
Eq
然而,我觉得编写这个I0 = imread('1_2.jpg');
[R,C,K] = size(I0);
if K==1
I1 = I0;
else
I1 = rgb2gray(I0);
end
T = adaptthresh(I1, 0.4); %adaptive thresholding
% Convert image to binary image, specifying the threshold value.
BW = imbinarize(I1,T);
% Display the original image with the binary version, side-by-side.
figure
imshowpair(I1, BW, 'montage')
实例需要语言扩展似乎很奇怪。在vanilla Haskell中没有其他方法可以表达这样的类型类约束吗?如果没有,为什么?
答案 0 :(得分:6)
您正在寻找自{4.9}以来Data.Functor.Classes
以来的Eq1
。在此之前,它位于-extras
个包中的一个或transformers
? (它是in transformers now since 0.4.0.0)
Eq1 f
表示您可以比较f
只要您有办法比较其内容
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)
答案 1 :(得分:2)
值得注意的是,此实例已存在于either
包的当前版本中(尽管不是旧的EitherT
包,这被认为是过时的):
instance Eq (m (Either e a)) => Eq (EitherT e m a) where
(==) = (==) on runEitherT
当然,正如@Alexis King所说,它需要UndecidableInstances
,但either
包是由Edward Kmett创作的,他是臭名昭着的dilettante和业余爱好者,他们不能像我们一样编写适当的Haskell98 < em>真正的程序员。 ;)