2010-07-27 21:18:53 +00:00
{- | This is just like "Control.Monad.Reader.Class" except you can access the context of any Reader in the monad stack instead of just the top one as long as the context types are different. If two or more readers in the stack have the same context type you get the context of the top one. -}
2010-06-21 15:06:20 +00:00
{- # LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverlappingInstances # -}
module Control.Monad.Context where
import Control.Monad.Reader
import Control.Monad.Error
-- | Same as 'MonadReader' but without functional dependency so the same monad can have multiple contexts with different types
2010-07-27 21:18:53 +00:00
class ( Monad m ) => Context x m where
2010-06-21 15:06:20 +00:00
context :: m x
-- ^ Get the context in the Reader in the monad stack that has @x@ context type. Analogous to 'ask'.
push :: ( x -> x ) -> m a -> m a
-- ^ Push new context in the Reader in the monad stack that has @x@ context type. Analogous to 'local'
instance ( Monad m ) => Context x ( ReaderT x m ) where
context = ask
push = local
2010-07-27 21:18:53 +00:00
instance ( Context x m ) => Context x ( ReaderT r m ) where
2010-06-21 15:06:20 +00:00
context = lift context
push f m = ReaderT ( push f . runReaderT m )
2010-07-27 21:18:53 +00:00
instance ( Context x m , Error e ) => Context x ( ErrorT e m ) where
2010-06-21 15:06:20 +00:00
context = lift context
push f = ErrorT . push f . runErrorT