//! Implementation of the `st.State` effect
let { Eff, inject_rest, ? } = import! std.effect
let { map } = import! std.functor
let { wrap } = import! std.applicative
let { (<<) } = import! std.function
let reference @ { Reference, ref, load } = import! std.st.reference.prim
type STRef s a = Reference a
#[infix(right, 9)]
let (<-) = reference.(<-)
/// The `State` effect enables the use of mutable state. By branding the state with `s` the mutable
/// values are prevented from escaping the monad.
type State s r a =
| Call : forall b . (() -> b) -> State s r b
.. r
#[inline(never)]
let extract_state x : forall s . [| st : State s | r |] a -> State s r a = convert_variant! x
#[inline(never)]
let send_state f : forall s . State s r a -> Eff [| st : State s | r |] a =
Impure (convert_effect! st f) Pure
let make_call = Call
/// Creates a new mutable reference that contains `a`.
let new_ref a : forall s . a -> Eff [| st : State s | r |] (STRef s a) =
send_state (Call (\_ -> ref a))
/// Reads the values stored in the reference.
let read_ref ref : forall s . STRef s a -> Eff [| st : State s | r |] a =
send_state (Call (\_ -> load ref))
/// Writes a new value into the reference.
let write_ref a ref : forall s . a -> STRef s a -> Eff [| st : State s | r |] () =
send_state (Call (\_ -> ref <- a))
/// Eliminates the `State` effect
let run_state eff : (forall s . Eff [| st : State s | r |] a) -> Eff [| | r |] a =
let loop ve : forall s . Eff [| st : State s | r |] a -> Eff [| | r |] a =
match ve with
| Pure value -> wrap value
| Impure e f ->
match extract_state e with
| Call g ->
loop (f (g ()))
| rest ->
Impure (inject_rest rest) (loop << f)
loop eff
{
State,
STRef,
send_state,
new_ref,
read_ref,
write_ref,
run_state,
make_call,
}