Reputation: 15434
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
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