user606521
user606521

Reputation: 15434

catching errors during string parsing

I want to parse String to get Int and I use this:

string2int :: String -> Int
string2int str = read str::Int

Now I want to catch paring exception/error as SIMPLY as possible. I tried:

import qualified Control.Exception as E

eVal <- try (print (string2int "a")) :: IO (Either E.SomeException ())
   case eVal of
      Left e -> do { putStrLn "exception"; }
      Right n -> do { putStrLn "good"; }

But compiler says couldn't match expected type 'E.SomeException()' with actual type E.IOException.

What am I doing wrong?

Ok I don't know how to use it for my problem: I want somthing like this:

loadfunction = do
{
   x <- string2int getLine
   if( failed parsing int ) call somefunction
   y <- string2int getLine
  if( failed parsing int ) call somefunction

  otherfunction x y
}

I dont know how to do it using your answers...

Upvotes: 0

Views: 863

Answers (1)

ehird
ehird

Reputation: 40787

You're using try imported from the old exceptions mechanism, but are trying to use its result type as if it was using the new extensible Control.Exception mechanism. Use E.try instead.

You should ideally import Control.Exception like this:

import Prelude hiding (catch)
import Control.Exception

and remove all imports of Control.OldException. Then you can use its functions directly without worrying about any clashes.

By the way, you don't have to use IO exceptions to handle read errors; you can use reads instead:

reads :: (Read a) => String -> [(a, String)]

Here's how I'd write your code with reads:

case reads "a" of
  [(a, "")] -> do
    print a
    putStrLn "good"
  _ -> putStrLn "exception"

The fact that reads returns a list is a little confusing; practically, you can think of it as returning Maybe (a, String) instead. If you want a version using Maybe, you can define it like this:

readMaybe :: (Read a) => String -> Maybe a
readMaybe s =
  case reads s of
    [(a, "")] -> Just a
    _ -> Nothing

which makes your code become:

case readMaybe "a" of
  Just a -> do
    print a
    putStrLn "good"
  Nothing -> putStrLn "exception"

(You can also define readMaybe as listToMaybe . map fst . filter (null . snd) . reads like dave4420 did; they'll be equivalent in practice, since none of the standard Read instances ever return lists of more than one element.)

In general, you should try and use pure error-handling methods like this whenever possible, and only use IO exceptions when there's really no other option, or you're dealing with IO-specific code (like file/network handling, etc.). However, if you want to stick with exceptions, using E.try instead should fix your error.


Based on your updated question, however, exceptions might be the right way to go after all; something like ErrorT would also work, but if you're already doing everything in IO to start with, then there's no harm in using exceptions. So I would write your example like this:

loadfunction = do
  line1 <- getLine
  x <- string2int line1
  line2 <- getLine
  y <- string2int line2
  otherfunction x y

and use E.catch to handle the exceptions it throws; take a look at the documentation for catch to see how to do that.

Upvotes: 7

Related Questions