pipes-3.2.0: Control/Proxy/Trans/Either.hs
-- | This module provides the proxy transformer equivalent of 'EitherT'.
{-# LANGUAGE KindSignatures, CPP #-}
module Control.Proxy.Trans.Either (
-- * EitherP
EitherP(..),
runEitherK,
-- * Either operations
left,
right,
-- * Symmetric monad
-- $symmetry
throw,
catch,
handle,
fmapL
) where
import Control.Applicative (Applicative(pure, (<*>)), Alternative(empty, (<|>)))
import Control.Monad (MonadPlus(mzero, mplus))
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.Morph (MFunctor(hoist))
import Control.Monad.Trans.Class (MonadTrans(lift))
import Control.Proxy.Class (
Proxy(request, respond, (->>), (>>~)),
ProxyInternal(return_P, (?>=), lift_P, liftIO_P, hoist_P),
MonadPlusP(mzero_P, mplus_P) )
import Control.Proxy.Morph (PFunctor(hoistP), PMonad(embedP))
import Control.Proxy.Trans (ProxyTrans(liftP))
#if MIN_VERSION_base(4,6,0)
#else
import Prelude hiding (catch)
#endif
import Data.Monoid (Monoid(mempty, mappend))
-- | 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 (Proxy p, Monad m) => Functor (EitherP e p a' a b' b m) where
fmap f p = EitherP (
runEitherP p ?>= \e ->
return_P (case e of
Left l -> Left l
Right r -> Right (f r) ) )
instance (Proxy p, Monad m) => Applicative (EitherP e p a' a b' b m) where
pure = return
fp <*> xp = EitherP (
runEitherP fp ?>= \e1 ->
case e1 of
Left l -> return_P (Left l)
Right f ->
runEitherP xp ?>= \e2 ->
return_P (case e2 of
Left l -> Left l
Right x -> Right (f x) ) )
instance (Proxy p, Monad m) => Monad (EitherP e p a' a b' b m) where
return = return_P
(>>=) = (?>=)
instance (Proxy p) => MonadTrans (EitherP e p a' a b' b) where
lift = lift_P
instance (Proxy p) => MFunctor (EitherP e p a' a b' b) where
hoist = hoist_P
instance (Proxy p, MonadIO m) => MonadIO (EitherP e p a' a b' b m) where
liftIO = liftIO_P
instance (Proxy p, Monad m, Monoid e)
=> Alternative (EitherP e p a' a b' b m) where
empty = mzero
(<|>) = mplus
instance (Proxy p, Monad m, Monoid e)
=> MonadPlus (EitherP e p a' a b' b m) where
mzero = mzero_P
mplus = mplus_P
instance (Proxy p) => ProxyInternal (EitherP e p) where
return_P = \r -> EitherP (return_P (Right r))
m ?>= f = EitherP (
runEitherP m ?>= \e ->
case e of
Left l -> return_P (Left l)
Right r -> runEitherP (f r) )
lift_P m = EitherP (lift_P (m >>= \x -> return (Right x)))
hoist_P nat p = EitherP (hoist_P nat (runEitherP p))
liftIO_P m = EitherP (liftIO_P (m >>= \x -> return (Right x)))
instance (Proxy p) => Proxy (EitherP e p) where
fb' ->> p = EitherP ((\b' -> runEitherP (fb' b')) ->> runEitherP p)
p >>~ fb = EitherP (runEitherP p >>~ (\b -> runEitherP (fb b)))
request = \a' -> EitherP (request a' ?>= \a -> return_P (Right a ))
respond = \b -> EitherP (respond b ?>= \b' -> return_P (Right b'))
instance (Proxy p, Monoid e) => MonadPlusP (EitherP e p) where
mzero_P = EitherP (return_P (Left mempty))
mplus_P p1 p2 = EitherP (
runEitherP p1 ?>= \e1 ->
case e1 of
Right r -> return_P (Right r)
Left l1 ->
runEitherP p2 ?>= \e2 ->
case e2 of
Right r -> return_P (Right r)
Left l2 -> return_P (Left (mappend l1 l2)) )
instance ProxyTrans (EitherP e) where
liftP p = EitherP (p ?>= \x -> return_P (Right x))
instance PFunctor (EitherP e) where
hoistP nat p = EitherP (nat (runEitherP p))
instance PMonad (EitherP e) where
embedP nat p = EitherP (
runEitherP (nat (runEitherP p)) ?>= \x ->
return_P (case x of
Left e -> Left e
Right (Left e) -> Left e
Right (Right a) -> Right a ) )
-- | 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 p q = runEitherP (p q)
{-# INLINABLE runEitherK #-}
-- | Abort the computation and return a 'Left' result
left :: (Monad m, Proxy p) => e -> EitherP e p a' a b' b m r
left e = EitherP (return_P (Left e))
{-# INLINABLE left #-}
-- | Synonym for 'return'
right :: (Monad m, Proxy p) => r -> EitherP e p a' a b' b m r
right r = EitherP (return_P (Right r))
{-# INLINABLE 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 m, Proxy p) => e -> EitherP e p a' a b' b m r
throw = left
{-# INLINABLE throw #-}
-- | Resume from an aborted operation
catch
:: (Monad m, Proxy p)
=> 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 (
runEitherP m ?>= \e ->
runEitherP (case e of
Left l -> f l
Right r -> right r ))
{-# INLINABLE catch #-}
-- | 'catch' with the arguments flipped
handle
:: (Monad m, Proxy p)
=> (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 = catch m f
{-# INLINABLE handle #-}
-- | 'fmap' over the \'@L@\'eft variable
fmapL
:: (Monad m, Proxy p)
=> (e -> f) -> EitherP e p a' a b' b m r -> EitherP f p a' a b' b m r
fmapL f p = catch p (\e -> throw (f e))
{-# INLINABLE fmapL #-}