module Control.Monad.Exception.Asynchronous.Lazy (
Exceptional(..),
pure,
broken,
fromSynchronous,
fromSynchronousNull,
fromSynchronousMonoid,
toSynchronous,
throw,
throwMonoid,
eatNothing,
zipWith,
append,
continue,
maybeAbort,
force,
mapException,
mapExceptional,
simultaneousBind,
simultaneousBindM,
sequenceF,
traverse,
sequenceA,
mapM,
sequence,
swapToSynchronousAsynchronous,
swapToAsynchronousSynchronous,
ExceptionalT(..),
fromSynchronousT,
fromSynchronousMonoidT,
forceT,
mapExceptionT,
mapExceptionalT,
throwMonoidT,
eatNothingT,
bindT,
manySynchronousT,
manyMonoidT,
processToSynchronousT_,
appendM,
continueM,
) where
import qualified Control.Monad.Exception.Synchronous as Sync
import Control.Monad (Monad, return, liftM, mplus, join, (>>=), (>>), )
import Control.Applicative (Applicative, liftA, )
import Control.DeepSeq (NFData, rnf, )
import Data.Functor (Functor, fmap, )
import Data.Monoid(Monoid, mappend, mempty, )
import Data.Semigroup (Semigroup((<>)), )
import Data.Function (const, (.), ($), )
import Data.Maybe (Maybe(Just, Nothing), maybe, )
import Prelude (Show, )
data Exceptional e a =
Exceptional {exception :: Maybe e, result :: a}
deriving Show
pure :: a -> Exceptional e a
pure = Exceptional Nothing
broken :: e -> a -> Exceptional e a
broken e = Exceptional (Just e)
fromSynchronous :: a -> Sync.Exceptional e a -> Exceptional e a
fromSynchronous deflt x =
force $ case x of
Sync.Success y -> Exceptional Nothing y
Sync.Exception e -> Exceptional (Just e) deflt
fromSynchronousNull :: Sync.Exceptional e () -> Exceptional e ()
fromSynchronousNull = fromSynchronous ()
fromSynchronousMonoid :: Monoid a =>
Sync.Exceptional e a -> Exceptional e a
fromSynchronousMonoid = fromSynchronous mempty
toSynchronous :: Exceptional e a -> Sync.Exceptional e a
toSynchronous (Exceptional me a) =
maybe (Sync.Success a) Sync.Exception me
throw :: e -> Exceptional e ()
throw e = broken e ()
throwMonoid :: Monoid a => e -> Exceptional e a
throwMonoid e = broken e mempty
eatNothing :: Exceptional (Maybe e) a -> Exceptional e a
eatNothing (Exceptional e a) =
Exceptional (join e) a
zipWith ::
(a -> b -> c) ->
Exceptional e [a] -> Exceptional e [b] -> Exceptional e [c]
zipWith f (Exceptional ea a0) (Exceptional eb b0) =
let recourse (a:as) (b:bs) =
fmap (f a b :) (recourseF as bs)
recourse as _ =
Exceptional (case as of [] -> mplus ea eb; _ -> eb) []
recourseF as bs = force $ recourse as bs
in recourseF a0 b0
infixr 1 `append`, `continue`, `maybeAbort`
append ::
Monoid a =>
Exceptional e a -> Exceptional e a -> Exceptional e a
append (Exceptional ea a) b =
fmap (mappend a) $ continue ea b
continue ::
Monoid a =>
Maybe e -> Exceptional e a -> Exceptional e a
continue ea b =
force $
case ea of
Just _ -> Exceptional ea mempty
Nothing -> b
maybeAbort ::
Exceptional e a -> Maybe e -> Exceptional e a
maybeAbort ~(Exceptional ea a) eb =
Exceptional (mplus ea eb) a
instance (NFData e, NFData a) => NFData (Exceptional e a) where
rnf (Exceptional e a) = rnf (e, a)
instance Monoid a => Semigroup (Exceptional e a) where
Exceptional ea a <> Exceptional eb b =
Exceptional (mplus ea eb) (mappend a (maybe b (const mempty) ea))
instance Monoid a => Monoid (Exceptional e a) where
mempty = pure mempty
mappend = (<>)
{-# INLINE force #-}
force :: Exceptional e a -> Exceptional e a
force ~(Exceptional e a) = Exceptional e a
mapException :: (e0 -> e1) -> Exceptional e0 a -> Exceptional e1 a
mapException f ~(Exceptional e a) = Exceptional (fmap f e) a
mapExceptional :: (e0 -> e1) -> (a -> b) -> Exceptional e0 a -> Exceptional e1 b
mapExceptional f g ~(Exceptional e a) = Exceptional (fmap f e) (g a)
instance Functor (Exceptional e) where
fmap f ~(Exceptional e a) = Exceptional e (f a)
infixr 1 `simultaneousBind`, `simultaneousBindM`
{-# DEPRECATED simultaneousBind, simultaneousBindM "Check whether this function is really what you need. It generates an unreasonable exception when the second exception is caused by the first one." #-}
simultaneousBind :: Exceptional e a -> (a -> Exceptional e b) -> Exceptional e b
simultaneousBind ~(Exceptional mea a) actB =
let Exceptional meb b = actB a
in Exceptional (mplus meb mea) b
simultaneousBindM :: (Monad m) => m (Exceptional e a) -> (a -> m (Exceptional e b)) -> m (Exceptional e b)
simultaneousBindM actA actB =
do Exceptional mea a <- actA
Exceptional meb b <- actB a
return (Exceptional (mplus meb mea) b)
{-# INLINE sequenceF #-}
sequenceF :: Functor f => Exceptional e (f a) -> f (Exceptional e a)
sequenceF ~(Exceptional e a) =
fmap (Exceptional e) a
{-# INLINE traverse #-}
traverse :: Applicative f => (a -> f b) -> Exceptional e a -> f (Exceptional e b)
traverse f = sequenceA . fmap f
{-# INLINE sequenceA #-}
sequenceA :: Applicative f => Exceptional e (f a) -> f (Exceptional e a)
sequenceA ~(Exceptional e a) =
liftA (Exceptional e) a
{-# INLINE mapM #-}
mapM :: Monad m => (a -> m b) -> Exceptional e a -> m (Exceptional e b)
mapM f = sequence . fmap f
{-# INLINE sequence #-}
sequence :: Monad m => Exceptional e (m a) -> m (Exceptional e a)
sequence ~(Exceptional e a) =
liftM (Exceptional e) a
swapToSynchronousAsynchronous :: Exceptional e0 (Sync.Exceptional e1 a) -> Sync.Exceptional e1 (Exceptional e0 a)
swapToSynchronousAsynchronous ~(Exceptional e0 x) =
fmap (Exceptional e0) x
swapToAsynchronousSynchronous :: Sync.Exceptional e1 (Exceptional e0 a) -> Exceptional e0 (Sync.Exceptional e1 a)
swapToAsynchronousSynchronous x =
force $
case x of
Sync.Exception e1 -> pure $ Sync.Exception e1
Sync.Success s -> fmap Sync.Success s
newtype ExceptionalT e m a =
ExceptionalT {runExceptionalT :: m (Exceptional e a)}
fromSynchronousT :: Functor m =>
a -> Sync.ExceptionalT e m a -> ExceptionalT e m a
fromSynchronousT deflt =
ExceptionalT .
fmap (fromSynchronous deflt) .
Sync.runExceptionalT
fromSynchronousMonoidT :: (Functor m, Monoid a) =>
Sync.ExceptionalT e m a -> ExceptionalT e m a
fromSynchronousMonoidT =
fromSynchronousT mempty
instance Functor m => Functor (ExceptionalT e m) where
fmap f (ExceptionalT x) =
ExceptionalT (fmap (fmap f) x)
instance (Monad m, Monoid a) => Semigroup (ExceptionalT e m a) where
x <> y =
ExceptionalT $
appendM (runExceptionalT x) (runExceptionalT y)
instance (Monad m, Monoid a) => Monoid (ExceptionalT e m a) where
mempty = ExceptionalT $ return mempty
mappend = (<>)
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
throwMonoidT :: (Monad m, Monoid a) =>
e -> ExceptionalT e m a
throwMonoidT = ExceptionalT . return . throwMonoid
eatNothingT :: Monad m =>
ExceptionalT (Maybe e) m a -> ExceptionalT e m a
eatNothingT =
mapExceptionalT (liftM eatNothing)
infixl 1 `bindT`
bindT :: (Monad m, Monoid b) =>
ExceptionalT e m a ->
(a -> ExceptionalT e m b) ->
ExceptionalT e m b
bindT x y =
ExceptionalT $
runExceptionalT x >>= \r ->
runExceptionalT $ maybe (y $ result r) throwMonoidT (exception r)
infixr 1 `appendM`, `continueM`
appendM :: (Monad m, Monoid a) =>
m (Exceptional e a) -> m (Exceptional e a) -> m (Exceptional e a)
appendM x y =
do r <- x
liftM (fmap (mappend (result r))) $
continueMPlain (exception r) y
continueM :: (Monad m, Monoid a) =>
m (Maybe e) -> m (Exceptional e a) -> m (Exceptional e a)
continueM mx y =
mx >>= \x -> continueMPlain x y
continueMPlain :: (Monad m, Monoid a) =>
Maybe e -> m (Exceptional e a) -> m (Exceptional e a)
continueMPlain x y =
maybe y (return . throwMonoid) x
manySynchronousT :: (Monad m) =>
(m (Exceptional e b) -> m (Exceptional e b))
->
(a -> b -> b) ->
b ->
Sync.ExceptionalT e m a ->
m (Exceptional e b)
manySynchronousT defer cons empty action =
let recourse =
liftM force $ defer $
do r <- Sync.tryT action
case r of
Sync.Exception e -> return (Exceptional (Just e) empty)
Sync.Success x -> liftM (fmap (cons x)) recourse
in recourse
{-# DEPRECATED manySynchronousT "use manyMonoidT with appropriate Monad like LazyIO and result Monoid like Endo instead" #-}
manyMonoidT :: (Monad m, Monoid a) =>
ExceptionalT e m a ->
ExceptionalT e m a
manyMonoidT act =
let
customFmap f = mapExceptionalT (liftM (fmap f))
go = act `bindT` \r -> customFmap (mappend r) go
in go
processToSynchronousT_ :: (Monad m) =>
(b -> Maybe (a,b)) ->
(a -> Sync.ExceptionalT e m ())
->
Exceptional e b ->
Sync.ExceptionalT e m ()
processToSynchronousT_ decons action (Exceptional me x) =
let recourse b0 =
maybe
(maybe (return ()) Sync.throwT me)
(\(a,b1) -> action a >> recourse b1)
(decons b0)
in recourse x