As an uni assignment, I was supposed to write a function with the type declaration:
pi_approx :: Int -> Double
and this was my first attempt:
pi_approx :: Int -> Double
pi_approx x = let total = sum [1 / (y^2) | y <- [1..x]]
in sqrt (6 * total)
which threw the below error:
pi_approx.hs:4:8: error:
* Couldn't match expected type `Double' with actual type `Int'
* In the expression: sqrt (6 * total)
In the expression:
let total = sum [1 / (y ^ 2) | y <- ...] in sqrt (6 * total)
In an equation for `pi_approx':
pi_approx x = let total = sum ... in sqrt (6 * total)
|
4 | in sqrt (6 * total)
| ^^^^^^^^^^^^^^^^
I went step by step trying to understand why the interpreter treats it as an Int:
level1 :: Fractional a => a -> a
level1 x = 1 / (x^2)
So far so good.
level2 :: (Enum a, Fractional a) => a -> [a]
level2 x = [level1 y | y <- [1..x]]
Also as expected.
level3 :: (Enum a, Fractional a) => a -> a
level3 x = sum (level2 x)
No Int to be seen...
level4 :: (Enum a, Fractional a) => a -> a
level4 x = 6 * (level3 x)
and finally
level5 :: (Floating a, Enum a) => a -> a
level5 x = sqrt (level4 x)
And having gone down this rabbit hole I'm no closer to my answer. I got it running with fromIntegral
pi_approx :: Int -> Double
pi_approx x = let total = sum [(fromIntegral 1) / ((fromIntegral y)^ (fromIntegral 2)) | y <- [1..x]]
in sqrt (6*total)
but it got me nowhere nearer to understanding what caused the error in the first version. Could someone explain what I'm missing? Why was sqrt (6*total)
treated as an Int
?
level1 :: Int -> Double
it would have stopped you in your tracks right there (or, if you had started with the concrete typelevel1 :: Double -> Double
then you would have soon discovered that yourlevel5
had noInt
anywhere in its type signature). – Daniel Wagner(fromIntegral y)
converter. TheInt
type constraint on the argument x propagates unmitigated to y. Hence the type conflict in your initial code at the level of the “/” operator. Unlike in C C++ Fortran, there is no automatic numeric type promotion. You have to allow it explicitely for it to happen. – jpmarinier:t
command, as deduced by it. – Will Ness