我正在尝试创建一个定义两个函数的类型类。一个叫做numMatching。它需要两个值并返回第二个值中第一个值的出现次数。例如:numMatching 1 1 = 1,因为第一个值1在第二个值1中出现一次.numMatching 1 0 = 0,因为第一个值永远不会出现在第二个值0中。
现在我已经定义了这个类:
class Counter a where
numMatching :: a -> a -> Int
numNonMatching :: a -> a -> Int
我正在尝试为Int类型创建此类的实例,但我确实如此 困惑。
instance Counter Int where
numMatching a b =
if a == b
then 1
else 0
我尝试通过输入numMatching 1在ghci中运行此函数。它应返回值1但我收到错误说我需要一个类型注释来指定a和b是什么。
任何帮助将不胜感激:)
答案 0 :(得分:1)
首先,1
的类型不是Int
,而是:
GHCi> :t 1
1 :: Num p => p
这意味着1
文字可以代表Num
实例的任何类型的值,具体类型取决于您如何使用它。这就是为什么1 + 2 :: Integer
和1 + 2.5 :: Double
工作的原因:1
在一个案例中是Integer
,在另一个案例中是Double
。 (+)
的类型是......
GHCi> :t (+)
(+) :: Num a => a -> a -> a
...因此,如果您说1 + 2
的结果应该是Integer
,那么GHC会推断1
和2
的类型应该是Integer
1}},因为(+)
的结果与其参数的类型相同。
现在,我们来看看numMatching
的类型:
GHCi> :t numMatching
numMatching :: Counter a => a -> a -> Int
我们知道numMatching
的结果是Int
,但与(+)
的结果不同,它不会告诉我们参数的类型。因此,GHC没有足够的信息来决定应该选择Num
的哪个实例作为1
中numMatching 1 1
的类型。这就是“模糊类型变量[...]阻止约束[...]被解决”的意思。无法为1
选择类型的后果之一是无法选择Counter
的实例,甚至无法确定是否存在实例(例如,您已为Int
定义了一个{1}},但不适用于Double
)。这就是为什么你单独提到Counter
的错误。
要在保留实例的同时避免此问题(即保留Int
实例而不必添加任何其他实例),请向1
中的任意一个添加显式类型注释。你转到numMatching
:
GHCi> numMatching (1 :: Int) 1
1
请注意,如果其中一个参数已经具有具体类型,则不需要额外的注释:
GHCi> :{
GHCi| foo :: Int
GHCi| foo = 1
GHCi| :}
GHCi> :t foo
foo :: Int
GHCi> numMatching foo 1
1
为了对比起见:
GHCi> numMatching (1 :: Double) 1
<interactive>:64:1: error:
* No instance for (Counter Double)
arising from a use of `numMatching'
* In the expression: numMatching (1 :: Double) 1
In an equation for `it': it = numMatching (1 :: Double) 1