{- | @MonadPlus@ transformers. There are also @Monad@ and @MonadFix@ transformes, see the corresponding modules. Note that each @MonadPlus@ transformer is also a @Monad@ transformer. -} module Control.Monad.Trans.MonadPlus (MonadP, TransP(..), instP, mzero', mplus') where import Control.Monad.List import Control.Monad.Reader import Control.Monad.State import Control.Monad.Trans.Category import Control.Monad.Trans.Monad import Control.Monad.Writer -- | @MonadP m@ is actually a free @MonadPlus@ generated by @m@. @MonadP@ is a monad itself (on the @(* -> *)@ category), as usually happens with free structures. newtype MonadP m x = MonadP {bindP :: forall n. MonadPlus n => (m :-> n) -> n x} -- | A @MonadPlus@ is nothing but an algebra over the @MonadP@ monad. @instP@ provides it's structure map. instP :: MonadPlus m => Inst MonadP m instP mmx = bindP mmx id -- | Sometimes we need an @instance MonadPlus T@, while everything we've got is @InstP MonadP T@. In this case, @mzero'@ serves as a @mzero@ substitution. mzero' :: Inst MonadP m -> m x mzero' i = i $ MonadP {bindP = \_ -> mzero} -- | Sometimes we need an @instance Monad T@, while everything we've got is @Inst MonadP T@. In this case, @mplus'@ serves as a @mplus@ substitution. mplus' :: Inst MonadP m -> m x -> m x -> m x mplus' i mx1 mx2 = i $ MonadP {bindP = \mor -> mor mx1 `mplus` mor mx2} -- | A composable @MonadPlus@ transformer. class TransM t => TransP t where -- | You shoudn't (and probably can't) use *anything* except for @'instP'@, defined in this very module, as @transPInst@. -- -- If you define @instance TransP T where transPInst = instP@, then you would also need to define @instance MonadPlus m => MonadPlus (T m)@ somewhere in your code. transPInst :: MonadPlus m => Inst MonadP (t m) instance (MonadPlus m, TransP t) => MonadPlus (t :$ m) where mzero = ApplyF {runApplyF = mzero' transPInst} tm1 `mplus` tm2 = ApplyF {runApplyF = runApplyF tm1 `mplus1` runApplyF tm2} where mplus1 = mplus' transPInst deriving instance (MonadPlus m, TransP t1, TransP t2) => MonadPlus ((t2 :. t1) m) instance (TransP t1, TransP t2) => TransP (t2 :. t1) where transPInst = instP instance TransP ListT where transPInst = instP instance TransP (ReaderT r) where transPInst = instP instance TransP (StateT s) where transPInst = instP instance Monoid w => TransP (WriterT w) where transPInst = instP