允许绑定中的不明确类型变量

Cod*_*ice 2 haskell types

我是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]
Run Code Online (Sandbox Code Playgroud)

错误消息是

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)
Run Code Online (Sandbox Code Playgroud)

13:60就在使用fromIntegral之前,在我的列表理解中让let绑定在main中.我还在尝试习惯ghc的错误信息.我无法破译这个特定的一个,以便弄清楚我需要改变什么来让我的代码编译.任何帮助将不胜感激.谢谢.

Don*_*art 6

这是一个常见的初学者错误的例子:过多的多态代码.

您已尽可能使代码尽可能通用,例如

phi :: (Integral a, Integral b) => a -> b
Run Code Online (Sandbox Code Playgroud)

这将通过转换将任何整数类型转换为任何其他整数类型phi.

这种多态代码对于库来说非常好,但对于类型推断却不是那么好.我把你想要的钱放在Integers上,所以我们可以继续给出一个更准确的类型,

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)) ]
Run Code Online (Sandbox Code Playgroud)

而类型错误就消失了.

您甚至可以看到性能改进(特别是如果您专注于Int).

  • @ Code-Guru:因为"整数"的唯一优势是性能,新手通常不会那么担心; 缺点是导致细微的溢出错误,我认为这非常非Haskelly. (2认同)