对于以下简单的函数定义:
printLength1::(Num a)=>String->a
printLength1 s = length s
printLength2::String->Int
printLength2 s = length s
他们为什么不一样?在什么情况下我应该选择一个而不是另一个?
我得到printLength1的错误:
Couldn't match type `a' with `Int'
`a' is a rigid type variable bound by
the type signature for rpnc :: String -> a at test.hs:20:1
In the return type of a call of `length'
In the expression: length s
In an equation for `rpnc': rpnc s = length s
我理解这个错误。但我该如何解决这个问题呢? 我已经在这里阅读了一些关于刚性类型变量的帖子,但仍然无法理解如何修复它。
答案 0 :(得分:9)
第一种签名更为通用。这意味着结果可以是任何Num
- 它的返回类型是多态的。因此,您的第一个函数的结果可以用作Int
或Integer
或任何其他Num
实例。
问题是length
返回Int
而不是任何Num
实例。您可以使用fromIntegral
:
printLength1 :: Num a => String -> a
printLength1 s = fromIntegral $ length s
请注意fromIntegral . length
的签名(上面代码的无点版本)是Num c => [a] -> c
。这与您为printLength1
函数指定的签名相匹配。
答案 1 :(得分:7)
注意:此函数的类型为numLongChains :: Int,因为历史原因,length返回Int而不是Num a。如果我们想要返回更一般的Num a,我们可以在结果长度上使用fromIntegral。