{-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE UndecidableInstances #-} module Control.Effect.Environment (EffEnvironment, runInEnvironment, ask, asks, mapEnvironment, liftReader, effToReaderT, readerTToEff) where import Control.Effect import Control.Monad.Morph (lift, hoist, generalize) import Control.Monad.Trans.Reader (Reader, ReaderT(..)) import qualified Control.Monad.Trans.Reader as Reader class (Monad m) => EffEnvironment env m | m -> env where liftReader :: Reader env a -> m a instance Monad m => EffEnvironment env (Eff (Reader env) m) where liftReader = interpret {-# INLINE liftReader #-} instance {-# OVERLAPPABLE #-} (EffEnvironment env m) => EffEnvironment env (Eff effects m) where liftReader = lift . liftReader {-# INLINE liftReader #-} ask :: (EffEnvironment env m) => m env ask = liftReader Reader.ask {-# INLINE ask #-} asks :: (EffEnvironment a m) => (a -> b) -> m b asks f = fmap f ask {-# INLINE asks #-} runInEnvironment :: Monad m => Eff (Reader env) m a -> env -> m a runInEnvironment = runReaderT . effToReaderT {-# INLINE runInEnvironment #-} mapEnvironment :: (EffEnvironment env m) => (env -> env') -> Eff (Reader env') m a -> m a mapEnvironment f m = ask >>= runInEnvironment m . f {-# INLINE mapEnvironment #-} effToReaderT :: Monad m => Eff (Reader e) m a -> ReaderT e m a effToReaderT = translate (lift . hoist generalize) {-# INLINE effToReaderT #-} readerTToEff :: (Monad m, EffEnvironment e m) => ReaderT e m a -> m a readerTToEff m = ask >>= runReaderT m {-# INLINE readerTToEff#-}