Search code examples
haskellio

Parsing floating point values from input results in "exception: no parse"


I wrote this code :

calculIOTest :: IO ()
calculIOTest = do
   putStrLn "Give me two numbers"
   l1 <- getLine
   let x1 = read l1 
   l2 <- getLine
   let x2 = read l2 
   print (x1 + x2)

I wanted code that takes two numbers and returns the sum. If I test my function with two integers it works but if I put a float then there is a problem with the error:

***Exception: Prelude.read: no parse

I would have understood with a string and a number but here I have trouble understanding what is causing the problem.

I tried to review how read works and indeed if I do:

(read 10000.9) + (read 1115)

It gives me the errors:

Could not deduce (Fractional String)
        arising from the literal ‘10000.9’
      from the context: (Read a, Num a)
        bound by the inferred type of it :: (Read a, Num a) => a
        at <interactive>:135:1-28

and

Could not deduce (Num String) arising from the literal ‘1115’
      from the context: (Read a, Num a)
        bound by the inferred type of it :: (Read a, Num a) => a
        at <interactive>:135:1-28

I would like to understand why it does not work in my code and where does the error prevent with the read?


Solution

  • Since you're adding x1 and x2 the compiler can infer that those have to have a Num instance and the default type for Num a is Integer. So implicitly your code is equivalent to the following:

    calculIOTest :: IO ()
    calculIOTest = do
       putStrLn "Give me two numbers"
       l1 <- getLine
       let x1 = (read l1 :: Integer)
       l2 <- getLine
       let x2 = (read l2 :: Integer)
       print (x1 + x2)
    

    and obviously you can't parse a float representation as an Integer. To accept Doubles all you have to do is explicitly annotate that type:

    calculIOTest :: IO ()
    calculIOTest = do
       putStrLn "Give me two numbers"
       l1 <- getLine
       let x1 = (read l1 :: Double)
       l2 <- getLine
       let x2 = (read l2 :: Double)
       print (x1 + x2)
    

    Your bare reads (read 10000.9) + (read 1115) would suffer from the same problem had you included the necessary " (read takes a String not floats or ints)

    read "10000.9" + read "1115"
    

    too results in ***Exception: Prelude.read: no parse and the fix is the same, annotate the type you want.