gluon 0.18.2

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