effin-0.1.0.0: src/Control/Effect/Reader.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
#if MTL
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
#endif
module Control.Effect.Reader (
EffectReader, Reader, runReader,
ask, asks, local
) where
import Control.Monad.Effect
#ifdef MTL
import qualified Control.Monad.Reader.Class as R
instance EffectReader r es => R.MonadReader r (Effect es) where
ask = ask
local = local
reader = asks
#endif
-- | An effect that describes an implicit environment.
newtype Reader r a = Reader (r -> a)
deriving Functor
type EffectReader r es = (Member (Reader r) es, r ~ ReaderType es)
type family ReaderType es where
ReaderType (Reader r ': es) = r
ReaderType (e ': es) = ReaderType es
-- | Retrieves the current environment.
ask :: EffectReader r es => Effect es r
ask = asks id
-- | Retrieves a value that is a function of the current environment.
asks :: EffectReader r es => (r -> a) -> Effect es a
asks = send . Reader
-- | Runs a computation with a modified environment.
local :: EffectReader r es => (r -> r) -> Effect es a -> Effect es a
local f effect = do
env <- asks f
run env effect
where
run env =
handle return
$ intercept (bind env)
$ defaultRelay
-- | Completely handes a `Reader` effect by providing an
-- environment value to be used throughout the computation.
runReader :: r -> Effect (Reader r ': es) a -> Effect es a
runReader env =
handle return
$ eliminate (bind env)
$ defaultRelay
bind :: r -> Reader r (Effect es b) -> Effect es b
bind env (Reader k) = k env