{-# options_haddock prune #-}
-- |Description: Scoped Effect, Internal
module Polysemy.Conc.Effect.Scoped where

import Polysemy (transform)
import Polysemy.Internal (send)

-- |@Scoped@ transforms a program so that @effect@ is associated with a @resource@ within that program.
-- This requires the interpreter for @effect@ to be parameterized by @resource@ and constructed for every program using
-- @Scoped@ separately.
--
-- An application for this is 'Polysemy.Conc.Events', in which each program using the effect 'Consume' is interpreted
-- with its own copy of the event channel; or a database transaction, in which a transaction handle is created for the
-- wrapped program and passed to the interpreter for the database effect.
--
-- Resource creation is performed by the function passed to 'runScoped'.
--
-- The constructors are not intended to be used directly; the smart constructor 'scoped' is used like a local
-- interpreter for @effect@.
data Scoped (resource :: Type) (effect :: Effect) :: Effect where
  Run ::  resource effect m a . resource -> effect m a -> Scoped resource effect m a
  InScope ::  resource effect m a . (resource -> m a) -> Scoped resource effect m a

-- |Constructor for 'Scoped', taking a nested program and transforming all instances of @effect@ to
-- @Scoped resource effect@.
scoped ::
   resource effect r .
  Member (Scoped resource effect) r =>
  InterpreterFor effect r
scoped :: InterpreterFor effect r
scoped Sem (effect : r) a
main =
  Scoped resource effect (Sem r) a -> Sem r a
forall (e :: Effect) (r :: [Effect]) a.
Member e r =>
e (Sem r) a -> Sem r a
send (Scoped resource effect (Sem r) a -> Sem r a)
-> Scoped resource effect (Sem r) a -> Sem r a
forall a b. (a -> b) -> a -> b
$ (resource -> Sem r a) -> Scoped resource effect (Sem r) a
forall resource (effect :: Effect) (m :: * -> *) a.
(resource -> m a) -> Scoped resource effect m a
InScope @resource @effect \ resource
resource ->
    (forall (rInitial :: [Effect]) x.
 effect (Sem rInitial) x -> Scoped resource effect (Sem rInitial) x)
-> Sem (effect : r) a -> Sem r a
forall (e1 :: Effect) (e2 :: Effect) (r :: [Effect]) a.
Member e2 r =>
(forall (rInitial :: [Effect]) x.
 e1 (Sem rInitial) x -> e2 (Sem rInitial) x)
-> Sem (e1 : r) a -> Sem r a
transform @effect (resource
-> effect (Sem rInitial) x
-> Scoped resource effect (Sem rInitial) x
forall resource (effect :: Effect) (m :: * -> *) a.
resource -> effect m a -> Scoped resource effect m a
Run resource
resource) Sem (effect : r) a
main