
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, I'm writing a little command line app, but I have a question about error handling. The code will go something like, main = do (a:b:cs) <- getArgs i <- return (read a :: Int) j <- return (read b :: Int) putStr $ i + j How can I catch any possible cast exception? Ideally, I think I would like to use the ErrorT monad as a means of handling a potentially fairly complex set of inputs, but I can see no way of handling these errors neatly within that monad. Tom -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.1 (GNU/Linux) iD8DBQE98+VqGse0w80KF2gRAqnMAJ9CMiOWFS+3y2ELu7851MyvTb1aCgCgru+z EtW/mO+WZ0lqtYUECcHyTDE= =r1DY -----END PGP SIGNATURE-----

G'day all. On Mon, Dec 09, 2002 at 11:35:54AM +1100, Thomas L. Bevan wrote:
main = do (a:b:cs) <- getArgs i <- return (read a :: Int) j <- return (read b :: Int) putStr $ i + j
How can I catch any possible cast exception?
How about this? readM :: (Read a, Monad m) => String -> m a readM s = case readEither s of Left err -> fail err Right x -> return x main = runErrorT main' main' = do (a:b:cs) <- liftIO getArgs (i::Int) <- readM a (j::Int) <- readM b liftIO (putStr $ i + j) Cheers, Andrew Bromage

you cannot catch exceptions anywhere but the IO monad, in Haskell 98 this is clear since only IO actions may throw exceptions. With imprecise exceptions as implemented by ghc the reasoning is that what exeption is thrown depends on the evaluation order of a given implementation. imagine: throw (userException "foo") + throw (userException "bar") without defining an evaluation order you cannot know which exepction is to be thrown. catching the exception in the IO monad makes this 'okay' since IO actions can depend on things other than its arguments (like the evaluation order of a given implementation) John On Mon, Dec 09, 2002 at 11:35:54AM +1100, Thomas L. Bevan wrote:
Hi,
I'm writing a little command line app, but I have a question about error handling. The code will go something like,
main = do (a:b:cs) <- getArgs i <- return (read a :: Int) j <- return (read b :: Int) putStr $ i + j
How can I catch any possible cast exception? Ideally, I think I would like to use the ErrorT monad as a means of handling a potentially fairly complex set of inputs, but I can see no way of handling these errors neatly within that monad.
Tom
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------

On Sun, 8 Dec 2002, John Meacham wrote: (snip)
throw (userException "foo") + throw (userException "bar")
without defining an evaluation order you cannot know which exepction is to be thrown. catching the exception in the IO monad makes this 'okay' (snip)
Would it help if you defined an order over the possible exceptions, then if one is thrown you evaluate other parts of the expression to see if they also threw one, and return the "first" according to the ordering? I still haven't given up my hope for simple exceptions without monads. (-: -- Mark

On 09-Dec-2002, Mark Carroll wrote:
On Sun, 8 Dec 2002, John Meacham wrote: (snip)
throw (userException "foo") + throw (userException "bar")
without defining an evaluation order you cannot know which exepction is to be thrown. catching the exception in the IO monad makes this 'okay' (snip)
Would it help if you defined an order over the possible exceptions, then if one is thrown you evaluate other parts of the expression to see if they also threw one, and return the "first" according to the ordering?
That would be too expensive, and would still prevent many of the
kinds of optimizations that we'd like to allow, I think.
E.g. consider
f :: Int -> Int
f = ...
x :: Int
x = a + b where b = f a
a = f 0
Suppose `f' is strict.
We'd like to implement `f' using some code which expects the arguments
to be already evaluated, and known to be non-exceptional values, so that
they can be passed directly in registers without any need for boxing.
We'd also like to implement `x' by code which evaluates `a = f 0', then
`b = f a', and finally `x = a + b'.
But with your proposed semantics, there is a problem with this approach.
If `a = f 0' throws an exception, then your proposed semantics
would mean that we need to still evaluate `b = f a' to see if that throws
an exception. But we don't have a (non-exceptional) value for `a'.
--
Fergus Henderson

On Sun, 8 Dec 2002, John Meacham wrote: (snip)
throw (userException "foo") + throw (userException "bar")
without defining an evaluation order you cannot know which exepction is to be thrown. catching the exception in the IO monad makes this 'okay' (snip)
Mark Carroll writes:
Would it help if you defined an order over the possible exceptions, then if one is thrown you evaluate other parts of the expression to see if they also threw one, and return the "first" according to the ordering? I still haven't given up my hope for simple exceptions without monads. (-:
To do this, we have to actually build the set of all exceptions that an expression could raise. This could take quite a while to build (lots more evaluation may need to be done) and getting any one exception probably isn't going to be any more useful than the 'random' choice you get at present. And even this wouldn't get rid of the monads since the problem monads deal with is present even if we can't observe the exceptions. For example, a simple operation like this: choose :: a -> a -> a which returns its first argument if it can evaluate its argument to WHNF without raising an exception and returns its 2nd argument otherwise has severe semantic problems. -- Alastair Reid alastair@reid-consulting-uk.ltd.uk Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/

