-- | Extend a monad with a read-only environment
module Mini.Transformers.ReaderT (
  -- * Type
  ReaderT (
    ReaderT
  ),

  -- * Runner
  runReaderT,

  -- * Operations
  ask,
  local,
) where

import Control.Applicative (
  Alternative (
    empty,
    (<|>)
  ),
 )
import Control.Monad (
  ap,
  liftM,
 )
import Mini.Transformers.Class (
  MonadTrans (
    lift
  ),
 )

{-
 - Type
 -}

-- | A transformer with read-only /r/, inner monad /m/, return /a/
newtype ReaderT r m a = ReaderT
  { forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT :: r -> m a
  -- ^ Unwrap a 'ReaderT' computation with an initial read-only value
  }

instance (Monad m) => Functor (ReaderT r m) where
  fmap :: forall a b. (a -> b) -> ReaderT r m a -> ReaderT r m b
fmap = (a -> b) -> ReaderT r m a -> ReaderT r m b
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM

instance (Monad m) => Applicative (ReaderT r m) where
  pure :: forall a. a -> ReaderT r m a
pure = (r -> m a) -> ReaderT r m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((r -> m a) -> ReaderT r m a)
-> (a -> r -> m a) -> a -> ReaderT r m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> r -> m a
forall a b. a -> b -> a
const (m a -> r -> m a) -> (a -> m a) -> a -> r -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
  <*> :: forall a b. ReaderT r m (a -> b) -> ReaderT r m a -> ReaderT r m b
(<*>) = ReaderT r m (a -> b) -> ReaderT r m a -> ReaderT r m b
forall (m :: * -> *) a b. Monad m => m (a -> b) -> m a -> m b
ap

instance (Monad m, Alternative m) => Alternative (ReaderT r m) where
  empty :: forall a. ReaderT r m a
empty = (r -> m a) -> ReaderT r m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((r -> m a) -> ReaderT r m a)
-> (m a -> r -> m a) -> m a -> ReaderT r m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> r -> m a
forall a b. a -> b -> a
const (m a -> ReaderT r m a) -> m a -> ReaderT r m a
forall a b. (a -> b) -> a -> b
$ m a
forall a. m a
forall (f :: * -> *) a. Alternative f => f a
empty
  ReaderT r m a
m <|> :: forall a. ReaderT r m a -> ReaderT r m a -> ReaderT r m a
<|> ReaderT r m a
n = (r -> m a) -> ReaderT r m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((r -> m a) -> ReaderT r m a) -> (r -> m a) -> ReaderT r m a
forall a b. (a -> b) -> a -> b
$ \r
r -> ReaderT r m a -> r -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT r m a
m r
r m a -> m a -> m a
forall a. m a -> m a -> m a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> ReaderT r m a -> r -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT r m a
n r
r

instance (Monad m) => Monad (ReaderT r m) where
  ReaderT r m a
m >>= :: forall a b. ReaderT r m a -> (a -> ReaderT r m b) -> ReaderT r m b
>>= a -> ReaderT r m b
k = (r -> m b) -> ReaderT r m b
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((r -> m b) -> ReaderT r m b) -> (r -> m b) -> ReaderT r m b
forall a b. (a -> b) -> a -> b
$ \r
r -> ReaderT r m a -> r -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT r m a
m r
r m a -> (a -> m b) -> m b
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (ReaderT r m b -> r -> m b
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
`runReaderT` r
r) (ReaderT r m b -> m b) -> (a -> ReaderT r m b) -> a -> m b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ReaderT r m b
k

instance MonadTrans (ReaderT r) where
  lift :: forall (m :: * -> *) a. Monad m => m a -> ReaderT r m a
lift = (r -> m a) -> ReaderT r m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((r -> m a) -> ReaderT r m a)
-> (m a -> r -> m a) -> m a -> ReaderT r m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> r -> m a
forall a b. a -> b -> a
const

{-
 - Operations
 -}

-- | Fetch the read-only environment
ask :: (Monad m) => ReaderT r m r
ask :: forall (m :: * -> *) r. Monad m => ReaderT r m r
ask = (r -> m r) -> ReaderT r m r
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT r -> m r
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure

-- | Run a computation in a modified environment
local :: (r -> r') -> ReaderT r' m a -> ReaderT r m a
local :: forall r r' (m :: * -> *) a.
(r -> r') -> ReaderT r' m a -> ReaderT r m a
local r -> r'
f ReaderT r' m a
m = (r -> m a) -> ReaderT r m a
forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT ((r -> m a) -> ReaderT r m a) -> (r -> m a) -> ReaderT r m a
forall a b. (a -> b) -> a -> b
$ ReaderT r' m a -> r' -> m a
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT r' m a
m (r' -> m a) -> (r -> r') -> r -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> r'
f