I would like define a monad transformer, that, among other things, endows a base monad with error functionality. The transformed monad should be an instance of MonadPlus if the base monad is, but I can't figure out how to define the MonadPlus instance so that the ErrorT transformer will return more than one answer (if there is more than one answer). My two attempts are in the code below. At the end of the code, is a statement showing how the monad transformer should behave if the base monad is []
. Thanks.
import Control.Monad.Error
import Control.Monad.Trans.Class
data MyTrans m a = MyTrans {runMyTrans :: ErrorT String m a}
instance Monad m => Monad (MyTrans m) where
return = MyTrans . lift . return
m >>= f = MyTrans $ do x <- runMyTrans m
runMyTrans (f x)
instance MonadTrans MyTrans where
lift m = MyTrans $ lift m
instance MonadPlus m => MonadPlus (MyTrans m) where
mzero = MyTrans $ lift mzero
-- Attempt #1 (Only reveals the first element)
m `mplus` n = MyTrans $ (runMyTrans m) `mplus` (runMyTrans n)
-- Attempt #2 (Incomplete: see undefined statements)
-- m `mplus` n = MyTrans $
-- lift $ do a <- runErrorT $ runMyTrans m
-- b <- runErrorT $ runMyTrans n
-- case a of
-- Right r 1
-- Left _ -> undefined
-- -> case b of
-- Left _ -> undefined
-- Right t -> return r `mplus` return t
type MyMonad = MyTrans []
x = return 1 :: MyMonad Int
y = MyTrans $ throwError "Error" :: MyMonad Int
z = x `mplus` y
main = do
print $ (runErrorT $ runMyTrans z) -- should be [Right 1, Left "Error"]