这个错误意味着什么 - “版本检查定义所需的Num Char实例”?

时间:2013-07-10 04:37:26

标签: haskell

versioncheck::String -> String -> Bool
versioncheck [] [] = True

versioncheck (x:xs) [] 
    |x /= 0 = False
    |otherwise = versioncheck xs [] 

versioncheck (x:xs) (y:ys) 
  | x /= y = False
  | otherwise = versioncheck xs ys 

为什么我会收到错误 - “版本检查定义所需的Num Char实例”?

1 个答案:

答案 0 :(得分:7)

解决此类问题的一种方法 - 我可以推荐的方法 - 是将您的函数定义提供给编译器而不附带类型签名,然后使用交互式环境来检查类型编译器推断出函数。

在您的情况下,如果我们定义

versioncheck []     []     = True
versioncheck (x:xs) [] 
  |x /= 0                  = False
  |otherwise               = versioncheck xs [] 
versioncheck (x:xs) (y:ys) 
  | x /= y                 = False
  | otherwise              = versioncheck xs ys 

然后,在GHCi中,查询

> :type versioncheck

它给了我们

versioncheck :: (Eq a, Num a) => [a] -> [a] -> Bool

明确指出您的函数在两个列表上运行,其中元素来自相同类型a,并且此类型a应该属于具有值的类型的Eq类可以测试相等性和数值类型的类Num

这些类约束来自何处?第一个(对于Eq)由您将两个输入列表的元素与/=进行比较而引入。第二个(对于Num)您将第一个列表的元素与数值(0)进行比较。

现在,您提供的类型签名为String -> String -> Bool。由于字符串只是字符列表,因此会扩展为[Char] -> [Char] -> Bool。将此与推断的签名进行比较,您的签名会使用a实例化类型变量Char。至于Eqa的约束,这是可以的,因为Char确实是Eq的一个实例。但是,根据需要,Char不是Num的实例(因此编译器无法知道如何执行测试x /= 0);因此,类型错误。

一个解决方案是使用推断的签名,但如果它确实是您要处理的字符列表,则必须删除测试x /= 0并将x与一个字符值。例如:

versioncheck :: String -> String -> Bool
versioncheck []     []     = True
versioncheck (x:xs) []
  |x /= '0'                = False
  |otherwise               = versioncheck xs []
versioncheck (x:xs) (y:ys)
  | x /= y                 = False
  | otherwise              = versioncheck xs ys

(注意'0'中的引号)编译得很好。