Exeption handling in GHC

Hi all, I'm trying to get exception handling working in GHC, but don't seem to be able to make it work. Am I likely to be missing a compiler switch, or something? Cutting things down to basics, I'd have thought that the following expression (typed at the ghci command prompt) should work: try (error "x") but the result is *** Exception: x I seem to get the same problem with compiled code. Any ideas anyone? TIA, Sarah

You're probably using IO (or System.IO) try. If you want imprecise exceptions (I think that's the right name), you want to use Control.Exception versions of try/catch/bracket/etc. Prelude> :m IO Prelude IO> :t try forall a. IO a -> IO (Either GHC.IOBase.Exception a) Prelude IO> try (error "a") *** Exception: a Prelude IO> :m Control.Exception Prelude Control.Exception> try (error "a") Prelude Control.Exception> it Left a HTH - Hal -- Hal Daume III "Computer science is no more about computers | hdaume@isi.edu than astronomy is about telescopes." -Dijkstra | www.isi.edu/~hdaume On Fri, 24 Jan 2003, Sarah Thompson wrote:
Hi all,
I'm trying to get exception handling working in GHC, but don't seem to be able to make it work. Am I likely to be missing a compiler switch, or something?
Cutting things down to basics, I'd have thought that the following expression (typed at the ghci command prompt) should work:
try (error "x")
but the result is
*** Exception: x
I seem to get the same problem with compiled code. Any ideas anyone?
TIA, Sarah
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

