Synchronous exceptions immediately abort a series of computations.
We provide monads for describing this behaviour.
In contrast to ErrorT from mtl
or transformers
package
we do not pose restrictions on the exception type.
How to tell, that a function can possibly throw more than one (kind of) exception?
If you would use the exception type (Either ParserException IOError)
then this is different from (Either IOError ParserException)
.
Thus we recommned using type classes for exceptions.
Then you can use one type containing all exceptions in an application,
but the type signature still tells which exceptions are actually possible.
Examples:
parser :: ParserException e => ExceptionalT e ParserMonad a getLine :: IOException e => ExceptionalT e IO String fileParser :: (ParserException e, IOException e) => ExceptionalT e IO String
Unfortunately, this way you cannot remove single exceptions
from the constraints by catching them.
You can only remove all of them using resolve
or none.
For a more advanced approach,
that allows removing exceptions constraints
by some nonHaskell98 type hackery,
see the exception package by Joseph Iborra.
 data Exceptional e a
 fromMaybe :: e > Maybe a > Exceptional e a
 toMaybe :: Exceptional e a > Maybe a
 fromEither :: Either e a > Exceptional e a
 toEither :: Exceptional e a > Either e a
 getExceptionNull :: Exceptional e () > Maybe e
 switch :: (e > b) > (a > b) > Exceptional e a > b
 force :: Exceptional e a > Exceptional e a
 mapException :: (e0 > e1) > Exceptional e0 a > Exceptional e1 a
 mapExceptional :: (e0 > e1) > (a > b) > Exceptional e0 a > Exceptional e1 b
 throw :: e > Exceptional e a
 assert :: e > Bool > Exceptional e ()
 catch :: Exceptional e0 a > (e0 > Exceptional e1 a) > Exceptional e1 a
 resolve :: (e > a) > Exceptional e a > a
 newtype ExceptionalT e m a = ExceptionalT {
 runExceptionalT :: m (Exceptional e a)
 fromErrorT :: Monad m => ErrorT e m a > ExceptionalT e m a
 toErrorT :: Monad m => ExceptionalT e m a > ErrorT e m a
 fromEitherT :: Monad m => m (Either e a) > ExceptionalT e m a
 toEitherT :: Monad m => ExceptionalT e m a > m (Either e a)
 forceT :: Monad m => ExceptionalT e m a > ExceptionalT e m a
 mapExceptionT :: Monad m => (e0 > e1) > ExceptionalT e0 m a > ExceptionalT e1 m a
 mapExceptionalT :: (m (Exceptional e0 a) > n (Exceptional e1 b)) > ExceptionalT e0 m a > ExceptionalT e1 n b
 throwT :: Monad m => e > ExceptionalT e m a
 assertT :: Monad m => e > Bool > ExceptionalT e m ()
 catchT :: Monad m => ExceptionalT e0 m a > (e0 > ExceptionalT e1 m a) > ExceptionalT e1 m a
 bracketT :: Monad m => ExceptionalT e m h > (h > ExceptionalT e m ()) > (h > ExceptionalT e m a) > ExceptionalT e m a
 resolveT :: Monad m => (e > m a) > ExceptionalT e m a > m a
 tryT :: Monad m => ExceptionalT e m a > m (Exceptional e a)
 manyT :: Monad m => (e0 > Maybe e1) > (a > b > b) > b > ExceptionalT e0 m a > ExceptionalT e1 m b
 manyMonoidT :: (Monad m, Monoid a) => (e0 > Maybe e1) > ExceptionalT e0 m a > ExceptionalT e1 m a
Documentation
data Exceptional e a Source
Like Either
, but explicitly intended for handling of exceptional results.
In contrast to Either
we do not support fail
.
Calling fail
in the Exceptional
monad is an error.
This way, we do not require that an exception can be derived from a String
,
yet, we require no constraint on the exception type at all.
Monad (Exceptional e)  
Functor (Exceptional e)  
MonadFix (Exceptional e)  
Applicative (Exceptional e)  
(Eq e, Eq a) => Eq (Exceptional e a)  
(Show e, Show a) => Show (Exceptional e a) 
fromMaybe :: e > Maybe a > Exceptional e aSource
toMaybe :: Exceptional e a > Maybe aSource
fromEither :: Either e a > Exceptional e aSource
toEither :: Exceptional e a > Either e aSource
getExceptionNull :: Exceptional e () > Maybe eSource
useful in connection with Control.Monad.Exception.Asynchronous.continue
switch :: (e > b) > (a > b) > Exceptional e a > bSource
force :: Exceptional e a > Exceptional e aSource
mapException :: (e0 > e1) > Exceptional e0 a > Exceptional e1 aSource
mapExceptional :: (e0 > e1) > (a > b) > Exceptional e0 a > Exceptional e1 bSource
throw :: e > Exceptional e aSource
assert :: e > Bool > Exceptional e ()Source
catch :: Exceptional e0 a > (e0 > Exceptional e1 a) > Exceptional e1 aSource
resolve :: (e > a) > Exceptional e a > aSource
newtype ExceptionalT e m a Source
like ErrorT, but ExceptionalT is the better name in order to distinguish from real (programming) errors
ExceptionalT  

MonadTrans (ExceptionalT e)  
Monad m => Monad (ExceptionalT e m)  
Functor m => Functor (ExceptionalT e m)  
MonadFix m => MonadFix (ExceptionalT e m)  
Applicative m => Applicative (ExceptionalT e m)  
(MonadSIO m, ContainsIOException e) => MonadIO (ExceptionalT e m) 
fromErrorT :: Monad m => ErrorT e m a > ExceptionalT e m aSource
toErrorT :: Monad m => ExceptionalT e m a > ErrorT e m aSource
fromEitherT :: Monad m => m (Either e a) > ExceptionalT e m aSource
toEitherT :: Monad m => ExceptionalT e m a > m (Either e a)Source
forceT :: Monad m => ExceptionalT e m a > ExceptionalT e m aSource
see force
mapExceptionT :: Monad m => (e0 > e1) > ExceptionalT e0 m a > ExceptionalT e1 m aSource
mapExceptionalT :: (m (Exceptional e0 a) > n (Exceptional e1 b)) > ExceptionalT e0 m a > ExceptionalT e1 n bSource
throwT :: Monad m => e > ExceptionalT e m aSource
catchT :: Monad m => ExceptionalT e0 m a > (e0 > ExceptionalT e1 m a) > ExceptionalT e1 m aSource
bracketT :: Monad m => ExceptionalT e m h > (h > ExceptionalT e m ()) > (h > ExceptionalT e m a) > ExceptionalT e m aSource
If the enclosed monad has custom exception facilities, they could skip the cleanup code. Make sure, that this cannot happen by choosing an appropriate monad.
resolveT :: Monad m => (e > m a) > ExceptionalT e m a > m aSource
tryT :: Monad m => ExceptionalT e m a > m (Exceptional e a)Source
:: Monad m  
=> (e0 > Maybe e1)  exception handler 
> (a > b > b) 

> b  empty 
> ExceptionalT e0 m a  atomic action to repeat 
> ExceptionalT e1 m b 
:: (Monad m, Monoid a)  
=> (e0 > Maybe e1)  exception handler 
> ExceptionalT e0 m a  atomic action to repeat 
> ExceptionalT e1 m a 