{-# LANGUAGE TemplateHaskell #-}
module Polysemy.EndState
  (-- * Effect
    EndState(..)

    -- * Actions
  , getEndState

    -- * Interpretations
  , runEndState
  , runEndAtomicState
  ) where

import Polysemy
import Polysemy.Fixpoint
import Polysemy.Reader
import Polysemy.Reader.More

import Polysemy.State
import Polysemy.AtomicState


-----------------------------------------------------------------------------
-- | An effect for getting the end state of a computation in advance.
data EndState s m a where
  GetEndState :: EndState s m s

makeSem ''EndState

-----------------------------------------------------------------------------
-- | Runs an 'EndState' effect by getting the state after the computation
-- has finished, and providing it recursively back to calls of 'getEndState'.
runEndState :: forall s r a
             . (Member (State s) r, Member Fixpoint r)
            => Sem (EndState s ': r) a
            -> Sem r a
runEndState :: Sem (EndState s : r) a -> Sem r a
runEndState =
    Sem r s -> Sem (Reader s : r) a -> Sem r a
forall i (r :: EffectRow) a.
Member Fixpoint r =>
Sem r i -> Sem (Reader i : r) a -> Sem r a
runReaderFixSem (forall (r :: EffectRow). Member (State s) r => Sem r s
forall s (r :: EffectRow). Member (State s) r => Sem r s
get @s)
  (Sem (Reader s : r) a -> Sem r a)
-> (Sem (EndState s : r) a -> Sem (Reader s : r) a)
-> Sem (EndState s : r) a
-> Sem r a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (rInitial :: EffectRow) x.
 EndState s (Sem rInitial) x -> Sem (Reader s : r) x)
-> Sem (EndState s : r) a -> Sem (Reader s : r) a
forall (e1 :: (* -> *) -> * -> *) (e2 :: (* -> *) -> * -> *)
       (r :: EffectRow) a.
FirstOrder e1 "reinterpret" =>
(forall (rInitial :: EffectRow) x.
 e1 (Sem rInitial) x -> Sem (e2 : r) x)
-> Sem (e1 : r) a -> Sem (e2 : r) a
reinterpret (\EndState s (Sem rInitial) x
GetEndState -> Sem (Reader s : r) x
forall i (r :: EffectRow). Member (Reader i) r => Sem r i
ask)


-----------------------------------------------------------------------------
-- | Like 'runEndState', but for 'AtomicState' rather than 'State'.
runEndAtomicState
  :: forall s r a
   . (Member (AtomicState s) r, Member Fixpoint r)
  => Sem (EndState s ': r) a
  -> Sem r a
runEndAtomicState :: Sem (EndState s : r) a -> Sem r a
runEndAtomicState =
    Sem r s -> Sem (Reader s : r) a -> Sem r a
forall i (r :: EffectRow) a.
Member Fixpoint r =>
Sem r i -> Sem (Reader i : r) a -> Sem r a
runReaderFixSem (forall (r :: EffectRow). Member (AtomicState s) r => Sem r s
forall s (r :: EffectRow). Member (AtomicState s) r => Sem r s
atomicGet @s)
  (Sem (Reader s : r) a -> Sem r a)
-> (Sem (EndState s : r) a -> Sem (Reader s : r) a)
-> Sem (EndState s : r) a
-> Sem r a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (rInitial :: EffectRow) x.
 EndState s (Sem rInitial) x -> Sem (Reader s : r) x)
-> Sem (EndState s : r) a -> Sem (Reader s : r) a
forall (e1 :: (* -> *) -> * -> *) (e2 :: (* -> *) -> * -> *)
       (r :: EffectRow) a.
FirstOrder e1 "reinterpret" =>
(forall (rInitial :: EffectRow) x.
 e1 (Sem rInitial) x -> Sem (e2 : r) x)
-> Sem (e1 : r) a -> Sem (e2 : r) a
reinterpret (\EndState s (Sem rInitial) x
GetEndState -> Sem (Reader s : r) x
forall i (r :: EffectRow). Member (Reader i) r => Sem r i
ask)