mini-2.0.0.0: src/Mini/Transformers/Reader.hs
-- | Extend a monad with a read-only environment
module Mini.Transformers.Reader (
-- * Type
ReaderT (
ReaderT
),
runReaderT,
-- * Operations
ask,
local,
) where
import Control.Applicative (
Alternative,
empty,
(<|>),
)
import Control.Monad (
ap,
liftM,
)
import Control.Monad.IO.Class (
MonadIO,
liftIO,
)
import Data.Bifunctor (
first,
)
import Mini.Random.Class (
Random,
random,
)
import Mini.Transformers.Class (
MonadTrans,
lift,
)
import Prelude (
Applicative,
Functor,
Monad,
MonadFail,
const,
fail,
fmap,
pure,
($),
(.),
(<*>),
(>>=),
)
-- Type
-- | A transformer with read-only /r/, inner monad /m/, return /a/
newtype ReaderT r m a = ReaderT
{ runReaderT :: r -> m a
-- ^ Unwrap a transformer computation with an initial read-only value
}
instance (Monad m) => Functor (ReaderT r m) where
fmap = liftM
instance (Monad m) => Applicative (ReaderT r m) where
pure = lift . pure
(<*>) = ap
instance (Monad m, Alternative m) => Alternative (ReaderT r m) where
empty = lift empty
m <|> n = ReaderT $ \r -> runReaderT m r <|> runReaderT n r
instance (Monad m) => Monad (ReaderT r m) where
m >>= k = ReaderT $ \r -> runReaderT m r >>= (`runReaderT` r) . k
instance MonadTrans (ReaderT r) where
lift = ReaderT . const
instance (MonadFail m) => MonadFail (ReaderT r m) where
fail = lift . fail
instance (MonadIO m) => MonadIO (ReaderT r m) where
liftIO = lift . liftIO
instance (Monad m, Random a) => Random (ReaderT r m a) where
random = first pure . random
-- Operations
-- | Fetch the read-only environment
ask :: (Monad m) => ReaderT r m r
ask = ReaderT pure
-- | Run a computation in a modified environment
local :: (r -> r') -> ReaderT r' m a -> ReaderT r m a
local f m = ReaderT $ runReaderT m . f