我想定义一个特定的仿函数如下:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
data ValOrError a b = Val a | Error b
class MF c a b where
mcons :: a -> c -> c
merr :: b -> c
mhead :: c -> ValOrError a b
mtail :: c -> ValOrError c b
我希望类型 c
上的类型类 MF
具有类型参数 a
和 b
. 我试着在这样的数据结构上定义一个过滤函数,如下所示:
mfilter f e =
let h = mhead e in
let t = mtail e in
case h of
Error b -> e
Val a -> case (f a) of
True -> case t of
Error d -> mcons a (merr d)
Val b -> mcons a (mfilter f b)
False -> case t of
Error d -> merr d
Val b -> mfilter f b
但是我收到以下错误:
haskell.hs:24:1:无法演绎(MF c a2 b3)
由'mfilter'的歧义检查引起的
从背景来看(MF c a5 b6,
MF c a4 b5,
MF c a4 b4,
MF c a4 b,
MF c a3 b6,
MF c a b6)
由'mfilter'的推断类型绑定:
(MF c a5 b6,MF c a4 b5,MF c a4 b4,
MF c a4 b,MF c a3 b6,MF c a b6)=>
(a4 - > Bool) - > c - > c
在haskell.hs:(24,1) - (35,28)
类型变量'a2','b3'是不明确的
检查'mfilter'时
具有推断类型'forall b c a b1 a1 a2 b2 a3 b3 .
(MF c a3 b3,MF c a2 b2,MF c a2 b1,
MF c a2 b,MF c a1 b3,MF c a b3)=>
(a2 - > Bool) - > c - > c'
可能原因:推断类型不明确
我想知道在haskell中是否有更好的方法来声明类型 c
总是有 a
和 b
作为类型参数 . 使用类似Java的语法:
public interface MF<A,B> {
MF<A,B> mcons(A head, MF<A,B> tail);
MF<A,B> merr(B error);
ValOrError<A,B> head(MF<A,B> e);
ValOrError<MF<A,B>,B> tail(MF<A,B> e);
}
另外,另一方面,过滤功能应该有一个类型:
mfilter :: (a -> Bool) -> MF c a b -> MF c a b
1 回答
从代码开始,最直接的方法是向类型类添加功能依赖:
这基本上只是告诉编译器
a
和b
的类型信息已经包含在c
中(因此可以在调用站点提取,因此a2
,b3
等不会是不明确的) . 当您定义instance MF
时,可以通过GHC确定如何准确提取此信息 . 虽然通常这种方法效果很好,但我觉得为什么要这样做有点疑问:如果c
始终具有X a b
形式(并且X
是一个可以部分应用的正确data
-type-函数),那么为什么甚至在课堂上提到a
和b
?他们基本上是多余的 . 为什么不给这个类一个参数(种类Type -> Type -> Type
)然后可以应用于a
和b
?或者,如果你真的希望
c
有一个Type
(这确实有意义!),我应该建议将类定义中的a
和b
类型存储为类型系列:这基本上等同于
TypeFamilies
解决方案,但是提供了一个更明确,更隐蔽(尽管也更冗长)的界面 .