If you have ever had to compose an exception handler for exceptions of multiple types,
you know how frustraiting it can get.
This library approaches this issue by providing a composable exception handler type,
which has a Monoid instance.
Composability means that you can define custom partial handlers and
reuse them by composing other handlers from them.
Here is an example of a composable partial handler,
which only defines what to do in case of a ThreadKilled exception
(the code uses the LambdaCase extension):
ignoreThreadKilled :: PartialHandler ()
ignoreThreadKilled =
typed $ \case
ThreadKilled -> Just $ return ()
_ -> Nothing
Here's how you can construct a handler of type SomeException -> IO ()
using this library:
totalizeRethrowing $
ignoreThreadKilled <>
onAlreadyExists (putStrLn "Already exists")
and here is how you would do it traditionally (with the MultiWayIf extension):
\e -> if
| Just ThreadKilled <- fromException e ->
return ()
| Just e' <- fromException e, isAlreadyExistsError e' ->
putStrLn "Already exists"
| otherwise ->
throwIO e
Putting all the syntactic trickery to make it shorter aside,
this handler is a monolith block of code.
Unlike with PartialHandler you can neither decompose it into simpler ones,
nor compose it with other handlers to form a more complex one.