{-# LANGUAGE ScopedTypeVariables, TypeFamilies, FlexibleContexts #-}
{-# LANGUAGE DataKinds, GADTs #-}
{-# LANGUAGE DeriveGeneric #-}
-- | The regular old 'MonadReader' effect with some differences. First, there's no functional
--   dependency limiting your stack to a single environment type. This means less type inference so
--   it might not be enough to just write 'readEnv'. Write 'readEnv @MyEnvType' instead using
--   TypeApplications.
--
--   Second, the function has a less generic name and is called 'readEnv'.
--
--   Third, since it's a part of this effect framework, you get a 'implementReadEnv' function with
--   which you can provide a different environment implementation _at runtime_.
module Control.Effects.Reader (module Control.Effects.Reader, module Control.Effects) where

import Control.Effects
import GHC.Generics

newtype ReadEnv e m = ReadEnvMethods
    { _readEnv :: m e }
    deriving (Generic)
instance Effect (ReadEnv e)

-- | Read a value of type 'e'. Use with the TypeApplications extension to
--   help with type inference
--   @readEnv \@Int@
readEnv :: forall e m. MonadEffect (ReadEnv e) m => m e
readEnv = _readEnv effect

-- | Use the given action in the underlying monad to provide environment
--   values. You can think of @implementReadEnv x m@ as replacing all 'readEnv' calls
--   in 'm' with 'x'.
implementReadEnv :: Functor m => m e -> RuntimeImplemented (ReadEnv e) m a -> m a
implementReadEnv m = implement (ReadEnvMethods m)