{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Dynamically dispatched effects.
module Effectful.Dispatch.Dynamic
  ( -- * Introduction
    -- $intro

    -- ** An example
    -- $example

    -- ** First order and higher order effects
    -- $order

    -- ** Integration with @mtl@ style effects
    -- $integration

    -- *** Functional dependencies
    -- $mtl-fundeps

    -- * Sending operations to the handler
    send

    -- * Handling effects
  , EffectHandler
  , interpret
  , interpretWith
  , reinterpret
  , reinterpretWith
  , interpose
  , interposeWith
  , impose
  , imposeWith

    -- ** Handling local 'Eff' computations
  , LocalEnv

    -- *** Unlifts
  , localSeqUnlift
  , localSeqUnliftIO
  , localUnlift
  , localUnliftIO

    -- *** Lifts
  , localSeqLift
  , localLift
  , withLiftMap
  , withLiftMapIO

    -- *** Bidirectional lifts
  , localLiftUnlift
  , localLiftUnliftIO

    -- *** Misc
  , localSeqLend
  , localLend
  , localSeqBorrow
  , localBorrow
  , SharedSuffix
  , KnownSubset

    -- ** Utils for first order effects
  , EffectHandler_
  , interpret_
  , interpretWith_
  , reinterpret_
  , reinterpretWith_
  , interpose_
  , interposeWith_
  , impose_
  , imposeWith_

    -- * Re-exports
  , HasCallStack
  ) where

import Data.Primitive.PrimArray
import GHC.Stack (HasCallStack)
import GHC.TypeLits

import Effectful.Internal.Effect
import Effectful.Internal.Env
import Effectful.Internal.Monad
import Effectful.Internal.Utils

-- $intro
--
-- A dynamically dispatched effect is a collection of operations that can be
-- interpreted in different ways at runtime, depending on the handler that is
-- used to run the effect.
--
-- This allows a programmer to separate the __what__ from the __how__,
-- i.e. define effects that model what the code should do, while providing
-- handlers that determine how it should do it later. Moreover, different
-- environments can use different handlers to change the behavior of specific
-- parts of the application if appropriate.
--

-- $example
--
-- Let's create an effect for basic file access, i.e. writing and reading files.
--
-- First, we need to define a generalized algebraic data type of kind 'Effect',
-- where each constructor corresponds to a specific operation of the effect in
-- question.
--
-- >>> :{
--   data FileSystem :: Effect where
--     ReadFile  :: FilePath -> FileSystem m String
--     WriteFile :: FilePath -> String -> FileSystem m ()
-- :}
--
-- >>> type instance DispatchOf FileSystem = Dynamic
--
-- The @FileSystem@ effect has two operations:
--
-- - @ReadFile@, which takes a @FilePath@ and returns a @String@ in the monadic
--   context.
--
-- - @WriteFile@, which takes a @FilePath@, a @String@ and returns a @()@ in the
--   monadic context.
--
-- For people familiar with @mtl@ style effects, note that the syntax looks very
-- similar to defining an appropriate type class:
--
-- @
-- class FileSystem m where
--   readFile  :: FilePath -> m String
--   writeFile :: FilePath -> String -> m ()
-- @
--
-- The biggest difference between these two is that the definition of a type
-- class gives us operations as functions, while the definition of an effect
-- gives us operations as data constructors. They can be turned into functions
-- with the help of 'send':
--
-- >>> :{
--   readFile :: (HasCallStack, FileSystem :> es) => FilePath -> Eff es String
--   readFile path = send (ReadFile path)
-- :}
--
-- >>> :{
--   writeFile :: (HasCallStack, FileSystem :> es) => FilePath -> String -> Eff es ()
--   writeFile path content = send (WriteFile path content)
-- :}
--
-- /Note:/ the above functions and the 'DispatchOf' instance can also be
-- automatically generated by the
-- [@makeEffect@](https://hackage.haskell.org/package/effectful-th/docs/Effectful-TH.html#v:makeEffect)
-- function from the
-- [effectful-th](https://hackage.haskell.org/package/effectful-th) package.
--
-- The following defines an 'EffectHandler' that reads and writes files from the
-- drive:
--
-- >>> import Effectful.Error.Static
-- >>> import Effectful.Exception
-- >>> import System.IO qualified as IO
--
-- >>> newtype FsError = FsError String deriving Show
--
-- >>> :{
--  runFileSystemIO
--    :: (IOE :> es, Error FsError :> es)
--    => Eff (FileSystem : es) a
--    -> Eff es a
--  runFileSystemIO = interpret $ \_ -> \case
--    ReadFile path           -> adapt $ IO.readFile path
--    WriteFile path contents -> adapt $ IO.writeFile path contents
--    where
--      adapt m = liftIO m `catchIO` \e -> throwError . FsError $ show e
-- :}
--
-- Here, we use 'interpret' and simply execute corresponding 'IO' actions for
-- each operation, additionally doing a bit of error management.
--
-- On the other hand, maybe there is a situation in which instead of interacting
-- with the outside world, a pure, in-memory storage is preferred:
--
-- >>> import Data.Map.Strict qualified as M
-- >>> import Effectful.State.Static.Local
--
-- >>> :{
--   runFileSystemPure
--     :: Error FsError :> es
--     => M.Map FilePath String
--     -> Eff (FileSystem : es) a
--     -> Eff es a
--   runFileSystemPure fs0 = reinterpret (evalState fs0) $ \_ -> \case
--     ReadFile path -> gets (M.lookup path) >>= \case
--       Just contents -> pure contents
--       Nothing       -> throwError . FsError $ "File not found: " ++ show path
--     WriteFile path contents -> modify $ M.insert path contents
-- :}
--
-- Here, we use 'reinterpret' and introduce a
-- t'Effectful.State.Static.Local.State' effect for the storage that is private
-- to the effect handler and cannot be accessed outside of it.
--
-- Let's compare how these differ.
--
-- >>> :{
--   action = do
--     file <- readFile "effectful-core.cabal"
--     pure $ length file > 0
-- :}
--
-- >>> :t action
-- action :: (FileSystem :> es) => Eff es Bool
--
-- >>> runEff . runError @FsError . runFileSystemIO $ action
-- Right True
--
-- >>> runPureEff . runErrorNoCallStack @FsError . runFileSystemPure M.empty $ action
-- Left (FsError "File not found: \"effectful-core.cabal\"")
--

-- $order
--
-- Note that the definition of the @FileSystem@ effect from the previous section
-- doesn't use the @m@ type parameter. What is more, when the effect is
-- interpreted, the 'LocalEnv' argument of the 'EffectHandler' is also not
-- used. Such effects are /first order/.
--
-- If an effect makes use of the @m@ parameter, it is a /higher order effect/.
--
-- /Note:/ for handling first order effects you can use 'interpret_' or
-- 'reinterpret_' whose 'EffectHandler_' doesn't take the 'LocalEnv' parameter.
--
-- Interpretation of higher order effects is slightly more involving. To see
-- why, let's consider the @Profiling@ effect for logging how much time a
-- specific action took to run:
--
-- >>> :{
--   data Profiling :: Effect where
--     Profile :: String -> m a -> Profiling m a
-- :}
--
-- >>> type instance DispatchOf Profiling = Dynamic
--
-- >>> :{
--   profile :: (HasCallStack, Profiling :> es) => String -> Eff es a -> Eff es a
--   profile label action = send (Profile label action)
-- :}
--
-- If we naively try to interpret it, we will run into trouble:
--
-- >>> import GHC.Clock (getMonotonicTime)
--
-- >>> :{
--  runProfiling :: IOE :> es => Eff (Profiling : es) a -> Eff es a
--  runProfiling = interpret $ \_ -> \case
--    Profile label action -> do
--      t1 <- liftIO getMonotonicTime
--      r <- action
--      t2 <- liftIO getMonotonicTime
--      liftIO . putStrLn $ "Action '" ++ label ++ "' took " ++ show (t2 - t1) ++ " seconds."
--      pure r
-- :}
-- ...
-- ... Couldn't match type ‘localEs’ with ‘es’
-- ...
--
-- The problem is that @action@ has a type @Eff localEs a@, while the monad of
-- the effect handler is @Eff es@. @localEs@ represents the /local environment/
-- in which the @Profile@ operation was called, which is opaque as the effect
-- handler cannot possibly know how it looks like.
--
-- The solution is to use the 'LocalEnv' that an 'EffectHandler' is given to run
-- the action using one of the functions from the 'localUnlift' family:
--
-- >>> :{
--  runProfiling :: IOE :> es => Eff (Profiling : es) a -> Eff es a
--  runProfiling = interpret $ \env -> \case
--    Profile label action -> localSeqUnliftIO env $ \unlift -> do
--      t1 <- getMonotonicTime
--      r <- unlift action
--      t2 <- getMonotonicTime
--      putStrLn $ "Action '" ++ label ++ "' took " ++ show (t2 - t1) ++ " seconds."
--      pure r
-- :}
--
-- In a similar way we can define a dummy interpreter that does no profiling:
--
-- >>> :{
--  runNoProfiling :: Eff (Profiling : es) a -> Eff es a
--  runNoProfiling = interpret $ \env -> \case
--    Profile label action -> localSeqUnlift env $ \unlift -> unlift action
-- :}
--
-- ...and it's done.
--
-- >>> action = profile "greet" . liftIO $ putStrLn "Hello!"
--
-- >>> :t action
-- action :: (Profiling :> es, IOE :> es) => Eff es ()
--
-- >>> runEff . runProfiling $ action
-- Hello!
-- Action 'greet' took ... seconds.
--
-- >>> runEff . runNoProfiling $ action
-- Hello!
--

-- $integration
--
-- #integration#
--
-- There exists a lot of libraries that provide their functionality as an @mtl@
-- style effect, which generally speaking is a type class that contains core
-- operations of the library in question.
--
-- Such effects are quite easy to use with the 'Eff' monad. As an example,
-- consider the @mtl@ style effect for generation of random numbers:
--
-- >>> :{
--   class Monad m => MonadRNG m where
--     randomInt :: m Int
-- :}
--
-- Let's say the library also defines a helper function for generation of random
-- strings:
--
-- >>> import Control.Monad
-- >>> import Data.Char
--
-- >>> :{
--  randomString :: MonadRNG m => Int -> m String
--  randomString n = map chr <$> replicateM n randomInt
-- :}
--
-- To make it possible to use it with the 'Eff' monad, the first step is to
-- create an effect with operations that mirror the ones of a type class:
--
-- >>> :{
--   data RNG :: Effect where
--     RandomInt :: RNG m Int
-- :}
--
-- >>> type instance DispatchOf RNG = Dynamic
--
-- If we continued as in the example above, we'd now create top level helper
-- functions that execute effect operations using 'send', in this case
-- @randomInt@ tied to @RandomInt@. But this function is already declared by the
-- @MonadRNG@ type class! Therefore, what we do instead is provide an
-- __orphan__, __canonical__ instance of @MonadRNG@ for 'Eff' that delegates to
-- the @RNG@ effect:
--
-- >>> :set -XUndecidableInstances
--
-- >>> :{
--   instance RNG :> es => MonadRNG (Eff es) where
--     randomInt = send RandomInt
-- :}
--
-- Now we only need an interpreter:
--
-- >>> :{
--   runDummyRNG :: Eff (RNG : es) a -> Eff es a
--   runDummyRNG = interpret_ $ \case
--     RandomInt -> pure 55
-- :}
--
-- and we can use any function that requires a @MonadRNG@ constraint with the
-- 'Eff' monad as long as the @RNG@ effect is in place:
--
-- >>> runEff . runDummyRNG $ randomString 3
-- "777"
--

-- $mtl-fundeps
--
-- For dealing with classes that employ functional dependencies an additional
-- trick is needed.
--
-- Consider the following:
--
-- >>> :set -XFunctionalDependencies
--
-- >>> :{
--   class Monad m => MonadInput i m | m -> i where
--     input :: m i
-- :}
--
-- An attempt to define the instance as in the example above leads to violation
-- of the liberal coverage condition:
--
-- >>> :{
--   instance Reader i :> es => MonadInput i (Eff es) where
--     input = ask
-- :}
-- ...
-- ...Illegal instance declaration for ‘MonadInput i (Eff es)’...
-- ...  The liberal coverage condition fails in class ‘MonadInput’...
-- ...    for functional dependency: ‘m -> i’...
-- ...
--
-- However, there exists a trick for bypassing the coverage condition,
-- i.e. including the instance head in its context:
--
-- >>> :{
--   instance (MonadInput i (Eff es), Reader i :> es) => MonadInput i (Eff es) where
--     input = ask
-- :}
--
-- Now the @MonadInput@ class can be used with the 'Eff' monad:
--
-- >>> :{
--   double :: MonadInput Int m => m Int
--   double = (+) <$> input <*> input
-- :}
--
-- >>> runPureEff . runReader @Int 3 $ double
-- 6

----------------------------------------
-- Handling effects

-- | Interpret an effect.
--
-- /Note:/ 'interpret' can be turned into a 'reinterpret' with the use of
-- 'inject'.
interpret
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => EffectHandler e es
  -- ^ The effect handler.
  -> Eff (e : es) a
  -> Eff      es  a
interpret :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
EffectHandler e es -> Eff (e : es) a -> Eff es a
interpret EffectHandler e es
handler Eff (e : es) a
m = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ Handler e -> Eff (e : es) a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
Handler e -> Eff (e : es) a -> Eff es a
runHandler (Env es -> Handler e
mkHandler Env es
es) Eff (e : es) a
m
  where
    mkHandler :: Env es -> Handler e
mkHandler Env es
es = Env es -> EffectHandler e es -> Handler e
forall (handlerEs :: [Effect]) (a :: Effect).
Env handlerEs -> EffectHandler a handlerEs -> Handler a
Handler Env es
es (let ?callStack = CallStack -> CallStack
thawCallStack HasCallStack
CallStack
?callStack in LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
EffectHandler e es
handler)

-- | 'interpret' with the effect handler as the last argument.
--
-- @since 2.4.0.0
interpretWith
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => Eff (e : es) a
  -> EffectHandler e es
  -- ^ The effect handler.
  -> Eff      es  a
interpretWith :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
Eff (e : es) a -> EffectHandler e es -> Eff es a
interpretWith Eff (e : es) a
m EffectHandler e es
handler = EffectHandler e es -> Eff (e : es) a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
EffectHandler e es -> Eff (e : es) a -> Eff es a
interpret LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
EffectHandler e es
handler Eff (e : es) a
m

-- | Interpret an effect using other, private effects.
--
-- @'interpret' ≡ 'reinterpret' 'id'@
reinterpret
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> EffectHandler e handlerEs
  -- ^ The effect handler.
  -> Eff (e : es) a
  -> Eff      es  b
reinterpret :: forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret Eff handlerEs a -> Eff es b
runHandlerEs EffectHandler e handlerEs
handler Eff (e : es) a
m = (Env es -> IO b) -> Eff es b
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO b) -> Eff es b) -> (Env es -> IO b) -> Eff es b
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  (Eff es b -> Env es -> IO b
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es b -> IO b)
-> ((Env handlerEs -> IO a) -> Eff es b)
-> (Env handlerEs -> IO a)
-> IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff handlerEs a -> Eff es b
runHandlerEs (Eff handlerEs a -> Eff es b)
-> ((Env handlerEs -> IO a) -> Eff handlerEs a)
-> (Env handlerEs -> IO a)
-> Eff es b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Env handlerEs -> IO a) -> Eff handlerEs a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env handlerEs -> IO a) -> IO b)
-> (Env handlerEs -> IO a) -> IO b
forall a b. (a -> b) -> a -> b
$ \Env handlerEs
handlerEs -> do
    (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ Handler e -> Eff (e : es) a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
Handler e -> Eff (e : es) a -> Eff es a
runHandler (Env handlerEs -> Handler e
mkHandler Env handlerEs
handlerEs) Eff (e : es) a
m
  where
    mkHandler :: Env handlerEs -> Handler e
mkHandler Env handlerEs
es = Env handlerEs -> EffectHandler e handlerEs -> Handler e
forall (handlerEs :: [Effect]) (a :: Effect).
Env handlerEs -> EffectHandler a handlerEs -> Handler a
Handler Env handlerEs
es (let ?callStack = CallStack -> CallStack
thawCallStack HasCallStack
CallStack
?callStack in LocalEnv localEs handlerEs -> e (Eff localEs) a -> Eff handlerEs a
EffectHandler e handlerEs
handler)

-- | 'reinterpret' with the effect handler as the last argument.
--
-- @since 2.4.0.0
reinterpretWith
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> Eff (e : es) a
  -> EffectHandler e handlerEs
  -- ^ The effect handler.
  -> Eff      es  b
reinterpretWith :: forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> Eff (e : es) a -> EffectHandler e handlerEs -> Eff es b
reinterpretWith Eff handlerEs a -> Eff es b
runHandlerEs Eff (e : es) a
m EffectHandler e handlerEs
handler = (Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret Eff handlerEs a -> Eff es b
runHandlerEs LocalEnv localEs handlerEs -> e (Eff localEs) a -> Eff handlerEs a
EffectHandler e handlerEs
handler Eff (e : es) a
m

-- | Replace the handler of an existing effect with a new one.
--
-- /Note:/ this function allows for augmenting handlers with a new functionality
-- as the new handler can send operations to the old one.
--
-- >>> :{
--   data E :: Effect where
--     Op1 :: E m ()
--     Op2 :: E m ()
--   type instance DispatchOf E = Dynamic
-- :}
--
-- >>> :{
--   runE :: IOE :> es => Eff (E : es) a -> Eff es a
--   runE = interpret_ $ \case
--     Op1 -> liftIO (putStrLn "op1")
--     Op2 -> liftIO (putStrLn "op2")
-- :}
--
-- >>> runEff . runE $ send Op1 >> send Op2
-- op1
-- op2
--
-- >>> :{
--   augmentOp2 :: (E :> es, IOE :> es) => Eff es a -> Eff es a
--   augmentOp2 = interpose_ $ \case
--     Op1 -> send Op1
--     Op2 -> liftIO (putStrLn "augmented op2") >> send Op2
-- :}
--
-- >>> runEff . runE . augmentOp2 $ send Op1 >> send Op2
-- op1
-- augmented op2
-- op2
--
-- /Note:/ when using 'interpose' to modify only specific operations of the
-- effect, your first instinct might be to match on them, then handle the rest
-- with a generic match. Unfortunately, this doesn't work out of the box:
--
-- >>> :{
--   genericAugmentOp2 :: (E :> es, IOE :> es) => Eff es a -> Eff es a
--   genericAugmentOp2 = interpose_ $ \case
--     Op2 -> liftIO (putStrLn "augmented op2") >> send Op2
--     op  -> send op
-- :}
-- ...
-- ...Couldn't match type ‘localEs’ with ‘es’
-- ...
--
-- This is because within the generic match, 'send' expects @Op (Eff es) a@, but
-- @op@ has a type @Op (Eff localEs) a@. If the effect in question is first
-- order (i.e. its @m@ type parameter is phantom), you can use 'coerce':
--
-- >>> import Data.Coerce
-- >>> :{
--   genericAugmentOp2 :: (E :> es, IOE :> es) => Eff es a -> Eff es a
--   genericAugmentOp2 = interpose_ $ \case
--     Op2 -> liftIO (putStrLn "augmented op2") >> send Op2
--     op  -> send @E (coerce op)
-- :}
--
-- >>> runEff . runE . genericAugmentOp2 $ send Op1 >> send Op2
-- op1
-- augmented op2
-- op2
--
-- On the other hand, when dealing with higher order effects you need to pattern
-- match on each operation and unlift where necessary.
--
interpose
  :: forall e es a. (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => EffectHandler e es
  -- ^ The effect handler.
  -> Eff es a
  -> Eff es a
interpose :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
EffectHandler e es -> Eff es a -> Eff es a
interpose EffectHandler e es
handler Eff es a
m = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  IO (Env es) -> (Env es -> IO ()) -> (Env es -> IO a) -> IO a
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
inlineBracket
    (do
        Handler e
origHandler <- forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> IO (EffectRep (DispatchOf e) e)
getEnv @e Env es
es
        EffectRep (DispatchOf e) e
-> Relinker (EffectRep (DispatchOf e)) e -> Env es -> IO (Env es)
forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
EffectRep (DispatchOf e) e
-> Relinker (EffectRep (DispatchOf e)) e -> Env es -> IO (Env es)
replaceEnv EffectRep (DispatchOf e) e
Handler e
origHandler Relinker (EffectRep (DispatchOf e)) e
Relinker Handler e
forall (e :: Effect). Relinker Handler e
relinkHandler Env es
es
    )
    (\Env es
newEs -> do
        -- Restore the original handler.
        Env es -> EffectRep (DispatchOf e) e -> IO ()
forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> EffectRep (DispatchOf e) e -> IO ()
putEnv Env es
es (EffectRep (DispatchOf e) e -> IO ())
-> IO (EffectRep (DispatchOf e) e) -> IO ()
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> IO (EffectRep (DispatchOf e) e)
getEnv @e Env es
newEs
        forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> IO ()
unreplaceEnv @e Env es
newEs
    )
    (\Env es
newEs -> do
        -- Replace the original handler with a new one. Note that 'newEs'
        -- will still see the original handler.
        Env es -> EffectRep (DispatchOf e) e -> IO ()
forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> EffectRep (DispatchOf e) e -> IO ()
putEnv Env es
es (EffectRep (DispatchOf e) e -> IO ())
-> EffectRep (DispatchOf e) e -> IO ()
forall a b. (a -> b) -> a -> b
$ Env es -> Handler e
mkHandler Env es
newEs
        Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
unEff Eff es a
m Env es
es
    )
  where
    mkHandler :: Env es -> Handler e
mkHandler Env es
es = Env es -> EffectHandler e es -> Handler e
forall (handlerEs :: [Effect]) (a :: Effect).
Env handlerEs -> EffectHandler a handlerEs -> Handler a
Handler Env es
es (let ?callStack = CallStack -> CallStack
thawCallStack HasCallStack
CallStack
?callStack in LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
EffectHandler e es
handler)

-- | 'interpose' with the effect handler as the last argument.
--
-- @since 2.4.0.0
interposeWith
  :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => Eff es a
  -> EffectHandler e es
  -- ^ The effect handler.
  -> Eff es a
interposeWith :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
Eff es a -> EffectHandler e es -> Eff es a
interposeWith Eff es a
m EffectHandler e es
handler = EffectHandler e es -> Eff es a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
EffectHandler e es -> Eff es a -> Eff es a
interpose LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
EffectHandler e es
handler Eff es a
m

-- | Replace the handler of an existing effect with a new one that uses other,
-- private effects.
--
-- @'interpose' ≡ 'impose' 'id'@
impose
  :: forall e es handlerEs a b. (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> EffectHandler e handlerEs
  -- ^ The effect handler.
  -> Eff es a
  -> Eff es b
impose :: forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
impose Eff handlerEs a -> Eff es b
runHandlerEs EffectHandler e handlerEs
handler Eff es a
m = (Env es -> IO b) -> Eff es b
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO b) -> Eff es b) -> (Env es -> IO b) -> Eff es b
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  IO (Env es) -> (Env es -> IO ()) -> (Env es -> IO b) -> IO b
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
inlineBracket
    (do
        Handler e
origHandler <- forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> IO (EffectRep (DispatchOf e) e)
getEnv @e Env es
es
        EffectRep (DispatchOf e) e
-> Relinker (EffectRep (DispatchOf e)) e -> Env es -> IO (Env es)
forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
EffectRep (DispatchOf e) e
-> Relinker (EffectRep (DispatchOf e)) e -> Env es -> IO (Env es)
replaceEnv EffectRep (DispatchOf e) e
Handler e
origHandler Relinker (EffectRep (DispatchOf e)) e
Relinker Handler e
forall (e :: Effect). Relinker Handler e
relinkHandler Env es
es
    )
    (\Env es
newEs -> do
        -- Restore the original handler.
        Env es -> EffectRep (DispatchOf e) e -> IO ()
forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> EffectRep (DispatchOf e) e -> IO ()
putEnv Env es
es (EffectRep (DispatchOf e) e -> IO ())
-> IO (EffectRep (DispatchOf e) e) -> IO ()
forall (m :: Type -> Type) a b. Monad m => (a -> m b) -> m a -> m b
=<< forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> IO (EffectRep (DispatchOf e) e)
getEnv @e Env es
newEs
        forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> IO ()
unreplaceEnv @e Env es
newEs
    )
    (\Env es
newEs -> do
        (Eff es b -> Env es -> IO b
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
newEs) (Eff es b -> IO b)
-> ((Env handlerEs -> IO a) -> Eff es b)
-> (Env handlerEs -> IO a)
-> IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff handlerEs a -> Eff es b
runHandlerEs (Eff handlerEs a -> Eff es b)
-> ((Env handlerEs -> IO a) -> Eff handlerEs a)
-> (Env handlerEs -> IO a)
-> Eff es b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Env handlerEs -> IO a) -> Eff handlerEs a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env handlerEs -> IO a) -> IO b)
-> (Env handlerEs -> IO a) -> IO b
forall a b. (a -> b) -> a -> b
$ \Env handlerEs
handlerEs -> do
          -- Replace the original handler with a new one. Note that
          -- 'newEs' (and thus 'handlerEs') wil still see the original
          -- handler.
          Env es -> EffectRep (DispatchOf e) e -> IO ()
