我是来自C ++和Java背景的Haskell新手。有时候,我遇到了Haskell类型系统的问题。我目前的错误是这段代码:
countIf :: (Integral b) => [a] -> (a -> Bool) -> b
countIf [] p = 0
countIf (x:xs) p
| p x = 1 + countIf xs p
| otherwise = countIf xs p
isRelativelyPrime :: (Integral a) => a -> a -> Bool
isRelativelyPrime m n = gcd m n == 1
phi :: (Integral a, Integral b) => a -> b
phi n = countIf [1..(n - 1)] (isRelativelyPrime n)
main = print [(n, phi n, ratio) | n <- [1..10], let ratio = (fromIntegral (phi n)) / n]
错误消息是
prog.hs:13:60:
Ambiguous type variable `b' in the constraints:
`Fractional b' arising from a use of `/' at prog.hs:13:60-85
`Integral b' arising from a use of `phi' at prog.hs:13:75-79
Probable fix: add a type signature that fixes these type variable(s)
13:60就在使用fromIntegral之前,在我的列表理解中的let绑定中。我还在尝试习惯ghc的错误信息。我无法破译这个特定的一个,以便弄清楚我需要改变什么来让我的代码编译。任何帮助将不胜感激。感谢。
答案 0 :(得分:6)
这是一个常见的初学者错误的例子:过多的多态代码。
您已使代码尽可能通用,例如
phi :: (Integral a, Integral b) => a -> b
这将通过phi
转换将任何整数类型转换为任何其他整数类型。
这种多态代码非常适合库,但对类型推断不太好。我会把你想要的钱用于整数,所以我们可以继续提供更准确的类型,
countIf :: [Integer] -> (Integer -> Bool) -> Integer
countIf [] p = 0
countIf (x:xs) p
| p x = 1 + countIf xs p
| otherwise = countIf xs p
isRelativelyPrime :: Integer -> Integer -> Bool
isRelativelyPrime m n = gcd m n == 1
phi :: Integer -> Integer
phi n = countIf [1..(n - 1)] (isRelativelyPrime n)
main = print [ (n, phi n, ratio)
| n <- [1..10], let ratio = (fromIntegral (phi n)) ]
,类型错误就消失了。
您甚至可以看到效果改进(特别是如果您专注于Int
)。
答案 1 :(得分:3)
你需要在n上调用fromIntegral,因为Haskell不会自动转换为整数类型,自从你调用fromIntegral(phi n)以来你就已经知道了。我一直犯这个错误,没什么大不了的!