-- | The dynamically dispatched variant of the 'Reader' effect.
--
-- /Note:/ unless you plan to change interpretations at runtime, it's
-- recommended to use the statically dispatched variant,
-- i.e. "Effectful.Reader.Static".
module Effectful.Reader.Dynamic
  ( -- * Effect
    Reader(..)

    -- ** Handlers
  , runReader
  , withReader

    -- ** Operations
  , ask
  , asks
  , local
  ) where

import Effectful
import Effectful.Dispatch.Dynamic

data Reader r :: Effect where
  Ask   :: Reader r m r
  Local :: (r -> r) -> m a -> Reader r m a

type instance DispatchOf (Reader r) = Dynamic

-- | Run the 'Reader' effect with the given initial environment.
runReader
  :: HasCallStack
  => r -- ^ The initial environment.
  -> Eff (Reader r : es) a
  -> Eff es a
runReader :: forall r (es :: [(Type -> Type) -> Type -> Type]) a.
HasCallStack =>
r -> Eff (Reader r : es) a -> Eff es a
runReader r
r0 = EffectHandler (Reader r) es -> Eff (Reader r : es) a -> Eff es a
forall (e :: (Type -> Type) -> Type -> Type)
       (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
EffectHandler e es -> Eff (e : es) a -> Eff es a
interpret (EffectHandler (Reader r) es -> Eff (Reader r : es) a -> Eff es a)
-> EffectHandler (Reader r) es -> Eff (Reader r : es) a -> Eff es a
forall a b. (a -> b) -> a -> b
$ r -> EffectHandler (Reader r) es
forall r (es :: [(Type -> Type) -> Type -> Type]).
r -> EffectHandler (Reader r) es
handler r
r0
  where
    handler :: r -> EffectHandler (Reader r) es
    handler :: forall r (es :: [(Type -> Type) -> Type -> Type]).
r -> EffectHandler (Reader r) es
handler r
r LocalEnv localEs es
env = \case
      Reader r (Eff localEs) a
Ask -> a -> Eff es a
forall a. a -> Eff es a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure r
a
r
      Local r -> r
f Eff localEs a
action -> LocalEnv localEs es
-> ((forall {r}. Eff localEs r -> Eff es r) -> Eff es a)
-> Eff es a
forall (es :: [(Type -> Type) -> Type -> Type])
       (handlerEs :: [(Type -> Type) -> Type -> Type])
       (localEs :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> ((forall r. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a
localSeqUnlift LocalEnv localEs es
env (((forall {r}. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a)
-> ((forall {r}. Eff localEs r -> Eff es r) -> Eff es a)
-> Eff es a
forall a b. (a -> b) -> a -> b
$ \forall {r}. Eff localEs r -> Eff es r
unlift -> do
        Eff localEs a -> Eff es a
forall {r}. Eff localEs r -> Eff es r
unlift (Eff localEs a -> Eff es a) -> Eff localEs a -> Eff es a
forall a b. (a -> b) -> a -> b
$ EffectHandler (Reader r) localEs -> Eff localEs a -> Eff localEs a
forall (e :: (Type -> Type) -> Type -> Type)
       (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
EffectHandler e es -> Eff es a -> Eff es a
interpose (r -> EffectHandler (Reader r) localEs
forall r (es :: [(Type -> Type) -> Type -> Type]).
r -> EffectHandler (Reader r) es
handler (r -> EffectHandler (Reader r) localEs)
-> r -> EffectHandler (Reader r) localEs
forall a b. (a -> b) -> a -> b
$ r -> r
f r
r) Eff localEs a
action

-- | Execute a computation in a modified environment.
--
-- @since 1.1.0.0
withReader
  :: HasCallStack
  => (r1 -> r2)
  -- ^ The function to modify the environment.
  -> Eff (Reader r2 : es) a
  -- ^ Computation to run in the modified environment.
  -> Eff (Reader r1 : es) a
withReader :: forall r1 r2 (es :: [(Type -> Type) -> Type -> Type]) a.
HasCallStack =>
(r1 -> r2) -> Eff (Reader r2 : es) a -> Eff (Reader r1 : es) a
withReader r1 -> r2
f Eff (Reader r2 : es) a
m = do
  r1
r <- Eff (Reader r1 : es) r1
forall r (es :: [(Type -> Type) -> Type -> Type]).
(HasCallStack, Reader r :> es) =>
Eff es r
ask
  Eff es a -> Eff (Reader r1 : es) a
forall (e :: (Type -> Type) -> Type -> Type)
       (es :: [(Type -> Type) -> Type -> Type]) a.
Eff es a -> Eff (e : es) a
raise (Eff es a -> Eff (Reader r1 : es) a)
-> Eff es a -> Eff (Reader r1 : es) a
forall a b. (a -> b) -> a -> b
$ r2 -> Eff (Reader r2 : es) a -> Eff es a
forall r (es :: [(Type -> Type) -> Type -> Type]) a.
HasCallStack =>
r -> Eff (Reader r : es) a -> Eff es a
runReader (r1 -> r2
f r1
r) Eff (Reader r2 : es) a
m
{-# DEPRECATED withReader "withReader doesn't work correctly for all potential interpreters" #-}

----------------------------------------
-- Operations

-- | Fetch the value of the environment.
ask :: (HasCallStack, Reader r :> es) => Eff es r
ask :: forall r (es :: [(Type -> Type) -> Type -> Type]).
(HasCallStack, Reader r :> es) =>
Eff es r
ask = Reader r (Eff es) r -> Eff es r
forall (e :: (Type -> Type) -> Type -> Type)
       (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send Reader r (Eff es) r
forall r (m :: Type -> Type). Reader r m r
Ask

-- | Retrieve a function of the current environment.
--
-- @'asks' f ≡ f '<$>' 'ask'@
asks
  :: (HasCallStack, Reader r :> es)
  => (r -> a) -- ^ The function to apply to the environment.
  -> Eff es a
asks :: forall r (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, Reader r :> es) =>
(r -> a) -> Eff es a
asks r -> a
f = r -> a
f (r -> a) -> Eff es r -> Eff es a
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Eff es r
forall r (es :: [(Type -> Type) -> Type -> Type]).
(HasCallStack, Reader r :> es) =>
Eff es r
ask

-- | Execute a computation in a modified environment.
--
-- @'runReader' r ('local' f m) ≡ 'runReader' (f r) m@
--
local
  :: (HasCallStack, Reader r :> es)
  => (r -> r) -- ^ The function to modify the environment.
  -> Eff es a
  -> Eff es a
local :: forall r (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, Reader r :> es) =>
(r -> r) -> Eff es a -> Eff es a
local r -> r
f = Reader r (Eff es) a -> Eff es a
forall (e :: (Type -> Type) -> Type -> Type)
       (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
e (Eff es) a -> Eff es a
send (Reader r (Eff es) a -> Eff es a)
-> (Eff es a -> Reader r (Eff es) a) -> Eff es a -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (r -> r) -> Eff es a -> Reader r (Eff es) a
forall r (m :: Type -> Type) a. (r -> r) -> m a -> Reader r m a
Local r -> r
f