bitu
bitu

Reputation: 5

Haskell catch handling

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

Answers (1)

Random Dev
Random Dev

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

making the function pure

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

Related Questions