bluefin-algae-0.1.0.2: src/Bluefin/Algae/State.hs
{-# LANGUAGE
BangPatterns,
GADTs,
KindSignatures,
RankNTypes,
ScopedTypeVariables,
StandaloneKindSignatures,
TypeOperators #-}
-- | = State as an algebraic effect
--
-- The 'runState' handler calls each continuation exactly once.
-- It is compatible with single-shot continuations.
module Bluefin.Algae.State
( -- * Operations
State(..)
, get
, put
, putL
, modify
, modifyL
-- * Handlers
, runState
, evalState
, execState
) where
import Data.Kind (Type)
import Bluefin.Eff (Eff, type (:&), type (:>))
import Bluefin.Algae
-- | The state effect.
data State (s :: Type) :: AEffect where
-- | Get the current state.
Get :: State s s
-- | Put a new state.
Put :: s -> State s ()
-- | Get the current state. Call the 'Get' operation.
get :: z :> zz => Handler (State s) z -> Eff zz s
get h = call h Get
-- | Put a new state. Call the 'Put' operation.
--
-- This function is strict.
put :: z :> zz => Handler (State s) z -> s -> Eff zz ()
put h !s = call h (Put s)
-- | Lazy variant of 'put'.
putL :: z :> zz => Handler (State s) z -> s -> Eff zz ()
putL h s = call h (Put s)
-- | Modify the state.
--
-- This function is strict in the modified state.
modify :: z :> zz => Handler (State s) z -> (s -> s) -> Eff zz ()
modify h f = get h >>= put h . f
-- | Lazy variant of 'modify'.
modifyL :: z :> zz => Handler (State s) z -> (s -> s) -> Eff zz ()
modifyL h f = get h >>= putL h . f
-- | Run a stateful computation from the given starting state.
runState ::
s -> -- ^ Initial state
(forall z. Handler (State s) z -> Eff (z :& zz) a) -> -- ^ Stateful computation
Eff zz (a, s)
runState = runStateWith (,)
-- | Variant of 'runState' that returns only the result value.
evalState ::
s -> -- ^ Initial state
(forall z. Handler (State s) z -> Eff (z :& zz) a) -> -- ^ Stateful computation
Eff zz a
evalState = runStateWith const
-- | Variant of 'runState' that returns only the final state.
execState ::
s -> -- ^ Initial state
(forall z. Handler (State s) z -> Eff (z :& zz) a) -> -- ^ Stateful computation
Eff zz s
execState = runStateWith (const id)
runStateWith :: forall s a r zz.
(a -> s -> r) -> -- ^ Combine the result and final state.
s -> -- ^ Initial state
(forall z. Handler (State s) z -> Eff (z :& zz) a) -> -- ^ Stateful computation
Eff zz r
runStateWith finish s0 f = unwrap s0 (handle stateHandler (wrap . f))
where
stateHandler :: HandlerBody (State s) zz (s -> Eff zz r)
stateHandler Get k = pure (\s -> k s >>= \k1 -> k1 s)
stateHandler (Put s) k = pure (\_ -> k () >>= \k1 -> k1 s)
wrap :: Eff (z :& zz) a -> Eff (z :& zz) (s -> Eff zz r)
wrap = fmap (\a s -> pure (finish a s))
unwrap :: s -> Eff zz (s -> Eff zz r) -> Eff zz r
unwrap s m = m >>= \k -> k s