gluon 0.18.2

A static, type inferred programming language for application embedding
Documentation
//! Implementation of the `Reader` effect
let { Eff, inject_rest, ? } = import! std.effect
let { map } = import! std.functor
let { wrap } = import! std.applicative
let { (<<) } = import! std.function

/// The `Reader` effects provides a shared, immutable environment for the effectful functions using it
type Reader s r a =
    | Ask : Reader s r s
    .. r

let extract_reader x : forall s . [| reader : Reader s | r |] a -> Reader s r a = convert_variant! x

let send_reader f : Reader s r a -> Eff [| reader : Reader s | r |] a =
    Impure (convert_effect! reader f) Pure

/// Retrieve the value from the environment
let ask : forall s . Eff [| reader : Reader s | r |] s =
    send_reader Ask

/// Retrieve the value from the environment while applying `f` to it
let asks f : forall s . (s -> a) -> Eff [| reader : Reader s | r |] a =
    map f ask

/// Runs a computation in a modified environment.
let local f eff : forall s .
        (s -> s) -> Eff [| reader : Reader s | r |] a -> Eff [| reader : Reader s | r |] a
    =
    do s = asks f
    let s : s = s
    // FIXME Remove after this does not affect inference
    let loop ve : Eff [| reader : Reader s | r |] a -> Eff [| reader : Reader s | r |] a =
        match ve with
        | Pure value -> wrap value
        | Impure e f ->
            match extract_reader e with
            | Ask ->
                loop (f s)
            | rest ->
                Impure (inject_rest rest) (loop << f)
    loop eff

/// Eliminates the `Reader` effect
let run_reader s eff : forall s . s -> Eff [| reader : Reader s | r |] a -> Eff [| | r |] a =
    let loop reader ve : s -> Eff [| reader : Reader s | r |] a -> Eff [| | r |] a =
        match ve with
        | Pure value -> wrap value
        | Impure e f ->
            match extract_reader e with
            | Ask ->
                loop reader (f reader)
            | rest ->
                Impure (inject_rest rest) (loop reader << f)
    loop s eff
{
    Reader,
    ask,
    asks,
    local,
    run_reader,
}