forall (e :: Effect) (es :: [Effect]).
(HasCallStack, e :> es) =>
Env es -> EffectRep (DispatchOf e) e -> IO ()
putEnv Env es
es (EffectRep (DispatchOf e) e -> IO ())
-> EffectRep (DispatchOf e) e -> IO ()
forall a b. (a -> b) -> a -> b
$ Env handlerEs -> Handler e
mkHandler Env handlerEs
handlerEs
          Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
unEff Eff es a
m Env es
es
    )
  where
    mkHandler :: Env handlerEs -> Handler e
mkHandler Env handlerEs
es = Env handlerEs -> EffectHandler e handlerEs -> Handler e
forall (handlerEs :: [Effect]) (a :: Effect).
Env handlerEs -> EffectHandler a handlerEs -> Handler a
Handler Env handlerEs
es (let ?callStack = CallStack -> CallStack
thawCallStack HasCallStack
CallStack
?callStack in LocalEnv localEs handlerEs -> e (Eff localEs) a -> Eff handlerEs a
EffectHandler e handlerEs
handler)

-- | 'impose' with the effect handler as the last argument.
--
-- @since 2.4.0.0
imposeWith
  :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> Eff es a
  -> EffectHandler e handlerEs
  -- ^ The effect handler.
  -> Eff es b
