Reputation: 5
I used the code below to catch a read error, while inputting an Integer
using getLine
.
The problem is I have to print the integer unnecessarily to match the expected output of function. As shown in the catch statement below in the checkInt
function. Please let me know what modifications I have to make to avoid print
ing the integer in the catch block.
showError= do
putStrLn("ERR")
exitSuccess
checkInt str = do
catch (print(read str :: Int)) handler
where
handler :: SomeException -> IO ()
handler ex = showError
Upvotes: 0
Views: 782
Reputation: 52290
of course @leftaroundabout is right but I think it might be interesting to see how you can get it working anyways.
you don't have to print it - you just have to enforce evaluation (which you can do here using seq
:
checkInt :: String -> IO ()
checkInt str =
catch (seq (read str :: Int) $ return ()) showError
showError :: SomeException -> IO ()
showError _ =
putStrLn("ERR")
example:
λ> checkInt "33"
λ> checkInt "ad"
ERR
of course it might be better to not only check but also return the Int
:
checkInt :: String -> IO Int
checkInt str =
catch (let i = read str in seq i $ return i) showError
showError :: SomeException -> IO Int
showError _ = do
putStrLn("ERR")
return (-1)
example:
λ> checkInt "33"
33
λ> checkInt "a3"
ERR
-1
λ> i <- checkInt "a3"
ERR
anyways you should heed @leftaroundabouts advice and one possibility would be using reads
which allows for more flexibility then read
:
checkInt :: String -> Maybe Int
checkInt str =
case reads str of
((i, _):_) -> Just i
_ -> Nothing
example:
λ> checkInt "33"
Just 33
λ> checkInt "ab"
Nothing
λ> checkInt "33a77"
Just 33
if you don't like the behavior shown in the last example you can change the function to:
checkInt :: String -> Maybe Int
checkInt str =
case reads str of
[(i, [])] -> Just i
_ -> Nothing
and it should only parse inputs where the complete string can be parsed as an integer:
λ> checkInt "33"
Just 33
λ> checkInt "ab"
Nothing
λ> checkInt "33a77"
Nothing
λ> checkInt "33 77"
Nothing
Upvotes: 2