//! Implementation of the `State` effect
let { Eff, inject_rest, ? } = import! std.effect
let { map } = import! std.functor
let { wrap } = import! std.applicative
let { (<<) } = import! std.function
/// The `State` effect provides an updatable state
type State s r a =
| Get : State s r s
| Put : s -> State s r ()
.. r
let extract_state x : forall s . [| state : State s | r |] a -> State s r a = convert_variant! x
let send_state f : State s r a -> Eff [| state : State s | r |] a =
Impure (convert_effect! state f) Pure
/// Retreive the current value.
let get : forall s . Eff [| state : State s | r |] s =
send_state Get
/// Retreive the current value and applied `f` to it.
let gets f : forall s . (s -> a) -> Eff [| state : State s | r |] a =
map f get
/// Store `s` as the new value of the state.
let put s : s -> Eff [| state : State s | r |] () =
send_state (Put s)
/// Update the state by applying `f`.
let modify f : (s -> s) -> Eff [| state : State s | r |] () =
do s = get
put (f s)
/// Eliminate the `State` effect and return the state and the computed value
let run_state s eff : forall s .
s
-> Eff [| state : State s | r |] a
-> Eff [| | r |] { state : s, value : a }
=
let loop state ve : s
-> Eff [| state : State s | r |] a
-> Eff [| | r |] { state : s, value : a }
=
match ve with
| Pure value -> wrap { state, value }
| Impure e f ->
match extract_state e with
| Get ->
loop state (f state)
| Put state ->
loop state (f ())
| rest ->
Impure (inject_rest rest) (loop state << f)
loop s eff
/// Eliminate the `State` effect and return the state
let exec_state s eff : forall s . s -> Eff [| state : State s | r |] a -> Eff [| | r |] s =
map (\r -> r.state) (run_state s eff)
/// Eliminate the `State` effect and return the computed value
let eval_state s eff : forall s . s -> Eff [| state : State s | r |] a -> Eff [| | r |] a =
map (\r -> r.value) (run_state s eff)
{
State,
get,
gets,
put,
modify,
run_state,
exec_state,
eval_state,
}