-- | The dynamically dispatched variant of the 'ReturnWith' effect.
--
-- /Note:/ unless you plan to change interpretations at runtime, it's
-- recommended to use the statically dispatched variant,
-- i.e. "Effectful.ReturnWith.Static".
--
-- All caveats described in "Effectful.ReturnWith.Static" (in particular the
-- interaction with threads) apply.
--
-- @since 2.7.0.0
module Effectful.ReturnWith.Dynamic
  ( -- * Effect
    ReturnWith(..)

    -- ** Handlers
  , runReturnWith

    -- ** Operations
  , returnWith
  ) where

import GHC.Stack (withFrozenCallStack)

import Effectful
import Effectful.Dispatch.Dynamic
import Effectful.ReturnWith.Static qualified as R

-- | Provide the ability to return early with a value of type @r@.
data ReturnWith r :: Effect where
  ReturnWith :: r -> ReturnWith r m a

type instance DispatchOf (ReturnWith r) = Dynamic

-- | Run a computation that can return early with a value of type @r@ (via
-- "Effectful.ReturnWith.Static").
runReturnWith
  :: HasCallStack
  => Eff (ReturnWith r : es) r
  -> Eff es r
runReturnWith :: forall r (es :: [(Type -> Type) -> Type -> Type]).
HasCallStack =>
Eff (ReturnWith r : es) r -> Eff es r
runReturnWith = (Eff (ReturnWith r : es) r -> Eff es r)
-> (forall {a} {localEs :: [(Type -> Type) -> Type -> Type]}.
    HasCallStack =>
    ReturnWith r (Eff localEs) a -> Eff (ReturnWith r : es) a)
-> Eff (ReturnWith r : es) r
-> Eff es r
forall (e :: (Type -> Type) -> Type -> Type)
       (handlerEs :: [(Type -> Type) -> Type -> Type]) a
       (es :: [(Type -> Type) -> Type -> Type]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler_ e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret_ Eff (ReturnWith r : es) r -> Eff es r
forall r (es :: [(Type -> Type) -> Type -> Type]).
HasCallStack =>
Eff (ReturnWith r : es) r -> Eff es r
R.runReturnWith ((forall {a} {localEs :: [(Type -> Type) -> Type -> Type]}.
  HasCallStack =>
  ReturnWith r (Eff localEs) a -> Eff (ReturnWith r : es) a)
 -> Eff (ReturnWith r : es) r -> Eff es r)
-> (forall {a} {localEs :: [(Type -> Type) -> Type -> Type]}.
    HasCallStack =>
    ReturnWith r (Eff localEs) a -> Eff (ReturnWith r : es) a)
-> Eff (ReturnWith r : es) r
-> Eff es r
forall a b. (a -> b) -> a -> b
$ \case
  ReturnWith r
r -> r -> Eff (ReturnWith r : es) a
forall r (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, ReturnWith r :> es) =>
r -> Eff es a
R.returnWith r
r

-- | Return early with the given value.
returnWith
  :: (HasCallStack, ReturnWith r :> es)
  => r
  -- ^ The value.
  -> Eff es a
returnWith :: forall r (es :: [(Type -> Type) -> Type -> Type]) a.
(HasCallStack, ReturnWith r :> es) =>
r -> Eff es a
returnWith = (HasCallStack => ReturnWith r (Eff es) a -> Eff es a)
-> ReturnWith r (Eff es) a -> Eff es a
forall a. HasCallStack => (HasCallStack => a) -> a
withFrozenCallStack HasCallStack => ReturnWith r (Eff es) a -> Eff es a
ReturnWith 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 (ReturnWith r (Eff es) a -> Eff es a)
-> (r -> ReturnWith r (Eff es) a) -> r -> Eff es a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. r -> ReturnWith r (Eff es) a
forall r (m :: Type -> Type) a. r -> ReturnWith r m a
ReturnWith