Take the 2-minute tour ×

I have the following Haskell code:

-- 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
                (0, 0, 0.0)
                [(n, phi n, ratio) | n <- [2..max], let ratio = fromIntegral n / (fromIntegral (phi n))]
    where max = 1000

which gives the following error:

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))]'

I suspect that in the triple (0, 0, 0.0) the 0's are type Int. Is 0 always type Int or is ghci deducing the type as Int in this case? If the later, how do I force it to be type Integer instead? Or is there something else that causes this error?

share|improve this question
add comment

4 Answers

up vote 10 down vote accepted

Haskell can generally infer the type of numeric literals such as 0 as whatever appropriate type you need them to be. This is because it knows what functions you pass them to; if I have a function phi :: Integer -> Integer, and I call phi 0, Haskell knows that that particular 0 must have been an Integer. It's also fine if I call a function pho :: Int -> Int with pho 0; that particular 0 is inferred to be an Int.

However Int and Integer are different types, and there's no way one particular 0 can be passed to both phi and pho.

Your issue is simply that the tuples that maxRatio deals with are typed (by you) (Int, Int, Double), but that one such tuple is constructed as (n, phi n, ratio). Since phi takes and returns Integer, the n in that expression has to be an Integer. But then that doesn't work for maxRatio, so you get the error.

Depending on which type you actually wanted (Int or Integer), all you need to do is change the type signature of phi or maxRatio so that they're working with the same kind of number. Haskell will decide that your literally written 0s are whatever numeric type is necessary to make that work, provided there is one that can make it work!

Note that the error messaged specifically told you that it was n in (n, phi n, ratio) that was expected to be an Int and was actually an Integer. The (0, 0, 0.0) tuple is never mentioned. Often type errors originate somewhere other than where the compiler points you (since all the compiler can do is spot that different chains of inference produce inconsistent requirements on the type of something, with no way to know which part of the whole process is "wrong"), but in this case it did pretty well.

Haskell gets a (fairly justified) bad rep for inscrutable error messages, but it can help a lot to start from what the compiler is telling you is the problem and try to figure out why the facts it's complaining about arise from your code. This will be painful at first, but you'll quickly develop a basic literacy in Haskell's error messages (at least the more straightforward ones) that will help you spot these kinds of errors really quickly, which makes the compiler a very powerful error-detection system for you.

share|improve this answer
Thanks for the clear explanation. I thought that 0 was polymorphic in its type, but my noob eyes couldn't see any other reason for the type inference that gave the error. Of course, I simply missed my explicit type declaration for maxRatio. –  Code-Guru Sep 6 '12 at 0:07
add comment

n is being inferred as Int due to the type of maxRatio, while the type of phi says it should be Integer. The simplest fix is to change the type of maxRatio to use Integer or even just a since it doesn't touch those values.

share|improve this answer
Doh! I missed that detail. I am revisiting some code that I wrote a while back probably before I learned to use Integer almost exclusively. –  Code-Guru Sep 5 '12 at 2:25
add comment

It's being inferred, so you can just change the type signature of maxRatio. Still, if you ever need to change an explicit Int to an Integer, use toInteger :: (Integral a) => a -> Integer

share|improve this answer
I usually use fromIntegeral, especially when I'm using length. Is there a difference between using fromIntegral rather than toInteger? –  Code-Guru Sep 5 '12 at 2:27
@Code-Guru: I think the only difference is that fromIntegral can return any Num type, so it's a little less clear when reading it what type it's going to be inferred as. –  amindfv Sep 5 '12 at 2:29
@Code-Guru: actually, fromIntegral is defined as fromIntegral = fromInteger . toInteger -- so it's definitely just a tradeoff between flexibility and readability –  amindfv Sep 5 '12 at 2:31
add comment

Your type signatures are inconsistent - replace Int with Integer throughout.

share|improve this answer
add comment

Your Answer


