无法将预期类型“Int”与实际类型“Integer”匹配

时间:2012-09-05 02:00:06

标签: haskell

我有以下Haskell代码:

-- Problem 69

import ProjectEuler

phi :: Integer -> Integer
phi n = n * product [p - 1 | p <- primeDivisors n] `div` product [p | p <- primeDivisors n]
-- primeDivisors n is a list of the prime divisors of n

maxRatio :: (Int, Int, Double) -> (Int, Int, Double) -> (Int, Int, Double)
maxRatio t1@(_, _, x) t2@(_, _, y)
  | x > y = t1
  | otherwise = t2

main = print (foldl
                maxRatio
                (0, 0, 0.0)
                [(n, phi n, ratio) | n <- [2..max], let ratio = fromIntegral n / (fromIntegral (phi n))]
              )
    where max = 1000

会出现以下错误:

Couldn't match expected type `Int' with actual type `Integer'
In the expression: n
In the expression: (n, phi n, ratio)
In the third argument of `foldl', namely
  `[(n, phi n, ratio) |
      n <- [2 .. max],
      let ratio = fromIntegral n / (fromIntegral (phi n))]'

我怀疑在三(0, 0, 0.0)中,0是类型Int0是否始终键入Int或者ghci在这种情况下将类型推断为Int?如果是后者,我该如何强制它为Integer类型呢?或者是否有其他原因会导致此错误?

4 个答案:

答案 0 :(得分:16)

Haskell通常可以将0等数字文字的类型推断为您需要的任何类型。这是因为它知道你传递给他们的功能;如果我有一个函数phi :: Integer -> Integer,并且我调用phi 0,则Haskell知道该特定0必须是Integer。如果我用pho :: Int -> Int调用函数pho 0,也可以。 特定0被推断为Int

但是IntInteger是不同的类型,并且一个特定的0无法传递给phipho

您的问题很简单,maxRatio处理的元组是由({你)(Int, Int, Double)键入的,但是这样的元组构造为(n, phi n, ratio)。由于phi接受并返回Integer,因此该表达式中的n必须为Integer。但那对maxRatio不起作用,所以你得到了错误。

根据您实际需要的类型(IntInteger),您需要做的就是更改phimaxRatio的类型签名,以便他们'重新使用相同的号码。 Haskell将决定你的字面编写的0是什么数字类型是必要的,提供有一个可以使它工作!

请注意,错误消息具体告诉您,n(n, phi n, ratio)的{​​{1}}预计为Int,实际上是{{1} }}。永远不会提到Integer元组。通常,类型错误源于编译器指向您的位置以外的其他位置(因为编译器可以做的就是发现不同的推理链对某些类型的类型产生不一致的要求,无法知道整个过程的哪个部分是“错误的” ),但在这种情况下它做得很好。

Haskell得到一个(相当合理的)糟糕的代表,因为不可思议的错误消息,但它可以从编译器告诉你的问题开始,并尝试找出为什么事实它抱怨你的代码产生了。这一开始会很痛苦,但是你会很快在Haskell的错误消息(至少是更直接的错误消息)中开发一个基本知识,这将有助于你真正快速地发现这些类型的错误,这使编译器成为一个非常强大的错误检测系统为你。

答案 1 :(得分:4)

由于n的类型,

Int被推断为maxRatio,而phi的类型应该是Integer。最简单的解决方法是将maxRatio的类型更改为使用Integer,甚至只更改a,因为它不会触及这些值。

答案 2 :(得分:3)

正在推断,因此您只需更改maxRatio的类型签名即可。不过,如果您需要将明确的Int更改为Integer,请使用toInteger :: (Integral a) => a -> Integer

答案 3 :(得分:1)

您的类型签名不一致 - 始终将Int替换为Integer