effectful-0.0.0.0: src/Effectful/State/Dynamic.hs
-- | The 'State' as an effect with dynamic dispatch.
--
-- It's not clear in which situation it's beneficial to use this instead of
-- "Effective.State" or "Effective.State.MVar" as you either:
--
-- - Share state between threads and need the synchonized version.
--
-- - Don't share state between threads and are free to use the faster, pure
-- version.
--
-- However, let's include this for now.
--
module Effectful.State.Dynamic
( State
-- * Pure
, runState
, evalState
, execState
-- * MVar
, runStateMVar
, evalStateMVar
, execStateMVar
-- * Operations
, get
, put
, state
, modify
, stateM
, modifyM
) where
import Control.Concurrent.MVar
import Effectful.Internal.Has
import Effectful.Internal.Monad
-- | Provide access to a mutable state of type @s@.
--
-- Whether the state is represented as a pure value or an 'MVar' depends on the
-- interpretation.
data State s = forall ref. State
{ _ref :: ref
, _get :: forall es. ref -> Eff es s
, _put :: forall es. ref -> s -> Eff es ref
, _state :: forall es a. ref -> (s -> Eff es (a, s)) -> Eff es (a, ref)
}
----------------------------------------
-- Pure
runState :: s -> Eff (State s : es) a -> Eff es (a, s)
runState s m = evalEffect (statePure s) $ (,) <$> m <*> get
evalState :: s -> Eff (State s : es) a -> Eff es a
evalState s = evalEffect (statePure s)
execState :: s -> Eff (State s : es) a -> Eff es s
execState s m = evalEffect (statePure s) $ m *> get
statePure :: s -> State s
statePure s0 = State
{ _ref = s0
, _get = pure
, _put = \_ -> pure
, _state = \s f -> f s
}
----------------------------------------
-- MVar
runStateMVar :: s -> Eff (State s : es) a -> Eff es (a, s)
runStateMVar s m = do
v <- impureEff_ $ newMVar s
evalEffect (stateMVar v) $ (,) <$> m <*> get
evalStateMVar :: s -> Eff (State s : es) a -> Eff es a
evalStateMVar s m = do
v <- impureEff_ $ newMVar s
evalEffect (stateMVar v) m
execStateMVar :: s -> Eff (State s : es) a -> Eff es s
execStateMVar s m = do
v <- impureEff_ $ newMVar s
evalEffect (stateMVar v) $ m *> get
stateMVar :: MVar s -> State s
stateMVar v0 = State
{ _ref = v0
, _get = impureEff_ . readMVar
, _put = \v s -> impureEff_ . modifyMVar v $ \_ ->
s `seq` pure (s, v)
, _state = \v f -> impureEff $ \es -> modifyMVar v $ \s0 -> do
(a, s) <- unEff (f s0) es
s `seq` pure (s, (a, v))
}
----------------------------------------
-- Operations
get :: State s :> es => Eff es s
get = readerEffectM $ \State{..} -> _get _ref
put :: State s :> es => s -> Eff es ()
put s = stateEffectM $ \State{..} -> do
ref <- _put _ref s
pure ((), State { _ref = ref, .. })
state :: State s :> es => (s -> (a, s)) -> Eff es a
state f = stateEffectM $ \State{..} -> do
(a, ref) <- _state _ref $ pure . f
pure (a, State { _ref = ref, .. })
modify :: State s :> es => (s -> s) -> Eff es ()
modify f = state (\s -> ((), f s))
stateM :: State s :> es => (s -> Eff es (a, s)) -> Eff es a
stateM f = stateEffectM $ \State{..} -> do
(a, ref) <- _state _ref f
pure (a, State { _ref = ref, .. })
modifyM :: State s :> es => (s -> Eff es s) -> Eff es ()
modifyM f = stateM (\s -> ((), ) <$> f s)