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