module Control.Monad.Exception.Synchronous (
Exceptional(..),
fromMaybe, toMaybe,
fromEither, toEither,
fromExitCode, toExitCode,
getExceptionNull,
switch,
force,
mapException,
mapExceptional,
throw,
assert,
catch,
resolve,
merge,
alternative,
ExceptionalT(..),
fromMaybeT, toMaybeT,
fromErrorT, toErrorT,
fromEitherT, toEitherT,
fromExitCodeT, toExitCodeT,
liftT,
switchT,
forceT,
mapExceptionT,
mapExceptionalT,
throwT,
assertT,
catchT,
bracketT,
resolveT,
tryT,
manyT,
manyMonoidT,
mergeT,
alternativeT,
) where
import Control.Applicative (Applicative(pure, (<*>)))
import Control.Monad (Monad, return, fail, liftM, liftM2, (>>=), (>>), (=<<),
)
import Control.Monad.Fix (MonadFix, mfix, )
import Control.Monad.Trans.Class (MonadTrans, lift, )
import Control.Monad.Trans.Error (ErrorT(ErrorT, runErrorT))
import Control.Monad.Trans.Maybe (MaybeT(MaybeT, runMaybeT))
import Control.DeepSeq (NFData, rnf, )
import Data.Functor (Functor, fmap, )
import Data.Monoid(Monoid, mappend, mempty, Endo(Endo, appEndo), )
import Data.Function (flip, const, (.), ($), )
import Data.Either (Either(Left, Right), either, )
import Data.Maybe (Maybe(Just, Nothing), maybe, )
import Data.Bool (Bool, )
import Data.Eq (Eq, )
import System.Exit (ExitCode(ExitSuccess, ExitFailure), )
import Prelude (Show, Int, error, )
data Exceptional e a =
Success a
| Exception e
deriving (Show, Eq)
fromMaybe :: e -> Maybe a -> Exceptional e a
fromMaybe e = maybe (Exception e) Success
fromEither :: Either e a -> Exceptional e a
fromEither = either Exception Success
toMaybe :: Exceptional e a -> Maybe a
toMaybe = switch (const Nothing) Just
toEither :: Exceptional e a -> Either e a
toEither x =
case x of
Success a -> Right a
Exception e -> Left e
toExitCode :: Exceptional Int () -> ExitCode
toExitCode e =
case e of
Success () -> ExitSuccess
Exception n -> ExitFailure n
fromExitCode :: ExitCode -> Exceptional Int ()
fromExitCode e =
case e of
ExitSuccess -> Success ()
ExitFailure n -> Exception n
getExceptionNull :: Exceptional e () -> Maybe e
getExceptionNull x =
case x of
Success _ -> Nothing
Exception e -> Just e
switch :: (e -> b) -> (a -> b) -> Exceptional e a -> b
switch f g x =
case x of
Success a -> g a
Exception e -> f e
force :: Exceptional e a -> Exceptional e a
force ~(Success a) = Success a
mapException :: (e0 -> e1) -> Exceptional e0 a -> Exceptional e1 a
mapException f x =
case x of
Success a -> Success a
Exception e -> Exception (f e)
mapExceptional :: (e0 -> e1) -> (a -> b) -> Exceptional e0 a -> Exceptional e1 b
mapExceptional f g x =
case x of
Success a -> Success (g a)
Exception e -> Exception (f e)
throw :: e -> Exceptional e a
throw = Exception
assert :: e -> Bool -> Exceptional e ()
assert e b =
if b then Success () else throw e
catch :: Exceptional e0 a -> (e0 -> Exceptional e1 a) -> Exceptional e1 a
catch x handler =
case x of
Success a -> Success a
Exception e -> handler e
resolve :: (e -> a) -> Exceptional e a -> a
resolve handler x =
case x of
Success a -> a
Exception e -> handler e
infixl 3 `alternative`, `alternativeT`
alternative, _alternative ::
Exceptional e a -> Exceptional e a -> Exceptional e a
alternative x y = catch x (const y)
_alternative x y = switch (const y) Success x
infixl 4 `merge`, `mergeT`
merge, mergeLazy, _mergeStrict ::
(Monoid e) =>
Exceptional e (a -> b) -> Exceptional e a -> Exceptional e b
merge = mergeLazy
mergeLazy ef ea =
case ef of
Exception e0 ->
Exception $ mappend e0 $
case ea of
Success _ -> mempty
Exception e1 -> e1
Success f -> fmap f ea
_mergeStrict ef ea =
case (ef,ea) of
(Success f, Success a) -> Success $ f a
(Exception e, Success _) -> Exception e
(Success _, Exception e) -> Exception e
(Exception e0, Exception e1) -> Exception $ mappend e0 e1
instance (NFData e, NFData a) => NFData (Exceptional e a) where
rnf = switch rnf rnf
instance Functor (Exceptional e) where
fmap f x =
case x of
Success a -> Success (f a)
Exception e -> Exception e
instance Applicative (Exceptional e) where
pure = Success
f <*> x =
case f of
Exception e -> Exception e
Success g ->
case x of
Success a -> Success (g a)
Exception e -> Exception e
instance Monad (Exceptional e) where
return = Success
fail _msg = Exception (error "Exception.Synchronous: Monad.fail method is not supported")
x >>= f =
case x of
Exception e -> Exception e
Success y -> f y
instance MonadFix (Exceptional e) where
mfix f =
let unSuccess ~(Success x) = x
a = f (unSuccess a)
in a
newtype ExceptionalT e m a =
ExceptionalT {runExceptionalT :: m (Exceptional e a)}
_assertMaybeT :: (Monad m) => e -> Maybe a -> ExceptionalT e m a
_assertMaybeT e = maybe (throwT e) return
fromMaybeT :: Monad m => e -> MaybeT m a -> ExceptionalT e m a
fromMaybeT e = ExceptionalT . liftM (fromMaybe e) . runMaybeT
toMaybeT :: Monad m => ExceptionalT e m a -> MaybeT m a
toMaybeT = MaybeT . liftM toMaybe . runExceptionalT
fromErrorT :: Monad m => ErrorT e m a -> ExceptionalT e m a
fromErrorT = fromEitherT . runErrorT
toErrorT :: Monad m => ExceptionalT e m a -> ErrorT e m a
toErrorT = ErrorT . toEitherT
fromEitherT :: Monad m => m (Either e a) -> ExceptionalT e m a
fromEitherT = ExceptionalT . liftM fromEither
toEitherT :: Monad m => ExceptionalT e m a -> m (Either e a)
toEitherT = liftM toEither . runExceptionalT
toExitCodeT ::
(Functor m) =>
ExceptionalT Int m () -> m ExitCode
toExitCodeT act =
fmap toExitCode $ runExceptionalT act
fromExitCodeT ::
(Functor m) =>
m ExitCode -> ExceptionalT Int m ()
fromExitCodeT act =
ExceptionalT $ fmap fromExitCode act
liftT :: (Monad m) => Exceptional e a -> ExceptionalT e m a
liftT = ExceptionalT . return
switchT ::
(Monad m) =>
(e -> m b) -> (a -> m b) ->
ExceptionalT e m a -> m b
switchT e s m =
switch e s =<< runExceptionalT m
forceT :: Monad m => ExceptionalT e m a -> ExceptionalT e m a
forceT =
ExceptionalT . liftM force . runExceptionalT
mapExceptionT :: (Monad m) =>
(e0 -> e1) ->
ExceptionalT e0 m a ->
ExceptionalT e1 m a
mapExceptionT f =
ExceptionalT . liftM (mapException f) . runExceptionalT
mapExceptionalT ::
(m (Exceptional e0 a) -> n (Exceptional e1 b)) ->
ExceptionalT e0 m a -> ExceptionalT e1 n b
mapExceptionalT f =
ExceptionalT . f . runExceptionalT
throwT :: (Monad m) =>
e -> ExceptionalT e m a
throwT = ExceptionalT . return . throw
assertT :: (Monad m) =>
e -> Bool -> ExceptionalT e m ()
assertT e = ExceptionalT . return . assert e
catchT :: (Monad m) =>
ExceptionalT e0 m a ->
(e0 -> ExceptionalT e1 m a) ->
ExceptionalT e1 m a
catchT action handler =
ExceptionalT $ switchT (runExceptionalT . handler) (return . Success) action
bracketT :: (Monad m) =>
ExceptionalT e m h ->
(h -> ExceptionalT e m ()) ->
(h -> ExceptionalT e m a) ->
ExceptionalT e m a
bracketT open close action =
open >>= \h ->
ExceptionalT $
do a <- runExceptionalT (action h)
c <- runExceptionalT (close h)
return (a >>= \r -> c >> return r)
resolveT :: (Monad m) =>
(e -> m a) -> ExceptionalT e m a -> m a
resolveT handler x =
do r <- runExceptionalT x
resolve handler (fmap return r)
tryT :: (Monad m) =>
ExceptionalT e m a -> m (Exceptional e a)
tryT = runExceptionalT
manyT :: (Monad m) =>
(e0 -> Maybe e1) ->
(a -> b -> b) ->
b ->
ExceptionalT e0 m a ->
ExceptionalT e1 m b
manyT handler cons empty action =
liftM (flip appEndo empty) $
manyMonoidT handler $
liftM (Endo . cons) action
manyMonoidT :: (Monad m, Monoid a) =>
(e0 -> Maybe e1) ->
ExceptionalT e0 m a ->
ExceptionalT e1 m a
manyMonoidT handler action =
let recourse =
do r <- lift $ tryT action
case r of
Exception e -> ExceptionalT $ return $ maybe (Success mempty) throw (handler e)
Success x -> liftM (mappend x) recourse
in recourse
mergeT ::
(Monoid e, Monad m) =>
ExceptionalT e m (a -> b) ->
ExceptionalT e m a ->
ExceptionalT e m b
mergeT mf ma =
ExceptionalT $
liftM2 merge (runExceptionalT mf) (runExceptionalT ma)
alternativeT, _alternativeT ::
(Monad m) =>
ExceptionalT e m a -> ExceptionalT e m a -> ExceptionalT e m a
alternativeT x y = catchT x (const y)
_alternativeT x y =
ExceptionalT $ switchT (const $ runExceptionalT y) (return . Success) x
instance Functor m => Functor (ExceptionalT e m) where
fmap f (ExceptionalT x) =
ExceptionalT (fmap (fmap f) x)
instance Applicative m => Applicative (ExceptionalT e m) where
pure = ExceptionalT . pure . pure
ExceptionalT f <*> ExceptionalT x =
ExceptionalT (fmap (<*>) f <*> x)
instance Monad m => Monad (ExceptionalT e m) where
return = ExceptionalT . return . return
x0 >>= f =
ExceptionalT $
runExceptionalT x0 >>= \x1 ->
case x1 of
Exception e -> return (Exception e)
Success x -> runExceptionalT $ f x
instance (MonadFix m) => MonadFix (ExceptionalT e m) where
mfix f = ExceptionalT $ mfix $ \ ~(Success r) -> runExceptionalT $ f r
instance MonadTrans (ExceptionalT e) where
lift m = ExceptionalT $ liftM Success m