【问题标题】:Ambiguous type variable in let bindinglet绑定中的不明确类型变量
【发布时间】:2012-06-07 04:11:43
【问题描述】:

我是来自 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 就在我在 main 的列表理解中的 let 绑定中使用 fromIntegral 之前。我仍在尝试习惯 ghc 的错误消息。我无法破译这个特定的内容,以便弄清楚我需要更改哪些内容才能编译我的代码。任何帮助将不胜感激。谢谢。

【问题讨论】:

  • 您的countIf 可以定义为标准函数的组合:countIf = length . flip filter

标签: haskell types


【解决方案1】:

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

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

phi :: (Integral a, Integral b) => a -> b

这将通过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)) ]

然后类型错误就消失了。

您甚至可能会看到性能改进(特别是如果您专攻Int)。

【讨论】:

  • 我个人反对向新手推荐 Int,但 +1 表示将过度多态性视为一个问题 :)
  • @DonStewart 感谢您提供有关过度多态性的提示。在这一点上,我可能确实过分了。但是,该错误不会随着该更改而消失。您的代码在“let ratio = ...”绑定中没有划分(因此名称为“ratio”),这是发生错误消息的地方。 Max 上面的回答解决了这个错误,因为我需要一个“fromInteger n”来进行浮点除法。
  • @benmachine 为什么你反对向新手推荐 Int's?
  • @Code-Guru:因为与Integer相比唯一的优势是性能,新手通常不会太担心;缺点是会导致微妙的溢出错误,我认为这非常不合时宜。
  • @benmachine 谢谢!我会记住这一点。 p.s.我不是一般编程的新手,只是 Haskell 和函数式编程。 ;-)
【解决方案2】:

你还需要在 n 上调用 fromIntegral,因为 Haskell 不会自动从整数类型转换,你似乎已经知道了,因为你调用了 fromIntegral (phi n)。我经常犯这个错误,没什么大不了的!

【讨论】:

  • 谢谢,这是我遗漏的细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多