On 10 Dec 2002, Alastair Reid wrote: (snip)
To do this, we have to actually build the set of all exceptions that an expression could raise. This could take quite a while to build
Why? I can see that, to do the ordering, you may want to know all the exceptions that can arise somewhere in the program, not minding about a few false positives. Then, at runtime, if an exception pops up, we just evaluate the other "parallel" expressions to see what else happens. Even if we do need the exact set of all exceptions that a particular expression could raise, could that be found at compile time? (snip)
And even this wouldn't get rid of the monads since the problem monads deal with is present even if we can't observe the exceptions. For example, a simple operation like this:
choose :: a -> a -> a
which returns its first argument if it can evaluate its argument to WHNF without raising an exception and returns its 2nd argument otherwise has severe semantic problems.
I don't understand why, I'm afraid. I'm not sure if I'm missing something obvious or if we're somehow talking at cross-purposes. It probably doesn't help that I can imagine what it means to evaluate the first argument strictly but I'm having difficulty figuring out what Weak Head Normal Form is in relation to what Haskell code might get up to. I seem to have a problem understanding exactly how mathematical things shore up practical computing things even when I understand each in isolation, though. Of course, I am happy to suspend judgment until I understand your point better, and I don't think that you have any obligation to bring my education to the point where I can understand it! -- Mark

On 10-Dec-2002, Alastair Reid
On Sun, 8 Dec 2002, John Meacham wrote: (snip)
throw (userException "foo") + throw (userException "bar")
without defining an evaluation order you cannot know which exepction is to be thrown. catching the exception in the IO monad makes this 'okay' (snip)
Mark Carroll writes:
Would it help if you defined an order over the possible exceptions, then if one is thrown you evaluate other parts of the expression to see if they also threw one, and return the "first" according to the ordering? I still haven't given up my hope for simple exceptions without monads. (-:
To do this, we have to actually build the set of all exceptions that an expression could raise. This could take quite a while to build (lots more evaluation may need to be done)
[playing devil's advocate for a moment] The set of all exceptions only needs to be built if an exception is actually raised. If no exception is raised, couldn't the code run just as fast as it currently does in Haskell? (My answer: yes, in theory it could; but only at the cost of major code bloat in the generated code and major increases in the degree of complication of the compiler. It's not worth the trade-off.)
and getting any one exception probably isn't going to be any more useful than the 'random' choice you get at present.
The advantage of what Mark Carroll was suggesting is not that you would get a more useful exception, just that you get a more predictable one, and that you don't need to use Monads. (My response: the potential advantages of more deterministic behaviour and [slightly] reduced need to use Monads would be outweighed by the drawbacks mentioned above, i.e. code bloat and compiler complexity.)
And even this wouldn't get rid of the monads since the problem monads deal with is present even if we can't observe the exceptions. For example, a simple operation like this:
choose :: a -> a -> a
which returns its first argument if it can evaluate its argument to WHNF without raising an exception and returns its 2nd argument otherwise has severe semantic problems.
That depends on what kind of exceptions you are trying to catch,
doesn't it? If you need to catch out-of-memory errors (e.g.
stack overflow or heap overflow), yes, that would cause semantic
problems. Likewise for asynchronous exceptions/signals such as
time-outs or user interrupts. But if `choose' is only catching
exceptions raised by explicit calls to "throw" or "error", then
I think it would be semantically OK, wouldn't it?
(Still, most of the time you probably do want to handle those kinds of
errors -- at least the out-of-memory case, anyway -- so most of the
time you'd still need Monads.)
--
Fergus Henderson

On Fri, 13 Dec 2002, Fergus Henderson wrote: (snip)
and [slightly] reduced need to use Monads would be outweighed by the drawbacks mentioned above, i.e. code bloat and compiler complexity.)
Ah - that's the impression I got from your earlier reply, too. (snip)
time-outs or user interrupts. But if `choose' is only catching exceptions raised by explicit calls to "throw" or "error", then I think it would be semantically OK, wouldn't it? (snip)
That would actually be fine - I hadn't been hoping to catch errors that were things like user interrupts, which sound like they should be monadic anyway - just things explicitly thrown as you suggest. Admittedly, that is a rather important point that I should have made - I hadn't actually thought about errors caused by other stuff going on in the system and I completely agree that they should be wrapped in monads. Basically I was just wanting to replace some of the nastiness I have in code that passes two-tuples of (result, errors) around and has conditional statements to deal with backing up the functional call chain to deal with "error conditions". What the code is doing can safely be done completely without monads so I didn't want any monads to be in the top-level type signature: all the "errors" involved are all things that were noticed in normal computation by matching "otherwise" in a guard and whatever, not IO or anything. -- Mark
participants (6)
-
Alastair Reid
-
Andrew J Bromage
-
Fergus Henderson
-
John Meacham
-
Mark Carroll
-
Thomas L. Bevan