I've noticed some interesting behaviour:
Prelude Control.Exception> try (return (error "e"))
Prelude Control.Exception> it
Right *** Exception: e
It would appear that when the result of this function is evaluated, the
exception fires during evaluation, after the try is out of scope. I suppose
it makes some kind of twisted sense due to lazy evaluation going on, but it
is certainly a gotcha.
I did notice this:
Prelude Control.Exception> try (return $! (error "e"))
Prelude Control.Exception> it
Left e
Seemingly, forcing strict evaluation on the argument of return fixes the
problem by making sure that any exception that *can* happen, *does* happen.
However, this code from my COM wrapper:
--[id(3)] HRESULT XmlQuery([in,string] BSTR query, [out,retval]BSTR* xml);
xmlQuery :: String -> State -> IO String
xmlQuery qry (State st) = do
db <- readIORef st
Control.Exception.catch (return $! (XMLDatabase.xmlQuery qry db))
(\ _ -> return "

In article
I've noticed some interesting behaviour:
Prelude Control.Exception> try (return (error "e")) Prelude Control.Exception> it Right *** Exception: e
It would appear that when the result of this function is evaluated, the exception fires during evaluation, after the try is out of scope. I suppose it makes some kind of twisted sense due to lazy evaluation going on, but it is certainly a gotcha.
You might be interested in this program to investigate what catches what. Your example corresponds to the line Control.Exception.catch MISSED return error Here's is the full output:
CAUGHT return CAUGHT return undefined CAUGHT return Control.Exception.throw CAUGHT return error MISSED fail MISSED error MISSED Control.Exception.throw MISSED ioError ErrorCall MISSED ioError IOException MISSED undefined Prelude.catch MISSED return Prelude.catch MISSED return undefined Prelude.catch MISSED return Control.Exception.throw Prelude.catch MISSED return error Prelude.catch CAUGHT fail Prelude.catch MISSED error Prelude.catch MISSED Control.Exception.throw Prelude.catch MISSED ioError ErrorCall Prelude.catch CAUGHT ioError IOException Prelude.catch MISSED undefined Control.Exception.catch MISSED return Control.Exception.catch MISSED return undefined Control.Exception.catch MISSED return Control.Exception.throw Control.Exception.catch MISSED return error Control.Exception.catch CAUGHT fail Control.Exception.catch CAUGHT error Control.Exception.catch CAUGHT Control.Exception.throw Control.Exception.catch CAUGHT ioError ErrorCall Control.Exception.catch CAUGHT ioError IOException Control.Exception.catch CAUGHT undefined Control.Exception.finally CAUGHT return Control.Exception.finally CAUGHT return undefined Control.Exception.finally CAUGHT return Control.Exception.throw Control.Exception.finally CAUGHT return error Control.Exception.finally CAUGHT fail Control.Exception.finally CAUGHT error Control.Exception.finally CAUGHT Control.Exception.throw Control.Exception.finally CAUGHT ioError ErrorCall Control.Exception.finally CAUGHT ioError IOException Control.Exception.finally CAUGHT undefined
-- Ashley Yakeley, Seattle WA -- ghc ThrowCatch.hs -o ThrowCatch && ./ThrowCatch module Main where { import qualified Control.Exception; import Data.IORef; import Prelude; safeCatch :: IO () -> IO (); safeCatch f = Control.Exception.catch f (\_ -> return ()); type Thrower = IO Bool; type Catcher = IO Bool -> IO () -> IO (); checkCatch :: Catcher -> Thrower -> IO Bool; checkCatch catcher thrower = do { ref <- newIORef False; safeCatch (catcher thrower (writeIORef ref True)); readIORef ref; }; data Named a = MkNamed String a; checkNamedCatch :: Named Catcher -> Named Thrower -> IO (); checkNamedCatch (MkNamed cname catcher) (MkNamed tname thrower) = do { didCatch <- checkCatch catcher thrower; putStrLn (cname ++ (if didCatch then " CAUGHT " else " MISSED ") ++ tname); }; checkNamedCatches :: [Named Catcher] -> [Named Thrower] -> IO (); checkNamedCatches [] _ = return (); checkNamedCatches _ [] = return (); checkNamedCatches [c] (t:tr) = do { checkNamedCatch c t; checkNamedCatches [c] tr; }; checkNamedCatches (c:cr) ts = do { checkNamedCatches [c] ts; checkNamedCatches cr ts }; -- throwers returnThrower :: Named Thrower; returnThrower = MkNamed "return" (return True); returnUndefinedThrower :: Named Thrower; returnUndefinedThrower = MkNamed "return undefined" (return undefined); returnErrorThrower :: Named Thrower; returnErrorThrower = MkNamed "return error" (return (error "some error")); undefinedThrower :: Named Thrower; undefinedThrower = MkNamed "undefined" undefined; failThrower :: Named Thrower; failThrower = MkNamed "fail" (fail "some failure"); errorThrower :: Named Thrower; errorThrower = MkNamed "error" (error "some error"); throwThrower :: Named Thrower; throwThrower = MkNamed "Control.Exception.throw" (Control.Exception.throw (Control.Exception.ErrorCall "throw error")); ioErrorErrorCallThrower :: Named Thrower; ioErrorErrorCallThrower = MkNamed "ioError ErrorCall" (ioError (Control.Exception.ErrorCall "throw error")); ioErrorIOExceptionThrower :: Named Thrower; ioErrorIOExceptionThrower = MkNamed "ioError IOException" (ioError (Control.Exception.IOException undefined)); returnThrowThrower :: Named Thrower; returnThrowThrower = MkNamed "return Control.Exception.throw" (return (Control.Exception.throw (Control.Exception.ErrorCall "throw error"))); -- catchers bindCatcher :: Named Catcher; bindCatcher = MkNamed ">>" (>>); preludeCatchCatcher :: Named Catcher; preludeCatchCatcher = MkNamed "Prelude.catch" (\f cc -> Prelude.catch (f >> (return ())) (const cc)); ceCatchCatcher :: Named Catcher; ceCatchCatcher = MkNamed "Control.Exception.catch" (\f cc -> Control.Exception.catch (f >> (return ())) (const cc)); finallyCatcher :: Named Catcher; finallyCatcher = MkNamed "Control.Exception.finally" (\f cc -> Control.Exception.finally (f >> (return ())) cc); main = checkNamedCatches [bindCatcher,preludeCatchCatcher,ceCatchCatcher,finallyCatcher] [returnThrower,returnUndefinedThrower,returnThrowThrower,returnErrorThrower,failThrower, errorThrower,throwThrower,ioErrorErrorCallThrower,ioErrorIOExceptionThrower,undefinedThrower]; }

I wrote:
-- Ashley Yakeley, Seattle WA -- ghc ThrowCatch.hs -o ThrowCatch && ./ThrowCatch module Main where
Sorry, I was expecting my UA to attach the file rather than append it. But there it is anyway. -- Ashley Yakeley, Seattle WA

On Fri, 24 Jan 2003, Sarah Thompson wrote:
I've noticed some interesting behaviour:
Prelude Control.Exception> try (return (error "e")) Prelude Control.Exception> it Right *** Exception: e
It would appear that when the result of this function is evaluated, the exception fires during evaluation, after the try is out of scope. I suppose it makes some kind of twisted sense due to lazy evaluation going on, but it is certainly a gotcha.
I did notice this:
Prelude Control.Exception> try (return $! (error "e")) Prelude Control.Exception> it Left e
Seemingly, forcing strict evaluation on the argument of return fixes the problem by making sure that any exception that *can* happen, *does* happen.
However, this code from my COM wrapper:
--[id(3)] HRESULT XmlQuery([in,string] BSTR query, [out,retval]BSTR* xml); xmlQuery :: String -> State -> IO String xmlQuery qry (State st) = do db <- readIORef st Control.Exception.catch (return $! (XMLDatabase.xmlQuery qry db)) (\ _ -> return "
") doesn't work. If XMLDatabase.xmlQuery throws an exception, the COM wrapper still terminates the host application (Yes, Sigbjorn - I did apply your patch to HDirect, but it seemed to make no difference).
Your COM wrapper code probably behaves differently because the error is not evoked at the very top level. Note that `seq` (and hence ($!)) only force evaluation to "weak head normal form", which essentially means only enough to determine the top-level constructor. You may need to evaluate more deeply. Check out `DeepSeq` (http://haskell.org/pipermail/haskell/2001-August/001586.html) and/or "strategies" (http://www.mail-archive.com/haskell@haskell.org/msg09543/Strategies.lhs).
I'm still a bit stuck here!
Sarah
Dean

Your COM wrapper code probably behaves differently because the error is not evoked at the very top level. Note that `seq` (and hence ($!)) only force evaluation to "weak head normal form", which essentially means only enough to determine the top-level constructor. You may need to evaluate more deeply. Check out `DeepSeq` (http://haskell.org/pipermail/haskell/2001-August/001586.html) and/or "strategies" (http://www.mail-archive.com/haskell@haskell.org/msg09543/Strategi es.lhs).
DeepSeq fixed it in one go. Brilliant! Many thanks for the help. My COM object now appears to be unreasonably solid regardless of what I throw at it. :) Sarah
participants (4)
-
Ashley Yakeley
-
Dean Herington
-
Hal Daume III
-
Sarah Thompson