pipes-2.5.0: Control/Proxy/Trans/Either.hs
-- | This module provides the proxy transformer equivalent of 'EitherT'.
{-# LANGUAGE FlexibleContexts, KindSignatures #-}
module Control.Proxy.Trans.Either (
-- * EitherP
EitherP(..),
runEitherK,
-- * Either operations
left,
right,
-- * Symmetric monad
-- $symmetry
throw,
catch,
handle
) where
import Control.Applicative (Applicative(pure, (<*>)), Alternative(empty, (<|>)))
import Control.Monad (liftM, ap, MonadPlus(mzero, mplus))
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.Trans.Class (MonadTrans(lift))
import Control.MFunctor (MFunctor(mapT))
import Control.Proxy.Class (Channel(idT, (>->)))
import Control.Proxy.Trans (ProxyTrans(liftP))
import Prelude hiding (catch)
-- | The 'Either' proxy transformer
newtype EitherP e p a' a b' b (m :: * -> *) r
= EitherP { runEitherP :: p a' a b' b m (Either e r) }
instance (Monad (p a' a b' b m)) => Functor (EitherP e p a' a b' b m) where
fmap = liftM
instance (Monad (p a' a b' b m)) => Applicative (EitherP e p a' a b' b m) where
pure = return
(<*>) = ap
instance (Monad (p a' a b' b m)) => Monad (EitherP e p a' a b' b m) where
return = right
m >>= f = EitherP $ do
e <- runEitherP m
runEitherP $ case e of
Left l -> left l
Right r -> f r
instance (MonadPlus (p a' a b' b m))
=> Alternative (EitherP e p a' a b' b m) where
empty = mzero
(<|>) = mplus
instance (MonadPlus (p a' a b' b m))
=> MonadPlus (EitherP e p a' a b' b m) where
mzero = EitherP mzero
mplus m1 m2 = EitherP $ mplus (runEitherP m1) (runEitherP m2)
instance (MonadTrans (p a' a b' b)) => MonadTrans (EitherP e p a' a b' b) where
lift = EitherP . lift . liftM Right
instance (MonadIO (p a' a b' b m)) => MonadIO (EitherP e p a' a b' b m) where
liftIO = EitherP . liftIO . liftM Right
instance (MFunctor (p a' a b' b)) => MFunctor (EitherP e p a' a b' b) where
mapT nat = EitherP . mapT nat . runEitherP
instance (Channel p) => Channel (EitherP e p) where
idT = EitherP . idT
p1 >-> p2 = (EitherP .) $ runEitherP . p1 >-> runEitherP . p2
instance ProxyTrans (EitherP e) where
liftP = EitherP . liftM Right
-- | Run an 'EitherP' \'@K@\'leisi arrow, returning either a 'Left' or 'Right'
runEitherK
:: (q -> EitherP e p a' a b' b m r) -> (q -> p a' a b' b m (Either e r))
runEitherK = (runEitherP .)
-- | Abort the computation and return a 'Left' result
left :: (Monad (p a' a b' b m)) => e -> EitherP e p a' a b' b m r
left = EitherP . return . Left
-- | Synonym for 'return'
right :: (Monad (p a' a b' b m)) => r -> EitherP e p a' a b' b m r
right = EitherP . return . Right
{- $symmetry
'EitherP' forms a second symmetric monad over the left type variable.
'throw' is symmetric to 'return'
'catch' is symmetric to ('>>=')
These two functions obey the monad laws:
> catch m throw = m
>
> catch (throw e) f = f e
>
> catch (catch m f) g = catch m (\e -> catch (f e) g)
-}
-- | Synonym for 'left'
throw :: (Monad (p a' a b' b m)) => e -> EitherP e p a' a b' b m r
throw = left
-- | Resume from an aborted operation
catch
:: (Monad (p a' a b' b m))
=> EitherP e p a' a b' b m r -- ^ Original computation
-> (e -> EitherP f p a' a b' b m r) -- ^ Handler
-> EitherP f p a' a b' b m r -- ^ Handled computation
catch m f = EitherP $ do
e <- runEitherP m
runEitherP $ case e of
Left l -> f l
Right r -> right r
-- | 'catch' with the arguments flipped
handle
:: (Monad (p a' a b' b m))
=> (e -> EitherP f p a' a b' b m r) -- ^ Handler
-> EitherP e p a' a b' b m r -- ^ Original computation
-> EitherP f p a' a b' b m r -- ^ Handled computation
handle f m = EitherP $ do
e <- runEitherP m
runEitherP $ case e of
Left l -> f l
Right r -> right r