我正在开发一个专业的数字数据处理库,但是我遇到了一个错误,不知道如何解决。我认为先展示一个例子,然后再解释我的问题会更容易一些。另外,对于奇怪的名称,我需要进行混淆以符合法律要求。
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
data MyError = MyError String deriving (Eq, Show)
data MyList = MyList [Double] deriving (Eq, Show)
data NamedList = NamedList String MyList deriving (Eq, Show)
class MyNum a b ret where
myAdd :: a -> b -> Either MyError ret
myLessThan :: a -> b -> Either MyError Bool
instance MyNum MyList Double MyList where
myAdd (MyList xs) x = Right $ MyList $ map (+x) xs
myLessThan (MyList xs) x = Right $ all (< x) xs
instance MyNum NamedList Double NamedList where
myAdd (NamedList n l) x = fmap (NamedList n) $ myAdd l x
myLessThan (NamedList n l) x = myLessThan l x
如果我尝试编译这个,就会出现错误
No instance for (MyNum MyList Double ret0)
arising from a use of `myLessThan'
The type variable `ret0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there is a potential instance available:
instance MyNum MyList Double MyList
-- Defined at testing_instances.hs:13:10
Possible fix:
add an instance declaration for (MyNum MyList Double ret0)
In the expression: myLessThan l x
In an equation for `myLessThan':
myLessThan (NamedList n l) x = myLessThan l x
In the instance declaration for `MyNum NamedList Double NamedList'
因为编译器无法确定在
MyList
中使用哪个特定的MyNum
实例。对于myAdd
可以工作,因为可以轻松推导出MyNum
的返回类型,但是对于myLessThan
则不行。我想使用这个类型类,以便我可以轻松地添加细粒度错误处理,并且因为我的实际代码具有+、-、*、/、<、<=、>和>=等等运算,我想为MyNum Double MyList MyList
、MyNum MyList MyList MyList
等制作实例,以及NamedList
的类似实例。除非有更简单的方法来做到这一点,否则这样做是为了拥有多态的可交换运算符。
然而,我无法确定在第二个实例中为myLessThan
添加什么类型签名,以便它可以知道要使用哪个实例。我知道一种解决方案是将算术和比较运算符拆分为两个单独的类型类,但如果可能的话,我想避免这样做。