//@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,
}