module Control.Monad.Trans.StringError where
import Control.Monad.Trans.Class (MonadTrans (lift))
import Control.Monad.IO.Class
import Control.Monad (MonadPlus(mzero, mplus))
import Control.Applicative
import Data.Foldable (Foldable(foldMap))
import Data.Traversable (Traversable(traverse))
import qualified Control.Monad.Fail as Fail
newtype StringErrorT m a = StringErrorT {runStringErrorT :: m (Either String a) }
mapStringErrorT :: (m (Either String a) -> n (Either String b)) -> StringErrorT m a -> StringErrorT n b
mapStringErrorT f = StringErrorT . f . runStringErrorT
instance MonadTrans StringErrorT where
lift m = StringErrorT $ m >>= (\ x -> return $ Right x)
instance (Functor m) => Functor (StringErrorT m) where
fmap f = mapStringErrorT (fmap (fmap f))
instance (Foldable f) => Foldable (StringErrorT f) where
foldMap f (StringErrorT a) = foldMap (foldMap f) a
instance (Traversable f) => Traversable (StringErrorT f) where
traverse f (StringErrorT a) = StringErrorT <$> traverse (traverse f) a
instance (Functor m, Monad m) => Applicative (StringErrorT m) where
pure = StringErrorT . return . Right
mf <*> mx = StringErrorT $ do
mb_f <- runStringErrorT mf
case mb_f of
Left s -> return (Left s)
Right f -> do
mb_x <- runStringErrorT mx
case mb_x of
Left s -> return (Left s)
Right x -> return (Right (f x))
m *> k = m >>= \_ -> k
instance (Functor m, Monad m) => Alternative (StringErrorT m) where
empty = StringErrorT (return $ Left "")
x <|> y = StringErrorT $ do
v <- runStringErrorT x
case v of
Left _ -> runStringErrorT y
Right _ -> return v
instance (Monad m) => Monad (StringErrorT m) where
return = StringErrorT . return . Right
(>>=) x f = StringErrorT $ do
v <- runStringErrorT x
case v of
Left s -> return (Left s)
Right y -> runStringErrorT (f y)
fail s = StringErrorT (return $ Left s)
instance (Monad m) => Fail.MonadFail (StringErrorT m) where
fail s = StringErrorT (return $ Left s)
instance (MonadIO m) => MonadIO (StringErrorT m) where
liftIO = lift . liftIO
instance (Monad m) => MonadPlus (StringErrorT m) where
mzero = StringErrorT (return $ Left "")
mplus x y = StringErrorT $ do
v <- runStringErrorT x
case v of
Left _ -> runStringErrorT y
Right _ -> return v