Haskell: Variable Type confusion between Double and Int

Because of the way typeclasses are type checked, the type error you were shown is not the most helpful one.

[ 1 / (y^2) | y <- [1..x] ]

So it is probably no surprise that, because x is an Int, [1..x] is a list of Ints and so y is an Int. Nor is it surprising that y^2 is an Int. Where GHC loses us is when it decides that therefore 1 / (y^2) is an Int.

The reason is this: the type of the divide operator is

(/) :: (Fractional a) => a -> a -> a

That is, it takes the same type on both sides, and also returns it. So as soon as the type of y^2 is known to be Int, we infer that 1 and the entire expression are Int also. Only later, during the constraint checking phase, GHC will make sure that Int is Fractional, which of course it is not. For example:

recp :: Int -> Int
recp x = 1 / x

Will give you a better error

• No instance for (Fractional Int) arising from a use of ‘/’
• In the expression: 1 / x
  In an equation for ‘recp’: recp x = 1 / x

But it didn't get that far when checking your function, because there was a type unification failure first.

Sometimes if you can't figure out an error it is helpful to remove the signature and see what type is inferred (more often, it's helpful to add more type signatures, but not always)

ghci> :t pi_approx
pi_approx :: (Floating a, Enum a) => a -> a

Without the signature, the function actually type-checks. It works, too:

ghci> pi_approx 100
3.1320765318091053

Here 100 is defaulted to be a Double to satisfy the Fractional constraint, and the whole definition goes through with everything as Doubles.

It's just that it doesn't accept Ints:

ghci> pi_approx (100 :: Int)

<interactive>:1:1: error:
• No instance for (Floating Int) arising from a use of ‘pi_approx’
• In the expression: pi_approx (1 :: Int)

All of the level functions you've defined have the type a -> a (or a -> [a]) with some constraints on a attached to them. So in all cases the type that comes out will be the type that went in (or a list thereof).

So when calling each of your level functions there are two possible outcomes: either the call is ill-typed because the type of the argument does not meet the constraints or you'll get back a value of the same time (or a list thereof). Either way it's impossible that you'd put in an Int and get back a Float.

So sqrt (6*total) was treated as an Int because, as we've just discussed, the type that comes out will be the same type that goes in and the type that came in was Int. Now the type that came in didn't actually meet the constraints, so you might expect an error about that. And without the type signature, you'd get exactly that error (once the function is called with an argument of type Int). But with the type signature, the error about the return type not matching is detected before the constraints are checked, so that's why you get that error.


Everyone explained why it is wrong but no-one showed you how to fix it.

Here is how you fix your code so that it works

pi_approx :: Int -> Double
pi_approx x = let total = sum [1 /(fromIntegral (y^2)) | y <- [1..x]]
    in sqrt (6 * total)

once you add in fromIntegral the type checker will be satisfied. As was explained by the other users the type of the function / wasn't being satisfied.

Tags:

Types

Haskell