import { Ok, Error, toList, Empty as $Empty, prepend as listPrepend } from "../gleam.mjs"; import * as $list from "../gleam/list.mjs"; /** * Checks whether the result is an `Ok` value. * * ## Examples * * ```gleam * is_ok(Ok(1)) * // -> True * ``` * * ```gleam * is_ok(Error(Nil)) * // -> False * ``` */ export function is_ok(result) { if (result instanceof Ok) { return true; } else { return false; } } /** * Checks whether the result is an `Error` value. * * ## Examples * * ```gleam * is_error(Ok(1)) * // -> False * ``` * * ```gleam * is_error(Error(Nil)) * // -> True * ``` */ export function is_error(result) { if (result instanceof Ok) { return false; } else { return true; } } /** * Updates a value held within the `Ok` of a result by calling a given function * on it. * * If the result is an `Error` rather than `Ok` the function is not called and the * result stays the same. * * ## Examples * * ```gleam * map(over: Ok(1), with: fn(x) { x + 1 }) * // -> Ok(2) * ``` * * ```gleam * map(over: Error(1), with: fn(x) { x + 1 }) * // -> Error(1) * ``` */ export function map(result, fun) { if (result instanceof Ok) { let x = result[0]; return new Ok(fun(x)); } else { return result; } } /** * Updates a value held within the `Error` of a result by calling a given function * on it. * * If the result is `Ok` rather than `Error` the function is not called and the * result stays the same. * * ## Examples * * ```gleam * map_error(over: Error(1), with: fn(x) { x + 1 }) * // -> Error(2) * ``` * * ```gleam * map_error(over: Ok(1), with: fn(x) { x + 1 }) * // -> Ok(1) * ``` */ export function map_error(result, fun) { if (result instanceof Ok) { return result; } else { let error = result[0]; return new Error(fun(error)); } } /** * Merges a nested `Result` into a single layer. * * ## Examples * * ```gleam * flatten(Ok(Ok(1))) * // -> Ok(1) * ``` * * ```gleam * flatten(Ok(Error(""))) * // -> Error("") * ``` * * ```gleam * flatten(Error(Nil)) * // -> Error(Nil) * ``` */ export function flatten(result) { if (result instanceof Ok) { let x = result[0]; return x; } else { return result; } } /** * "Updates" an `Ok` result by passing its value to a function that yields a result, * and returning the yielded result. (This may "replace" the `Ok` with an `Error`.) * * If the input is an `Error` rather than an `Ok`, the function is not called and * the original `Error` is returned. * * This function is the equivalent of calling `map` followed by `flatten`, and * it is useful for chaining together multiple functions that may fail. * * ## Examples * * ```gleam * try(Ok(1), fn(x) { Ok(x + 1) }) * // -> Ok(2) * ``` * * ```gleam * try(Ok(1), fn(x) { Ok(#("a", x)) }) * // -> Ok(#("a", 1)) * ``` * * ```gleam * try(Ok(1), fn(_) { Error("Oh no") }) * // -> Error("Oh no") * ``` * * ```gleam * try(Error(Nil), fn(x) { Ok(x + 1) }) * // -> Error(Nil) * ``` */ export function try$(result, fun) { if (result instanceof Ok) { let x = result[0]; return fun(x); } else { return result; } } export function then$(result, fun) { return try$(result, fun); } /** * Extracts the `Ok` value from a result, returning a default value if the result * is an `Error`. * * ## Examples * * ```gleam * unwrap(Ok(1), 0) * // -> 1 * ``` * * ```gleam * unwrap(Error(""), 0) * // -> 0 * ``` */ export function unwrap(result, default$) { if (result instanceof Ok) { let v = result[0]; return v; } else { return default$; } } /** * Extracts the `Ok` value from a result, evaluating the default function if the result * is an `Error`. * * ## Examples * * ```gleam * lazy_unwrap(Ok(1), fn() { 0 }) * // -> 1 * ``` * * ```gleam * lazy_unwrap(Error(""), fn() { 0 }) * // -> 0 * ``` */ export function lazy_unwrap(result, default$) { if (result instanceof Ok) { let v = result[0]; return v; } else { return default$(); } } /** * Extracts the `Error` value from a result, returning a default value if the result * is an `Ok`. * * ## Examples * * ```gleam * unwrap_error(Error(1), 0) * // -> 1 * ``` * * ```gleam * unwrap_error(Ok(""), 0) * // -> 0 * ``` */ export function unwrap_error(result, default$) { if (result instanceof Ok) { return default$; } else { let e = result[0]; return e; } } export function unwrap_both(result) { if (result instanceof Ok) { let a = result[0]; return a; } else { let a = result[0]; return a; } } /** * Returns the first value if it is `Ok`, otherwise returns the second value. * * ## Examples * * ```gleam * or(Ok(1), Ok(2)) * // -> Ok(1) * ``` * * ```gleam * or(Ok(1), Error("Error 2")) * // -> Ok(1) * ``` * * ```gleam * or(Error("Error 1"), Ok(2)) * // -> Ok(2) * ``` * * ```gleam * or(Error("Error 1"), Error("Error 2")) * // -> Error("Error 2") * ``` */ export function or(first, second) { if (first instanceof Ok) { return first; } else { return second; } } /** * Returns the first value if it is `Ok`, otherwise evaluates the given function for a fallback value. * * If you need access to the initial error value, use `result.try_recover`. * * ## Examples * * ```gleam * lazy_or(Ok(1), fn() { Ok(2) }) * // -> Ok(1) * ``` * * ```gleam * lazy_or(Ok(1), fn() { Error("Error 2") }) * // -> Ok(1) * ``` * * ```gleam * lazy_or(Error("Error 1"), fn() { Ok(2) }) * // -> Ok(2) * ``` * * ```gleam * lazy_or(Error("Error 1"), fn() { Error("Error 2") }) * // -> Error("Error 2") * ``` */ export function lazy_or(first, second) { if (first instanceof Ok) { return first; } else { return second(); } } /** * Combines a list of results into a single result. * If all elements in the list are `Ok` then returns an `Ok` holding the list of values. * If any element is `Error` then returns the first error. * * ## Examples * * ```gleam * all([Ok(1), Ok(2)]) * // -> Ok([1, 2]) * ``` * * ```gleam * all([Ok(1), Error("e")]) * // -> Error("e") * ``` */ export function all(results) { return $list.try_map(results, (result) => { return result; }); } function partition_loop(loop$results, loop$oks, loop$errors) { while (true) { let results = loop$results; let oks = loop$oks; let errors = loop$errors; if (results instanceof $Empty) { return [oks, errors]; } else { let $ = results.head; if ($ instanceof Ok) { let rest = results.tail; let a = $[0]; loop$results = rest; loop$oks = listPrepend(a, oks); loop$errors = errors; } else { let rest = results.tail; let e = $[0]; loop$results = rest; loop$oks = oks; loop$errors = listPrepend(e, errors); } } } } /** * Given a list of results, returns a pair where the first element is a list * of all the values inside `Ok` and the second element is a list with all the * values inside `Error`. The values in both lists appear in reverse order with * respect to their position in the original list of results. * * ## Examples * * ```gleam * partition([Ok(1), Error("a"), Error("b"), Ok(2)]) * // -> #([2, 1], ["b", "a"]) * ``` */ export function partition(results) { return partition_loop(results, toList([]), toList([])); } /** * Replace the value within a result * * ## Examples * * ```gleam * replace(Ok(1), Nil) * // -> Ok(Nil) * ``` * * ```gleam * replace(Error(1), Nil) * // -> Error(1) * ``` */ export function replace(result, value) { if (result instanceof Ok) { return new Ok(value); } else { return result; } } /** * Replace the error within a result * * ## Examples * * ```gleam * replace_error(Error(1), Nil) * // -> Error(Nil) * ``` * * ```gleam * replace_error(Ok(1), Nil) * // -> Ok(1) * ``` */ export function replace_error(result, error) { if (result instanceof Ok) { return result; } else { return new Error(error); } } /** * Given a list of results, returns only the values inside `Ok`. * * ## Examples * * ```gleam * values([Ok(1), Error("a"), Ok(3)]) * // -> [1, 3] * ``` */ export function values(results) { return $list.filter_map(results, (result) => { return result; }); } /** * Updates a value held within the `Error` of a result by calling a given function * on it, where the given function also returns a result. The two results are * then merged together into one result. * * If the result is an `Ok` rather than `Error` the function is not called and the * result stays the same. * * This function is useful for chaining together computations that may fail * and trying to recover from possible errors. * * If you do not need access to the initial error value, use `result.lazy_or`. * * ## Examples * * ```gleam * Ok(1) |> try_recover(with: fn(_) { Error("failed to recover") }) * // -> Ok(1) * ``` * * ```gleam * Error(1) |> try_recover(with: fn(error) { Ok(error + 1) }) * // -> Ok(2) * ``` * * ```gleam * Error(1) |> try_recover(with: fn(error) { Error("failed to recover") }) * // -> Error("failed to recover") * ``` */ export function try_recover(result, fun) { if (result instanceof Ok) { return result; } else { let error = result[0]; return fun(error); } }