0
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 实例”?

4

1 回答 1

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和数字类型类。

这些类约束从何而来?第一个 (for Eq) 是通过将两个输入列表的元素与 进行比较来引入的/=。第二个 (for Num) 通过将第一个列表的元素与数值 ( 0) 进行比较。

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

一种解决方案是使用推断的签名,但如果它确实是您想要处理的字符列表,您将不得不摆脱测试x /= 0x与字符值进行比较。例如:

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')编译得很好。

于 2013-07-10T07:02:33.647 回答