[More work on ch20 exceptions John Goerzen **20080506052835] { hunk ./en/book-shortcuts.xml 104 +handle"> +handleJust"> hunk ./en/ch20-errors.xml 433 - - + &exc.ghci:handle1; + + This way, we can print out a nice message if there is an error + in the calculations. It's nicer that having the program crash + with a division by zero error, for sure. + + hunk ./en/ch20-errors.xml 453 + + + Selective Handling of Exceptions + + One problem with the above example is that it prints + "Error calculating result" for + any exception. There may have been an + exception other than a division by zero exception. For + instance, there may have been an error displaying the output, + or some other exception could have been raised by the pure + code. + + + There's a function &handleJust; for these situations. It + lets you specify a test to see whether you are interested in a + given exception. Let's take a look: + + &hj1.hs:all; + + catchIt defines a function that decides + whether or not we're interested in a given exception. It + returns &Just; if so, and &Nothing; if not. Also, the value + attached to &Just; will be passed to our handler. We can now + use safePrint nicely: + + &exc.ghci:handleJust1; + + The Control.Exception module also presents + a number of functions that we can use as part of the test in + &handleJust; to narrow down the kinds of exceptions we care + about. For instance, there is a function + arithExceptions of type Exception + -> Maybe ArithException that will pick out any + ArithException, but ignore any other one. + We could use it like this: + + &hj2.hs:all; + + In this way, we can catch all types of + ArithException, but still let other + exceptions pass through unmodified and uncaught. We can see + it work like so: + + &exc.ghci:handleJust2; + hunk ./examples/ch20/exc.ghci 19 +--# handle1 +:m Control.Exception +let x = 5 `div` 0 +let y = 5 `div` 1 +handle (\_ -> putStrLn "Error calculating result") (print x) +handle (\_ -> putStrLn "Error calculating result") (print y) +--# handleJust1 +:l hj1.hs +let x = 5 `div` 0 +let y = 5 `div` 1 +safePrint x +safePrint y +--# handleJust2 +:l hj2.hs +let x = 5 `div` 0 +let y = 5 `div` 1 +safePrint x +safePrint y addfile ./examples/ch20/hj1.hs hunk ./examples/ch20/hj1.hs 1 +{-- snippet all --} +-- ch20/hj1.hs +import Control.Exception + +catchIt :: Exception -> Maybe () +catchIt (ArithException DivideByZero) = Just () +catchIt _ = Nothing + +handler :: () -> IO () +handler _ = putStrLn "Caught error: divide by zero" + +safePrint :: Integer -> IO () +safePrint x = handleJust catchIt handler (print x) +{-- /snippet all --} addfile ./examples/ch20/hj2.hs hunk ./examples/ch20/hj2.hs 1 +{-- snippet all --} +-- ch20/hj2.hs +import Control.Exception + +handler :: ArithException -> IO () +handler e = putStrLn $ "Caught arithmetic error: " ++ show e + +safePrint :: Integer -> IO () +safePrint x = handleJust arithExceptions handler (print x) +{-- /snippet all --} }