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实例”?
答案 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
。至于Eq
对a
的约束,这是可以的,因为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'
中的引号)编译得很好。