gluon 0.18.2

A static, type inferred programming language for application embedding
Documentation
//! 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,
}