gluon 0.18.2

A static, type inferred programming language for application embedding
Documentation
//! Implementation of the `Error` effect

let { Eff, inject_rest, ? } = import! std.effect
let { Result } = import! std.result
let { Option } = import! std.option
let { (<<) } = import! std.function
let { wrap } = import! std.applicative

/// The `Error` effects adds "exceptions" to the `Eff` monad
type Error e r a =
    | Error e
    .. r

let send_error f : Error e r a -> Eff [| error : Error e | r |] a =
    Impure (convert_effect! error f) Pure

let extract_error x : forall e . [| error : Error e | r |] a -> Error e r a = convert_variant! x

/// Throws the error `e`
let throw e : e -> Eff [| error : Error e | r |] a = send_error (Error e)

/// Moves a `Result` into the `Eff` monad
let ok_or_throw r : Result e t -> Eff [| error : Error e | r |] t =
    match r with
    | Ok t -> wrap t
    | Err e -> throw e

let some_or_throw e o : e -> Option a -> Eff [| error : Error e | r |] a =
    match o with
    | Some x -> wrap x
    | None -> throw e

/// Eliminates the `Error` effect and returns a `Result`
let run_error eff : forall e . Eff [| error : Error e | r |] a -> Eff [| | r |] (Result e a) =
    let loop ve : Eff [| error : Error e | r |] a -> Eff [| | r |] (Result e a) =
        match ve with
        | Pure v -> wrap (Ok v)
        | Impure e f ->
            match extract_error e with
            | Error err ->
                wrap (Err err)
            | rest ->
                Impure (inject_rest rest) (loop << f)
    loop eff

/// Catches an "exception", allowing the effect to continue executing
let catch eff handler : forall e .
        Eff [| error : Error e | r |] a
            -> (e -> Eff [| error : Error e | r |] a)
            -> Eff [| error : Error e | r |] a
    =
    let loop ve : Eff [| error : Error e | r |] a -> Eff [| error : Error e | r |] a =
        match ve with
        | Pure v -> wrap v
        | Impure e f ->
            match extract_error e with
            | Error err ->
                handler err
            | rest ->
                Impure e (loop << f)
    loop eff


{
    Error,

    catch,
    throw,
    ok_or_throw,
    some_or_throw,
    run_error,
}