module Data.EitherR (
    
    EitherR(..),
    
    succeed,
    
    throwE,
    catchE,
    handleE,
    fmapL,
    
    flipE,
    
    EitherRT(..),
    
    succeedT,
    
    throwT,
    catchT,
    handleT,
    fmapLT,
    
    flipET,
    ) where
import Control.Applicative (Applicative(pure, (<*>)), Alternative(empty, (<|>)))
import Control.Monad (liftM, ap, MonadPlus(mzero, mplus))
import Control.Monad.Trans.Class (MonadTrans(lift))
import Control.Monad.IO.Class (MonadIO(liftIO))
import Control.Monad.Trans.Either (EitherT(EitherT, runEitherT), left, right)
import Data.Monoid (Monoid(mempty, mappend))
newtype EitherR r e = EitherR { runEitherR :: Either e r }
instance Functor (EitherR r) where
    fmap = liftM
instance Applicative (EitherR r) where
    pure  = return
    (<*>) = ap
instance Monad (EitherR r) where
    return e = EitherR (Left e)
    EitherR m >>= f = case m of
        Left  e -> f e
        Right r -> EitherR (Right r)
instance (Monoid r) => Alternative (EitherR r) where
    empty = EitherR (Right mempty)
    e1@(EitherR (Left _)) <|> _ = e1
    _ <|> e2@(EitherR (Left _)) = e2
    EitherR (Right r1) <|> EitherR (Right r2)
        = EitherR (Right (mappend r1 r2))
instance (Monoid r) => MonadPlus (EitherR r) where
    mzero = empty
    mplus = (<|>)
succeed :: r -> EitherR r e
succeed r = EitherR (return r)
throwE :: e -> Either e r
throwE e = runEitherR (return e)
catchE :: Either a r -> (a -> Either b r) -> Either b r
e `catchE` f = runEitherR $ EitherR e >>= \a -> EitherR (f a)
handleE :: (a -> Either b r) -> Either a r -> Either b r
handleE = flip catchE
fmapL :: (a -> b) -> Either a r -> Either b r
fmapL f = runEitherR . fmap f . EitherR
flipE :: Either a b -> Either b a
flipE e = case e of
    Left  a -> Right a
    Right b -> Left  b
newtype EitherRT r m e = EitherRT { runEitherRT :: EitherT e m r }
instance (Monad m) => Functor (EitherRT r m) where
    fmap = liftM
instance (Monad m) => Applicative (EitherRT r m) where
    pure  = return
    (<*>) = ap
instance (Monad m) => Monad (EitherRT r m) where
    return e = EitherRT (left e)
    m >>= f = EitherRT $ EitherT $ do
        x <- runEitherT $ runEitherRT m
        runEitherT $ runEitherRT $ case x of
            Left  e -> f e
            Right r -> EitherRT (right r)
instance (Monad m, Monoid r) => Alternative (EitherRT r m) where
    empty = EitherRT $ EitherT $ return $ Right mempty
    e1 <|> e2 = EitherRT $ EitherT $ do
        x1 <- runEitherT $ runEitherRT e1
        case x1 of
            Left  l  -> return (Left l)
            Right r1 -> do
                x2 <- runEitherT $ runEitherRT e2
                case x2 of
                    Left  l  -> return (Left l)
                    Right r2 -> return (Right (mappend r1 r2))
instance (Monad m, Monoid r) => MonadPlus (EitherRT r m) where
    mzero = empty
    mplus = (<|>)
instance MonadTrans (EitherRT r) where
    lift = EitherRT . EitherT . liftM Left
instance (MonadIO m) => MonadIO (EitherRT r m) where
    liftIO = lift . liftIO
succeedT :: (Monad m) => r -> EitherRT r m e
succeedT r = EitherRT (return r)
throwT :: (Monad m) => e -> EitherT e m r
throwT e = runEitherRT (return e)
catchT :: (Monad m) => EitherT a m r -> (a -> EitherT b m r) -> EitherT b m r
e `catchT` f = runEitherRT $ EitherRT e >>= \a -> EitherRT (f a)
handleT :: (Monad m) => (a -> EitherT b m r) -> EitherT a m r -> EitherT b m r
handleT = flip catchT
fmapLT :: (Monad m) => (a -> b) -> EitherT a m r -> EitherT b m r
fmapLT f = runEitherRT . fmap f . EitherRT
flipET :: (Monad m) => EitherT a m b -> EitherT b m a
flipET = EitherT . liftM flipE . runEitherT