{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Control.Carrier.Reader
(
runReader
, ReaderC(..)
, module Control.Effect.Reader
) where
import Control.Algebra
import Control.Applicative (Alternative(..), liftA2)
import Control.Effect.Reader
import Control.Monad (MonadPlus)
import Control.Monad.Fail as Fail
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
runReader :: r -> ReaderC r m a -> m a
runReader r (ReaderC runReaderC) = runReaderC r
{-# INLINE runReader #-}
newtype ReaderC r m a = ReaderC (r -> m a)
deriving (Functor)
instance Applicative m => Applicative (ReaderC r m) where
pure = ReaderC . const . pure
{-# INLINE pure #-}
ReaderC f <*> ReaderC a = ReaderC (liftA2 (<*>) f a)
{-# INLINE (<*>) #-}
liftA2 f (ReaderC a) (ReaderC b) = ReaderC $ \ r ->
liftA2 f (a r) (b r)
{-# INLINE liftA2 #-}
ReaderC u *> ReaderC v = ReaderC $ \ r -> u r *> v r
{-# INLINE (*>) #-}
ReaderC u <* ReaderC v = ReaderC $ \ r -> u r <* v r
{-# INLINE (<*) #-}
instance Alternative m => Alternative (ReaderC r m) where
empty = ReaderC (const empty)
{-# INLINE empty #-}
ReaderC l <|> ReaderC r = ReaderC (liftA2 (<|>) l r)
{-# INLINE (<|>) #-}
instance Monad m => Monad (ReaderC r m) where
ReaderC a >>= f = ReaderC (\ r -> a r >>= runReader r . f)
{-# INLINE (>>=) #-}
instance Fail.MonadFail m => Fail.MonadFail (ReaderC r m) where
fail = ReaderC . const . Fail.fail
{-# INLINE fail #-}
instance MonadFix m => MonadFix (ReaderC s m) where
mfix f = ReaderC (\ r -> mfix (runReader r . f))
{-# INLINE mfix #-}
instance MonadIO m => MonadIO (ReaderC r m) where
liftIO = ReaderC . const . liftIO
{-# INLINE liftIO #-}
instance (Alternative m, Monad m) => MonadPlus (ReaderC r m)
instance MonadTrans (ReaderC r) where
lift = ReaderC . const
{-# INLINE lift #-}
instance Algebra sig m => Algebra (Reader r :+: sig) (ReaderC r m) where
alg hdl sig ctx = ReaderC $ \ r -> case sig of
L Ask -> pure (r <$ ctx)
L (Local f m) -> runReader (f r) (hdl (m <$ ctx))
R other -> alg (runReader r . hdl) other ctx
{-# INLINE alg #-}