-- | 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 { State s -> s
unState :: s }

runState :: s -> Eff (State s : es) a -> Eff es (a, s)
runState :: s -> Eff (State s : es) a -> Eff es (a, s)
runState s
s = Eff es (a, State s) -> Eff es (a, s)
coerce (Eff es (a, State s) -> Eff es (a, s))
-> (Eff (State s : es) a -> Eff es (a, State s))
-> Eff (State s : es) a
-> Eff es (a, s)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State s -> Eff (State s : es) a -> Eff es (a, State s)
forall e (es :: [*]) a. e -> Eff (e : es) a -> Eff es (a, e)
runEffect (s -> State s
forall s. s -> State s
State s
s)

evalState :: s -> Eff (State s : es) a -> Eff es a
evalState :: s -> Eff (State s : es) a -> Eff es a
evalState s
s = State s -> Eff (State s : es) a -> Eff es a
forall e (es :: [*]) a. e -> Eff (e : es) a -> Eff es a
evalEffect (s -> State s
forall s. s -> State s
State s
s)

execState :: s -> Eff (State s : es) a -> Eff es s
execState :: s -> Eff (State s : es) a -> Eff es s
execState s
s = Eff es (State s) -> Eff es s
coerce (Eff es (State s) -> Eff es s)
-> (Eff (State s : es) a -> Eff es (State s))
-> Eff (State s : es) a
-> Eff es s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. State s -> Eff (State s : es) a -> Eff es (State s)
forall e (es :: [*]) a. e -> Eff (e : es) a -> Eff es e
execEffect (s -> State s
forall s. s -> State s
State s
s)

get :: State s :> es => Eff es s
get :: Eff es s
get = State s -> s
forall s. State s -> s
unState (State s -> s) -> Eff es (State s) -> Eff es s
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Eff es (State s)
forall e (es :: [*]). (e :> es) => Eff es e
getEffect

put :: State s :> es => s -> Eff es ()
put :: s -> Eff es ()
put = State s -> Eff es ()
forall e (es :: [*]). (e :> es) => e -> Eff es ()
putEffect (State s -> Eff es ()) -> (s -> State s) -> s -> Eff es ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. s -> State s
forall s. s -> State s
State

state :: State s :> es => (s -> (a, s)) -> Eff es a
state :: (s -> (a, s)) -> Eff es a
state s -> (a, s)
f = (State s -> (a, State s)) -> Eff es a
forall e (es :: [*]) a. (e :> es) => (e -> (a, e)) -> Eff es a
stateEffect ((State s -> (a, State s)) -> Eff es a)
-> (State s -> (a, State s)) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \(State s
s0) -> let (a
a, s
s) = s -> (a, s)
f s
s0 in (a
a, s -> State s
forall s. s -> State s
State s
s)

modify :: State s :> es => (s -> s) -> Eff es ()
modify :: (s -> s) -> Eff es ()
modify s -> s
f = (s -> ((), s)) -> Eff es ()
forall s (es :: [*]) a.
(State s :> es) =>
(s -> (a, s)) -> Eff es a
state (\s
s -> ((), s -> s
f s
s))

stateM :: State s :> es => (s -> Eff es (a, s)) -> Eff es a
stateM :: (s -> Eff es (a, s)) -> Eff es a
stateM s -> Eff es (a, s)
f = (State s -> Eff es (a, State s)) -> Eff es a
forall e (es :: [*]) a.
(e :> es) =>
(e -> Eff es (a, e)) -> Eff es a
stateEffectM ((State s -> Eff es (a, State s)) -> Eff es a)
-> (State s -> Eff es (a, State s)) -> Eff es a
forall a b. (a -> b) -> a -> b
$ \(State s
s0) -> Eff es (a, s) -> Eff es (a, State s)
coerce (Eff es (a, s) -> Eff es (a, State s))
-> Eff es (a, s) -> Eff es (a, State s)
forall a b. (a -> b) -> a -> b
$ s -> Eff es (a, s)
f s
s0

modifyM :: State s :> es => (s -> Eff es s) -> Eff es ()
modifyM :: (s -> Eff es s) -> Eff es ()
modifyM s -> Eff es s
f = (s -> Eff es ((), s)) -> Eff es ()
forall s (es :: [*]) a.
(State s :> es) =>
(s -> Eff es (a, s)) -> Eff es a
stateM (\s
s -> ((), ) (s -> ((), s)) -> Eff es s -> Eff es ((), s)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> s -> Eff es s
f s
s)