imposeWith :: forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> Eff es a -> EffectHandler e handlerEs -> Eff es b
imposeWith Eff handlerEs a -> Eff es b
runHandlerEs Eff es a
m EffectHandler e handlerEs
handler = (Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
impose Eff handlerEs a -> Eff es b
runHandlerEs LocalEnv localEs handlerEs -> e (Eff localEs) a -> Eff handlerEs a
EffectHandler e handlerEs
handler Eff es a
m

----------------------------------------
-- First order effects

-- | Type signature of a first order effect handler.
--
-- @since 2.4.0.0
type EffectHandler_ (e :: Effect) (es :: [Effect])
  = forall a localEs. HasCallStack
  => e (Eff localEs) a
  -- ^ The operation.
  -> Eff es a

-- | 'interpret' for first order effects.
--
-- @since 2.4.0.0
interpret_
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => EffectHandler_ e es
  -- ^ The effect handler.
  -> Eff (e : es) a
  -> Eff      es  a
interpret_ :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
EffectHandler_ e es -> Eff (e : es) a -> Eff es a
interpret_ EffectHandler_ e es
handler = EffectHandler e es -> Eff (e : es) a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
EffectHandler e es -> Eff (e : es) a -> Eff es a
interpret ((e (Eff localEs) a -> Eff es a)
-> LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff es a
EffectHandler_ e es
handler)

-- | 'interpretWith' for first order effects.
--
-- @since 2.4.0.0
interpretWith_
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => Eff (e : es) a
  -> EffectHandler_ e es
  -- ^ The effect handler.
  -> Eff      es  a
interpretWith_ :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
Eff (e : es) a -> EffectHandler_ e es -> Eff es a
interpretWith_ Eff (e : es) a
m EffectHandler_ e es
handler = EffectHandler e es -> Eff (e : es) a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
EffectHandler e es -> Eff (e : es) a -> Eff es a
interpret ((e (Eff localEs) a -> Eff es a)
-> LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff es a
EffectHandler_ e es
handler) Eff (e : es) a
m

-- | 'reinterpret' for first order effects.
--
-- @since 2.4.0.0
reinterpret_
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> EffectHandler_ e handlerEs
  -- ^ The effect handler.
  -> Eff (e : es) a
  -> Eff      es  b
reinterpret_ :: forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler_ e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret_ Eff handlerEs a -> Eff es b
runHandlerEs EffectHandler_ e handlerEs
handler = (Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret Eff handlerEs a -> Eff es b
runHandlerEs ((e (Eff localEs) a -> Eff handlerEs a)
-> LocalEnv localEs handlerEs
-> e (Eff localEs) a
-> Eff handlerEs a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff handlerEs a
EffectHandler_ e handlerEs
handler)

-- | 'reinterpretWith' for first order effects.
--
-- @since 2.4.0.0
reinterpretWith_
  :: (HasCallStack, DispatchOf e ~ Dynamic)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> Eff (e : es) a
  -> EffectHandler_ e handlerEs
  -- ^ The effect handler.
  -> Eff      es  b
reinterpretWith_ :: forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> Eff (e : es) a -> EffectHandler_ e handlerEs -> Eff es b
reinterpretWith_ Eff handlerEs a -> Eff es b
runHandlerEs Eff (e : es) a
m EffectHandler_ e handlerEs
handler = (Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
forall (e :: Effect) (handlerEs :: [Effect]) a (es :: [Effect]) b.
(HasCallStack, DispatchOf e ~ 'Dynamic) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff (e : es) a -> Eff es b
reinterpret Eff handlerEs a -> Eff es b
runHandlerEs ((e (Eff localEs) a -> Eff handlerEs a)
-> LocalEnv localEs handlerEs
-> e (Eff localEs) a
-> Eff handlerEs a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff handlerEs a
EffectHandler_ e handlerEs
handler) Eff (e : es) a
m

-- | 'interpose' for first order effects.
--
-- @since 2.4.0.0
interpose_
  :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => EffectHandler_ e es
  -- ^ The effect handler.
  -> Eff es a
  -> Eff es a
interpose_ :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
EffectHandler_ e es -> Eff es a -> Eff es a
interpose_ EffectHandler_ e es
handler = EffectHandler e es -> Eff es a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
EffectHandler e es -> Eff es a -> Eff es a
interpose ((e (Eff localEs) a -> Eff es a)
-> LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff es a
EffectHandler_ e es
handler)

-- | 'interposeWith' for first order effects.
--
-- @since 2.4.0.0
interposeWith_
  :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => Eff es a
  -> EffectHandler_ e es
  -- ^ The effect handler.
  -> Eff es a
interposeWith_ :: forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
Eff es a -> EffectHandler_ e es -> Eff es a
interposeWith_ Eff es a
m EffectHandler_ e es
handler = EffectHandler e es -> Eff es a -> Eff es a
forall (e :: Effect) (es :: [Effect]) a.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
EffectHandler e es -> Eff es a -> Eff es a
interpose ((e (Eff localEs) a -> Eff es a)
-> LocalEnv localEs es -> e (Eff localEs) a -> Eff es a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff es a
EffectHandler_ e es
handler) Eff es a
m

-- | 'impose' for first order effects.
--
-- @since 2.4.0.0
impose_
  :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> EffectHandler_ e handlerEs
  -- ^ The effect handler.
  -> Eff es a
  -> Eff es b
impose_ :: forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler_ e handlerEs -> Eff es a -> Eff es b
impose_ Eff handlerEs a -> Eff es b
runHandlerEs EffectHandler_ e handlerEs
handler = (Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
impose Eff handlerEs a -> Eff es b
runHandlerEs ((e (Eff localEs) a -> Eff handlerEs a)
-> LocalEnv localEs handlerEs
-> e (Eff localEs) a
-> Eff handlerEs a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff handlerEs a
EffectHandler_ e handlerEs
handler)

-- | 'imposeWith' for first order effects.
--
-- @since 2.4.0.0
imposeWith_
  :: (HasCallStack, DispatchOf e ~ Dynamic, e :> es)
  => (Eff handlerEs a -> Eff es b)
  -- ^ Introduction of effects encapsulated within the handler.
  -> Eff es a
  -> EffectHandler_ e handlerEs
  -- ^ The effect handler.
  -> Eff es b
imposeWith_ :: forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> Eff es a -> EffectHandler_ e handlerEs -> Eff es b
imposeWith_ Eff handlerEs a -> Eff es b
runHandlerEs Eff es a
m EffectHandler_ e handlerEs
handler = (Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
forall (e :: Effect) (es :: [Effect]) (handlerEs :: [Effect]) a b.
(HasCallStack, DispatchOf e ~ 'Dynamic, e :> es) =>
(Eff handlerEs a -> Eff es b)
-> EffectHandler e handlerEs -> Eff es a -> Eff es b
impose Eff handlerEs a -> Eff es b
runHandlerEs ((e (Eff localEs) a -> Eff handlerEs a)
-> LocalEnv localEs handlerEs
-> e (Eff localEs) a
-> Eff handlerEs a
forall a b. a -> b -> a
const e (Eff localEs) a -> Eff handlerEs a
EffectHandler_ e handlerEs
handler) Eff es a
m

----------------------------------------
-- Unlifts

-- | Create a local unlifting function with the 'SeqUnlift' strategy. For the
-- general version see 'localUnlift'.
localSeqUnlift
  :: (HasCallStack, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
  -- ^ Continuation with the unlifting function in scope.
  -> Eff es a
localSeqUnlift :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> ((forall r. Eff localEs r -> Eff es r) -> Eff es a) -> Eff es a
localSeqUnlift (LocalEnv Env localEs
les) (forall r. Eff localEs r -> Eff es r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unlift -> do
    (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff localEs r -> Eff es r) -> Eff es a
k ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unlift
{-# INLINE localSeqUnlift #-}

-- | Create a local unlifting function with the 'SeqUnlift' strategy. For the
-- general version see 'localUnliftIO'.
localSeqUnliftIO
  :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> ((forall r. Eff localEs r -> IO r) -> IO a)
  -- ^ Continuation with the unlifting function in scope.
  -> Eff es a
localSeqUnliftIO :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs, IOE :> es) =>
LocalEnv localEs handlerEs
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> Eff es a
localSeqUnliftIO (LocalEnv Env localEs
les) (forall r. Eff localEs r -> IO r) -> IO a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
les (forall r. Eff localEs r -> IO r) -> IO a
k
{-# INLINE localSeqUnliftIO #-}

-- | Create a local unlifting function with the given strategy.
localUnlift
  :: (HasCallStack, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> UnliftStrategy
  -> ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
  -- ^ Continuation with the unlifting function in scope.
  -> Eff es a
localUnlift :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
-> Eff es a
localUnlift (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. Eff localEs r -> Eff es r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift -> Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff localEs r -> Eff es r) -> Eff es a
k ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unlift
    UnliftStrategy
SeqForkUnlift -> Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff localEs r -> Eff es r) -> Eff es a
k ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unlift
    ConcUnlift Persistence
p Limit
l -> Env localEs
-> Persistence
-> Limit
-> ((forall r. Eff localEs r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env localEs
les Persistence
p Limit
l (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff localEs r -> Eff es r) -> Eff es a
k ((forall r. Eff localEs r -> Eff es r) -> Eff es a)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unlift
{-# INLINE localUnlift #-}

-- | Create a local unlifting function with the given strategy.
localUnliftIO
  :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> UnliftStrategy
  -> ((forall r. Eff localEs r -> IO r) -> IO a)
  -- ^ Continuation with the unlifting function in scope.
  -> Eff es a
localUnliftIO :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs, IOE :> es) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. Eff localEs r -> IO r) -> IO a)
-> Eff es a
localUnliftIO (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. Eff localEs r -> IO r) -> IO a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift -> Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
les (forall r. Eff localEs r -> IO r) -> IO a
k
    UnliftStrategy
SeqForkUnlift -> Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env localEs
les (forall r. Eff localEs r -> IO r) -> IO a
k
    ConcUnlift Persistence
p Limit
l -> Env localEs
-> Persistence
-> Limit
-> ((forall r. Eff localEs r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env localEs
les Persistence
p Limit
l (forall r. Eff localEs r -> IO r) -> IO a
k
{-# INLINE localUnliftIO #-}

----------------------------------------
-- Lifts

-- | Create a local lifting function with the 'SeqUnlift' strategy. For the
-- general version see 'localLift'.
--
-- @since 2.2.1.0
localSeqLift
  :: (HasCallStack, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
  -- ^ Continuation with the lifting function in scope.
  -> Eff es a
localSeqLift :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> ((forall r. Eff es r -> Eff localEs r) -> Eff es a) -> Eff es a
localSeqLift (LocalEnv Env localEs
les) (forall r. Eff es r -> Eff localEs r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env es
es (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unlift -> do
    (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r) -> Eff es a
k ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
-> (forall r. Eff es r -> Eff localEs r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unlift
{-# INLINE localSeqLift #-}

-- | Create a local lifting function with the given strategy.
--
-- @since 2.2.1.0
localLift
  :: (HasCallStack, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> UnliftStrategy
  -> ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
  -- ^ Continuation with the lifting function in scope.
  -> Eff es a
localLift :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
-> Eff es a
localLift (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. Eff es r -> Eff localEs r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift -> Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env es
es (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r) -> Eff es a
k ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
-> (forall r. Eff es r -> Eff localEs r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unlift
    UnliftStrategy
SeqForkUnlift -> Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env es
es (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r) -> Eff es a
k ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
-> (forall r. Eff es r -> Eff localEs r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unlift
    ConcUnlift Persistence
p Limit
l -> Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env es
es Persistence
p Limit
l (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r) -> Eff es a
k ((forall r. Eff es r -> Eff localEs r) -> Eff es a)
-> (forall r. Eff es r -> Eff localEs r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unlift
{-# INLINE localLift #-}

-- | Utility for lifting 'Eff' computations of type
--
-- @'Eff' es a -> 'Eff' es b@
--
-- to
--
-- @'Eff' localEs a -> 'Eff' localEs b@
--
-- /Note:/ the computation must not run its argument in a different thread,
-- attempting to do so will result in a runtime error.
withLiftMap
  :: (HasCallStack, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> ((forall a b. (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
  -- ^ Continuation with the lifting function in scope.
  -> Eff es r
withLiftMap :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) r.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> ((forall a b.
     (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b)
    -> Eff es r)
-> Eff es r
withLiftMap (LocalEnv Env localEs
les) (forall a b.
 (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b)
-> Eff es r
k = (Env es -> IO r) -> Eff es r
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO r) -> Eff es r) -> (Env es -> IO r) -> Eff es r
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  (Eff es r -> Env es -> IO r
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es r -> IO r) -> Eff es r -> IO r
forall a b. (a -> b) -> a -> b
$ (forall a b.
 (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b)
-> Eff es r
k ((forall a b.
  (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b)
 -> Eff es r)
-> (forall a b.
    (Eff es a -> Eff es b) -> Eff localEs a -> Eff localEs b)
-> Eff es r
forall a b. (a -> b) -> a -> b
$ \Eff es a -> Eff es b
mapEff Eff localEs a
m -> (Env localEs -> IO b) -> Eff localEs b
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env localEs -> IO b) -> Eff localEs b)
-> (Env localEs -> IO b) -> Eff localEs b
forall a b. (a -> b) -> a -> b
$ \Env localEs
localEs -> do
    Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO b) -> IO b
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
localEs (((forall r. Eff localEs r -> IO r) -> IO b) -> IO b)
-> ((forall r. Eff localEs r -> IO r) -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unlift -> do
      (Eff es b -> Env es -> IO b
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es b -> IO b) -> (IO a -> Eff es b) -> IO a -> IO b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es a -> Eff es b
mapEff (Eff es a -> Eff es b) -> (IO a -> Eff es a) -> IO a -> Eff es b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> Eff es a
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO a -> IO b) -> IO a -> IO b
forall a b. (a -> b) -> a -> b
$ Eff localEs a -> IO a
forall r. Eff localEs r -> IO r
unlift Eff localEs a
m
{-# INLINE withLiftMap #-}

-- | Utility for lifting 'IO' computations of type
--
-- @'IO' a -> 'IO' b@
--
-- to
--
-- @'Eff' localEs a -> 'Eff' localEs b@
--
-- /Note:/ the computation must not run its argument in a different thread,
-- attempting to do so will result in a runtime error.
--
-- Useful e.g. for lifting the unmasking function in
-- 'Control.Exception.mask'-like computations:
--
-- >>> :{
-- data Fork :: Effect where
--   ForkWithUnmask :: ((forall a. m a -> m a) -> m ()) -> Fork m ThreadId
-- type instance DispatchOf Fork = Dynamic
-- :}
--
-- >>> :{
-- runFork :: IOE :> es => Eff (Fork : es) a -> Eff es a
-- runFork = interpret $ \env (ForkWithUnmask m) -> withLiftMapIO env $ \liftMap -> do
--   localUnliftIO env (ConcUnlift Ephemeral $ Limited 1) $ \unlift -> do
--     forkIOWithUnmask $ \unmask -> unlift $ m $ liftMap unmask
-- :}
withLiftMapIO
  :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> ((forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b) -> Eff es r)
  -- ^ Continuation with the lifting function in scope.
  -> Eff es r
withLiftMapIO :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) r.
(HasCallStack, SharedSuffix es handlerEs, IOE :> es) =>
LocalEnv localEs handlerEs
-> ((forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b)
    -> Eff es r)
-> Eff es r
withLiftMapIO (LocalEnv Env localEs
les) (forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b)
-> Eff es r
k = (Env es -> IO r) -> Eff es r
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO r) -> Eff es r) -> (Env es -> IO r) -> Eff es r
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  (Eff es r -> Env es -> IO r
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es r -> IO r) -> Eff es r -> IO r
forall a b. (a -> b) -> a -> b
$ (forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b)
-> Eff es r
k ((forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b)
 -> Eff es r)
-> (forall a b. (IO a -> IO b) -> Eff localEs a -> Eff localEs b)
-> Eff es r
forall a b. (a -> b) -> a -> b
$ \IO a -> IO b
mapIO Eff localEs a
m -> (Env localEs -> IO b) -> Eff localEs b
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env localEs -> IO b) -> Eff localEs b)
-> (Env localEs -> IO b) -> Eff localEs b
forall a b. (a -> b) -> a -> b
$ \Env localEs
localEs -> do
    Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO b) -> IO b
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
localEs (((forall r. Eff localEs r -> IO r) -> IO b) -> IO b)
-> ((forall r. Eff localEs r -> IO r) -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unlift -> IO a -> IO b
mapIO (IO a -> IO b) -> IO a -> IO b
forall a b. (a -> b) -> a -> b
$ Eff localEs a -> IO a
forall r. Eff localEs r -> IO r
unlift Eff localEs a
m
{-# INLINE withLiftMapIO #-}

----------------------------------------
-- Bidirectional lifts

-- | Create a local lifting and unlifting function with the given strategy.
--
-- Useful for lifting complicated 'Eff' computations where the monadic action
-- shows in both positive (as a result) and negative (as an argument) position.
--
-- /Note:/ depending on the computation you're lifting 'localUnlift' along with
-- 'withLiftMap' might be enough and is more efficient.
localLiftUnlift
  :: (HasCallStack, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> UnliftStrategy
  -> ((forall r. Eff es r -> Eff localEs r) -> (forall r. Eff localEs r -> Eff es r) -> Eff es a)
  -- ^ Continuation with the lifting and unlifting function in scope.
  -> Eff es a
localLiftUnlift :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. Eff es r -> Eff localEs r)
    -> (forall r. Eff localEs r -> Eff es r) -> Eff es a)
-> Eff es a
localLiftUnlift (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. Eff es r -> Eff localEs r)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift -> Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env es
es (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unliftEs -> do
      Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unliftLocalEs -> do
        (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
k (IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unliftEs) (IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unliftLocalEs)
    UnliftStrategy
SeqForkUnlift -> Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env es
es (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unliftEs -> do
      Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unliftLocalEs -> do
        (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
k (IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unliftEs) (IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unliftLocalEs)
    ConcUnlift Persistence
p Limit
l -> Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env es
es Persistence
p Limit
l (((forall r. Eff es r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff es r -> IO r
unliftEs -> do
      Env localEs
-> Persistence
-> Limit
-> ((forall r. Eff localEs r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env localEs
les Persistence
p Limit
l (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff localEs r -> IO r
unliftLocalEs -> do
        (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff es r -> Eff localEs r)
-> (forall r. Eff localEs r -> Eff es r) -> Eff es a
k (IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff es r -> IO r) -> Eff es r -> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff es r -> IO r
forall r. Eff es r -> IO r
unliftEs) (IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff localEs r -> IO r) -> Eff localEs r -> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff localEs r -> IO r
forall r. Eff localEs r -> IO r
unliftLocalEs)
{-# INLINE localLiftUnlift #-}

-- | Create a local unlifting function with the given strategy along with an
-- unrestricted lifting function.
--
-- Useful for lifting complicated 'IO' computations where the monadic action
-- shows in both positive (as a result) and negative (as an argument) position.
--
-- /Note:/ depending on the computation you're lifting 'localUnliftIO' along
-- with 'withLiftMapIO' might be enough and is more efficient.
localLiftUnliftIO
  :: (HasCallStack, SharedSuffix es handlerEs, IOE :> es)
  => LocalEnv localEs handlerEs
  -- ^ Local environment.
  -> UnliftStrategy
  -> ((forall r. IO r -> Eff localEs r) -> (forall r. Eff localEs r -> IO r) -> IO a)
  -- ^ Continuation with the lifting and unlifting function in scope.
  -> Eff es a
localLiftUnliftIO :: forall (es :: [Effect]) (handlerEs :: [Effect])
       (localEs :: [Effect]) a.
(HasCallStack, SharedSuffix es handlerEs, IOE :> es) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. IO r -> Eff localEs r)
    -> (forall r. Eff localEs r -> IO r) -> IO a)
-> Eff es a
localLiftUnliftIO (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. IO r -> Eff localEs r)
-> (forall r. Eff localEs r -> IO r) -> IO a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env es -> Env localEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es
es Env localEs
les
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift      -> Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. IO r -> Eff localEs r)
-> (forall r. Eff localEs r -> IO r) -> IO a
k IO r -> Eff localEs r
forall r. IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_
    UnliftStrategy
SeqForkUnlift  -> Env localEs -> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env localEs
les (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. IO r -> Eff localEs r)
-> (forall r. Eff localEs r -> IO r) -> IO a
k IO r -> Eff localEs r
forall r. IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_
    ConcUnlift Persistence
p Limit
l -> Env localEs
-> Persistence
-> Limit
-> ((forall r. Eff localEs r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env localEs
les Persistence
p Limit
l (((forall r. Eff localEs r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff localEs r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. IO r -> Eff localEs r)
-> (forall r. Eff localEs r -> IO r) -> IO a
k IO r -> Eff localEs r
forall r. IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_
{-# INLINE localLiftUnliftIO #-}

----------------------------------------
-- Misc

-- | Lend effects to the local environment.
--
-- Consider the following effect:
--
-- >>> :{
--   data D :: Effect where
--     D :: D m ()
--   type instance DispatchOf D = Dynamic
-- :}
--
-- and an auxiliary effect that requires both @IOE@ and @D@ to run:
--
-- >>> :{
--   data E :: Effect
--   runE :: (IOE :> es, D :> es) => Eff (E : es) a -> Eff es a
--   runE = error "runE"
-- :}
--
-- Trying to use @runE@ inside the handler of @D@ doesn't work out of the box:
--
-- >>> :{
--   runD :: IOE :> es => Eff (D : es) a -> Eff es a
--   runD = interpret $ \env -> \case
--     D -> localSeqUnlift env $ \unlift -> do
--       unlift . runE $ pure ()
-- :}
-- ...
-- ...Could not deduce ...IOE :> localEs... arising from a use of ‘runE’
-- ...from the context: IOE :> es
-- ...
--
-- The problem is that @runE@ needs @IOE :> localEs@, but only @IOE :> es@ is
-- available. This function allows us to bridge the gap:
--
-- >>> :{
--   runD :: IOE :> es => Eff (D : es) a -> Eff es a
--   runD = interpret $ \env -> \case
--     D -> localSeqUnlift env $ \unlift -> do
--       localSeqLend @'[IOE] env $ \useIOE -> do
--         unlift . useIOE . runE $ pure ()
-- :}
--
-- @since 2.4.0.0
localSeqLend
  :: forall lentEs es handlerEs localEs a
   . (HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a)
  -- ^ Continuation with the lent handler in scope.
  -> Eff es a
localSeqLend :: forall (lentEs :: [Effect]) (es :: [Effect])
       (handlerEs :: [Effect]) (localEs :: [Effect]) a.
(HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
    -> Eff es a)
-> Eff es a
localSeqLend (LocalEnv Env localEs
les) (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env (lentEs ++ localEs)
eles <- forall (es :: [Effect]) (srcEs :: [Effect]) (destEs :: [Effect]).
(HasCallStack, KnownSubset es srcEs) =>
Env srcEs -> Env destEs -> IO (Env (es ++ destEs))
copyRefs @lentEs Env es
es Env localEs
les
  Env (lentEs ++ localEs)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env (lentEs ++ localEs)
eles (((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (lentEs ++ localEs) r -> IO r
unlift -> (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a
k ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
 -> Eff es a)
-> (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
-> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff (lentEs ++ localEs) r -> IO r)
-> Eff (lentEs ++ localEs) r
-> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (lentEs ++ localEs) r -> IO r
forall r. Eff (lentEs ++ localEs) r -> IO r
unlift
{-# INLINE localSeqLend #-}

-- | Lend effects to the local environment with a given unlifting strategy.
--
-- Generalizes 'localSeqLend'.
--
-- @since 2.4.0.0
localLend
  :: forall lentEs es handlerEs localEs a
   . (HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -> UnliftStrategy
  -> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a)
  -- ^ Continuation with the lent handler in scope.
  -> Eff es a
localLend :: forall (lentEs :: [Effect]) (es :: [Effect])
       (handlerEs :: [Effect]) (localEs :: [Effect]) a.
(HasCallStack, KnownSubset lentEs es, SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
    -> Eff es a)
-> Eff es a
localLend (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env (lentEs ++ localEs)
eles <- forall (es :: [Effect]) (srcEs :: [Effect]) (destEs :: [Effect]).
(HasCallStack, KnownSubset es srcEs) =>
Env srcEs -> Env destEs -> IO (Env (es ++ destEs))
copyRefs @lentEs Env es
es Env localEs
les
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift -> Env (lentEs ++ localEs)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env (lentEs ++ localEs)
eles (((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (lentEs ++ localEs) r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a
k ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
 -> Eff es a)
-> (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
-> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff (lentEs ++ localEs) r -> IO r)
-> Eff (lentEs ++ localEs) r
-> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (lentEs ++ localEs) r -> IO r
forall r. Eff (lentEs ++ localEs) r -> IO r
unlift
    UnliftStrategy
SeqForkUnlift -> Env (lentEs ++ localEs)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env (lentEs ++ localEs)
eles (((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (lentEs ++ localEs) r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a
k ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
 -> Eff es a)
-> (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
-> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff (lentEs ++ localEs) r -> IO r)
-> Eff (lentEs ++ localEs) r
-> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (lentEs ++ localEs) r -> IO r
forall r. Eff (lentEs ++ localEs) r -> IO r
unlift
    ConcUnlift Persistence
p Limit
l -> Env (lentEs ++ localEs)
-> Persistence
-> Limit
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env (lentEs ++ localEs)
eles Persistence
p Limit
l (((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (lentEs ++ localEs) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (lentEs ++ localEs) r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r) -> Eff es a
k ((forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
 -> Eff es a)
-> (forall r. Eff (lentEs ++ localEs) r -> Eff localEs r)
-> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff localEs r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff localEs r)
-> (Eff (lentEs ++ localEs) r -> IO r)
-> Eff (lentEs ++ localEs) r
-> Eff localEs r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (lentEs ++ localEs) r -> IO r
forall r. Eff (lentEs ++ localEs) r -> IO r
unlift
{-# INLINE localLend #-}

-- | Borrow effects from the local environment.
--
-- @since 2.4.0.0
localSeqBorrow
  :: forall borrowedEs es handlerEs localEs a
   . (HasCallStack, KnownSubset borrowedEs localEs, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
  -- ^ Continuation with the borrowed handler in scope.
  -> Eff es a
localSeqBorrow :: forall (borrowedEs :: [Effect]) (es :: [Effect])
       (handlerEs :: [Effect]) (localEs :: [Effect]) a.
(HasCallStack, KnownSubset borrowedEs localEs,
 SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
-> Eff es a
localSeqBorrow (LocalEnv Env localEs
les) (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env (borrowedEs ++ es)
ees <- forall (es :: [Effect]) (srcEs :: [Effect]) (destEs :: [Effect]).
(HasCallStack, KnownSubset es srcEs) =>
Env srcEs -> Env destEs -> IO (Env (es ++ destEs))
copyRefs @borrowedEs Env localEs
les Env es
es
  Env (borrowedEs ++ es)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env (borrowedEs ++ es)
ees (((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (borrowedEs ++ es) r -> IO r
unlift -> (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
k ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
-> (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff (borrowedEs ++ es) r -> IO r)
-> Eff (borrowedEs ++ es) r
-> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (borrowedEs ++ es) r -> IO r
forall r. Eff (borrowedEs ++ es) r -> IO r
unlift
{-# INLINE localSeqBorrow #-}

-- | Borrow effects from the local environment with a given unlifting
-- strategy.
--
-- Generalizes 'localSeqBorrow'.
--
-- @since 2.4.0.0
localBorrow
  :: forall borrowedEs es handlerEs localEs a
   . (HasCallStack, KnownSubset borrowedEs localEs, SharedSuffix es handlerEs)
  => LocalEnv localEs handlerEs
  -> UnliftStrategy
  -> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
  -- ^ Continuation with the borrowed handler in scope.
  -> Eff es a
localBorrow :: forall (borrowedEs :: [Effect]) (es :: [Effect])
       (handlerEs :: [Effect]) (localEs :: [Effect]) a.
(HasCallStack, KnownSubset borrowedEs localEs,
 SharedSuffix es handlerEs) =>
LocalEnv localEs handlerEs
-> UnliftStrategy
-> ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
-> Eff es a
localBorrow (LocalEnv Env localEs
les) UnliftStrategy
strategy (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
k = (Env es -> IO a) -> Eff es a
forall (es :: [Effect]) a. (Env es -> IO a) -> Eff es a
unsafeEff ((Env es -> IO a) -> Eff es a) -> (Env es -> IO a) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \Env es
es -> do
  Env (borrowedEs ++ es)
ees <- forall (es :: [Effect]) (srcEs :: [Effect]) (destEs :: [Effect]).
(HasCallStack, KnownSubset es srcEs) =>
Env srcEs -> Env destEs -> IO (Env (es ++ destEs))
copyRefs @borrowedEs Env localEs
les Env es
es
  case UnliftStrategy
strategy of
    UnliftStrategy
SeqUnlift -> Env (borrowedEs ++ es)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqUnliftIO Env (borrowedEs ++ es)
ees (((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (borrowedEs ++ es) r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
k ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
-> (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff (borrowedEs ++ es) r -> IO r)
-> Eff (borrowedEs ++ es) r
-> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (borrowedEs ++ es) r -> IO r
forall r. Eff (borrowedEs ++ es) r -> IO r
unlift
    UnliftStrategy
SeqForkUnlift -> Env (borrowedEs ++ es)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es -> ((forall r. Eff es r -> IO r) -> IO a) -> IO a
seqForkUnliftIO Env (borrowedEs ++ es)
ees (((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (borrowedEs ++ es) r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
k ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
-> (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff (borrowedEs ++ es) r -> IO r)
-> Eff (borrowedEs ++ es) r
-> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (borrowedEs ++ es) r -> IO r
forall r. Eff (borrowedEs ++ es) r -> IO r
unlift
    ConcUnlift Persistence
p Limit
l -> Env (borrowedEs ++ es)
-> Persistence
-> Limit
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a)
-> IO a
forall (es :: [Effect]) a.
HasCallStack =>
Env es
-> Persistence
-> Limit
-> ((forall r. Eff es r -> IO r) -> IO a)
-> IO a
concUnliftIO Env (borrowedEs ++ es)
ees Persistence
p Limit
l (((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a)
-> ((forall r. Eff (borrowedEs ++ es) r -> IO r) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall r. Eff (borrowedEs ++ es) r -> IO r
unlift -> do
      (Eff es a -> Env es -> IO a
forall (es :: [Effect]) a. Eff es a -> Env es -> IO a
`unEff` Env es
es) (Eff es a -> IO a) -> Eff es a -> IO a
forall a b. (a -> b) -> a -> b
$ (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
k ((forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a)
-> (forall r. Eff (borrowedEs ++ es) r -> Eff es r) -> Eff es a
forall a b. (a -> b) -> a -> b
$ IO r -> Eff es r
forall a (es :: [Effect]). IO a -> Eff es a
unsafeEff_ (IO r -> Eff es r)
-> (Eff (borrowedEs ++ es) r -> IO r)
-> Eff (borrowedEs ++ es) r
-> Eff es r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Eff (borrowedEs ++ es) r -> IO r
forall r. Eff (borrowedEs ++ es) r -> IO r
unlift
{-# INLINE localBorrow #-}

copyRefs
  :: forall es srcEs destEs
   . (HasCallStack, KnownSubset es srcEs)
  => Env srcEs
  -> Env destEs
  -> IO (Env (es ++ destEs))
copyRefs :: forall (es :: [Effect]) (srcEs :: [Effect]) (destEs :: [Effect]).
(HasCallStack, KnownSubset es srcEs) =>
Env srcEs -> Env destEs -> IO (Env (es ++ destEs))
copyRefs src :: Env srcEs
src@(Env Int
soffset PrimArray Ref
srefs IORef' Storage
_) dest :: Env destEs
dest@(Env Int
doffset PrimArray Ref
drefs IORef' Storage
storage) = do
  Env srcEs -> Env destEs -> IO ()
forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env srcEs
src Env destEs
dest
  let es :: [Int]
es = forall (subEs :: [Effect]) (es :: [Effect]).
Subset subEs es =>
[Int]
reifyIndices @es @srcEs
      esSize :: Int
esSize = [Int] -> Int
forall a. [a] -> Int
forall (t :: Type -> Type) a. Foldable t => t a -> Int
length [Int]
es
      destSize :: Int
destSize = PrimArray Ref -> Int
forall a. Prim a => PrimArray a -> Int
sizeofPrimArray PrimArray Ref
drefs Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
doffset
  MutablePrimArray RealWorld Ref
mrefs <- Int -> IO (MutablePrimArray (PrimState IO) Ref)
forall (m :: Type -> Type) a.
(PrimMonad m, Prim a) =>
Int -> m (MutablePrimArray (PrimState m) a)
newPrimArray (Int
esSize Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
destSize)
  MutablePrimArray (PrimState IO) Ref
-> Int -> PrimArray Ref -> Int -> Int -> IO ()
forall (m :: Type -> Type) a.
(PrimMonad m, Prim a) =>
MutablePrimArray (PrimState m) a
-> Int -> PrimArray a -> Int -> Int -> m ()
copyPrimArray MutablePrimArray RealWorld Ref
MutablePrimArray (PrimState IO) Ref
mrefs Int
esSize PrimArray Ref
drefs Int
doffset Int
destSize
  let writeRefs :: Int -> [Int] -> IO ()
writeRefs Int
i = \case
        [] -> () -> IO ()
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()
        (Int
x : [Int]
xs) -> do
          MutablePrimArray (PrimState IO) Ref -> Int -> Ref -> IO ()
forall a (m :: Type -> Type).
(Prim a, PrimMonad m) =>
MutablePrimArray (PrimState m) a -> Int -> a -> m ()
writePrimArray MutablePrimArray RealWorld Ref
MutablePrimArray (PrimState IO) Ref
mrefs Int
i (Ref -> IO ()) -> Ref -> IO ()
forall a b. (a -> b) -> a -> b
$ PrimArray Ref -> Int -> Ref
forall a. Prim a => PrimArray a -> Int -> a
indexPrimArray PrimArray Ref
srefs (Int
soffset Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
x)
          Int -> [Int] -> IO ()
writeRefs (Int
i Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) [Int]
xs
  Int -> [Int] -> IO ()
writeRefs Int
0 [Int]
es
  PrimArray Ref
refs <- MutablePrimArray (PrimState IO) Ref -> IO (PrimArray Ref)
forall (m :: Type -> Type) a.
PrimMonad m =>
MutablePrimArray (PrimState m) a -> m (PrimArray a)
unsafeFreezePrimArray MutablePrimArray RealWorld Ref
MutablePrimArray (PrimState IO) Ref
mrefs
  Env (es ++ destEs) -> IO (Env (es ++ destEs))
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (Env (es ++ destEs) -> IO (Env (es ++ destEs)))
-> Env (es ++ destEs) -> IO (Env (es ++ destEs))
forall a b. (a -> b) -> a -> b
$ Int -> PrimArray Ref -> IORef' Storage -> Env (es ++ destEs)
forall (es :: [Effect]).
Int -> PrimArray Ref -> IORef' Storage -> Env es
Env Int
0 PrimArray Ref
refs IORef' Storage
storage
{-# NOINLINE copyRefs #-}

requireMatchingStorages :: HasCallStack => Env es1 -> Env es2 -> IO ()
requireMatchingStorages :: forall (es1 :: [Effect]) (es2 :: [Effect]).
HasCallStack =>
Env es1 -> Env es2 -> IO ()
requireMatchingStorages Env es1
es1 Env es2
es2
  | Env es1 -> IORef' Storage
forall (es :: [Effect]). Env es -> IORef' Storage
envStorage Env es1
es1 IORef' Storage -> IORef' Storage -> Bool
forall a. Eq a => a -> a -> Bool
/= Env es2 -> IORef' Storage
forall (es :: [Effect]). Env es -> IORef' Storage
envStorage Env es2
es2 = [Char] -> IO ()
forall a. HasCallStack => [Char] -> a
error
    ([Char] -> IO ()) -> [Char] -> IO ()
forall a b. (a -> b) -> a -> b
$ [Char]
"Env and LocalEnv point to different Storages.\n"
    [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"If you passed LocalEnv to a different thread and tried to create an "
    [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"unlifting function there, it's not allowed. You need to create it in "
    [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"the thread of the effect handler."
  | Bool
otherwise = () -> IO ()
forall a. a -> IO a
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure ()

-- | Require that both effect stacks share an opaque suffix.
--
-- Functions from the 'localUnlift' family utilize this constraint to guarantee
-- sensible usage of unlifting functions.
--
-- As an example, consider the following higher order effect:
--
-- >>> :{
--   data E :: Effect where
--     E :: m a -> E m a
--   type instance DispatchOf E = Dynamic
-- :}
--
-- Running local actions in a more specific environment is fine:
--
-- >>> :{
--  runE1 :: Eff (E : es) a -> Eff es a
--  runE1 = interpret $ \env -> \case
--    E m -> runReader () $ do
--      localSeqUnlift env $ \unlift -> unlift m
-- :}
--
-- Running local actions in a more general environment is fine:
--
-- >>> :{
--  runE2 :: Eff (E : es) a -> Eff es a
--  runE2 = reinterpret (runReader ()) $ \env -> \case
--    E m -> raise $ do
--      localSeqUnlift env $ \unlift -> unlift m
-- :}
--
-- However, running local actions in an unrelated environment is not fine as
-- this would make it possible to run anything within 'runPureEff':
--
-- >>> :{
--  runE3 :: Eff (E : es) a -> Eff es a
--  runE3 = reinterpret (runReader ()) $ \env -> \case
--    E m -> pure . runPureEff $ do
--      localSeqUnlift env $ \unlift -> unlift m
-- :}
-- ...
-- ...Could not deduce ...SharedSuffix '[] es...
-- ...
--
-- Running local actions in a monomorphic effect stack is also not fine as
-- this makes a special case of the above possible:
--
-- >>> :{
--  runE4 :: Eff [E, IOE] a -> Eff '[IOE] a
--  runE4 = interpret $ \env -> \case
--    E m -> pure . runPureEff $ do
--      localSeqUnlift env $ \unlift -> unlift m
-- :}
-- ...
-- ...Running local actions in monomorphic effect stacks is not supported...
-- ...
--
-- @since 1.2.0.0
class SharedSuffix (es1 :: [Effect]) (es2 :: [Effect])

instance {-# INCOHERENT #-} SharedSuffix es es
instance {-# INCOHERENT #-} SharedSuffix es1 es2 => SharedSuffix (e : es1) es2
instance {-# INCOHERENT #-} SharedSuffix es1 es2 => SharedSuffix es1 (e : es2)

-- | This is always preferred to @SharedSuffix es es@ as it's not incoherent.
instance
  TypeError
  ( Text "Running local actions in monomorphic effect stacks is not supported." :$$:
    Text "As a solution simply change the stack to have a polymorphic suffix."
  ) => SharedSuffix '[] '[]

-- $setup
-- >>> import Control.Concurrent (ThreadId, forkIOWithUnmask)
-- >>> import Control.Monad.IO.Class
-- >>> import Effectful.Reader.Static