gluon 0.18.2

A static, type inferred programming language for application embedding
Documentation
//@NO-IMPLICIT-PRELUDE
//! Implementation of the `Lift` effect
let { error } = import! std.prim
let { Eff, inject_rest } = import! std.effect
let { wrap } = import! std.applicative
let { Monad, flat_map } = import! std.monad
let { (<<) } = import! std.function

/// The `Lift` effect allows a regular monad (usually `IO`) to be used in an `Eff` monad
type Lift m r a =
    | Lift (m a)
    .. r

let send_lift f : Lift m r a -> Eff [| lift : Lift m | r |] a = Impure (convert_effect! lift f) Pure

let extract_state x : forall m . [| lift : Lift m | r |] a -> Lift m r a = convert_variant! x

/// "Lifts" a monadic action into the `Eff` monad. Since monads do not compose this can only be
let lift m : m a -> Eff [| lift : Lift m | r |] a = send_lift (Lift m)

/// Eliminates the lifted monad `m`. Can only be used once all other effects have been eliminated
let run_lift eff : [Monad m] -> Eff [| lift : Lift m |] a -> m a =
    let loop ve : Eff [| lift : Lift m |] a -> m a =
        match ve with
        | Pure v -> wrap v
        | Impure e f ->
            match extract_state e with
            | Lift m ->
                do a = m
                loop (f a)
            | _ -> error "Impossible: Lift should always be the only remaining variant"
    loop eff

{
    Lift,

    lift,
    run_lift,
}