packages feed

effectful-0.0.0.0: src/Effectful/State.hs

-- | The 'State' as an effect.
--
-- Represented as a pure value underneath, therefore:
--
-- - very fast
--
-- - not suitable for sharing between multiple threads.
--
-- If you plan to do the latter, have a look at "Effective.State.MVar" or
-- "Effective.State.Dynamic".
--
module Effectful.State
  ( State
  , runState
  , evalState
  , execState
  , get
  , put
  , state
  , modify
  , stateM
  , modifyM
  ) where

import Data.Coerce

import Effectful.Internal.Has
import Effectful.Internal.Monad

-- | Provide access to a pure, mutable state of type @s@.
newtype State s = State { unState :: s }

runState :: s -> Eff (State s : es) a -> Eff es (a, s)
runState s = coerce . runEffect (State s)

evalState :: s -> Eff (State s : es) a -> Eff es a
evalState s = evalEffect (State s)

execState :: s -> Eff (State s : es) a -> Eff es s
execState s = coerce . execEffect (State s)

get :: State s :> es => Eff es s
get = unState <$> getEffect

put :: State s :> es => s -> Eff es ()
put = putEffect . State

state :: State s :> es => (s -> (a, s)) -> Eff es a
state f = stateEffect $ \(State s0) -> let (a, s) = f s0 in (a, State s)

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 s0) -> coerce $ f s0

modifyM :: State s :> es => (s -> Eff es s) -> Eff es ()
modifyM f = stateM (\s -> ((), ) <$> f s)