//// Result represents the result of something that may succeed or not.
//// `Ok` means it was successful, `Error` means it was not successful.
import gleeps/stdlib/list
/// Checks whether the result is an `Ok` value.
///
/// ## Examples
///
/// ```gleam
/// assert is_ok(Ok(1))
/// ```
///
/// ```gleam
/// assert !is_ok(Error(Nil))
/// ```
///
pub fn is_ok(result: Result(a, e)) -> Bool {
case result {
Error(_) -> False
Ok(_) -> True
}
}
/// Checks whether the result is an `Error` value.
///
/// ## Examples
///
/// ```gleam
/// assert !is_error(Ok(1))
/// ```
///
/// ```gleam
/// assert is_error(Error(Nil))
/// ```
///
pub fn is_error(result: Result(a, e)) -> Bool {
case result {
Ok(_) -> False
Error(_) -> 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
/// assert map(over: Ok(1), with: fn(x) { x + 1 }) == Ok(2)
/// ```
///
/// ```gleam
/// assert map(over: Error(1), with: fn(x) { x + 1 }) == Error(1)
/// ```
///
pub fn map(over result: Result(a, e), with fun: fn(a) -> b) -> Result(b, e) {
case result {
Ok(x) -> Ok(fun(x))
Error(e) -> Error(e)
}
}
/// 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
/// assert map_error(over: Error(1), with: fn(x) { x + 1 }) == Error(2)
/// ```
///
/// ```gleam
/// assert map_error(over: Ok(1), with: fn(x) { x + 1 }) == Ok(1)
/// ```
///
pub fn map_error(
over result: Result(a, e),
with fun: fn(e) -> f,
) -> Result(a, f) {
case result {
Ok(x) -> Ok(x)
Error(error) -> Error(fun(error))
}
}
/// Merges a nested `Result` into a single layer.
///
/// ## Examples
///
/// ```gleam
/// assert flatten(Ok(Ok(1))) == Ok(1)
/// ```
///
/// ```gleam
/// assert flatten(Ok(Error(""))) == Error("")
/// ```
///
/// ```gleam
/// assert flatten(Error(Nil)) == Error(Nil)
/// ```
///
pub fn flatten(result: Result(Result(a, e), e)) -> Result(a, e) {
case result {
Ok(x) -> x
Error(error) -> Error(error)
}
}
/// "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
/// assert try(Ok(1), fn(x) { Ok(x + 1) }) == Ok(2)
/// ```
///
/// ```gleam
/// assert try(Ok(1), fn(x) { Ok(#("a", x)) }) == Ok(#("a", 1))
/// ```
///
/// ```gleam
/// assert try(Ok(1), fn(_) { Error("Oh no") }) == Error("Oh no")
/// ```
///
/// ```gleam
/// assert try(Error(Nil), fn(x) { Ok(x + 1) }) == Error(Nil)
/// ```
///
pub fn try(
result: Result(a, e),
apply fun: fn(a) -> Result(b, e),
) -> Result(b, e) {
case result {
Ok(x) -> fun(x)
Error(e) -> Error(e)
}
}
/// Extracts the `Ok` value from a result, returning a default value if the result
/// is an `Error`.
///
/// ## Examples
///
/// ```gleam
/// assert unwrap(Ok(1), 0) == 1
/// ```
///
/// ```gleam
/// assert unwrap(Error(""), 0) == 0
/// ```
///
pub fn unwrap(result: Result(a, e), or default: a) -> a {
case result {
Ok(v) -> v
Error(_) -> default
}
}
/// Extracts the `Ok` value from a result, evaluating the default function if the result
/// is an `Error`.
///
/// ## Examples
///
/// ```gleam
/// assert lazy_unwrap(Ok(1), fn() { 0 }) == 1
/// ```
///
/// ```gleam
/// assert lazy_unwrap(Error(""), fn() { 0 }) == 0
/// ```
///
pub fn lazy_unwrap(result: Result(a, e), or default: fn() -> a) -> a {
case result {
Ok(v) -> v
Error(_) -> default()
}
}
/// Extracts the `Error` value from a result, returning a default value if the result
/// is an `Ok`.
///
/// ## Examples
///
/// ```gleam
/// assert unwrap_error(Error(1), 0) == 1
/// ```
///
/// ```gleam
/// assert unwrap_error(Ok(""), 0) == 0
/// ```
///
pub fn unwrap_error(result: Result(a, e), or default: e) -> e {
case result {
Ok(_) -> default
Error(e) -> e
}
}
/// Returns the first value if it is `Ok`, otherwise returns the second value.
///
/// ## Examples
///
/// ```gleam
/// assert or(Ok(1), Ok(2)) == Ok(1)
/// ```
///
/// ```gleam
/// assert or(Ok(1), Error("Error 2")) == Ok(1)
/// ```
///
/// ```gleam
/// assert or(Error("Error 1"), Ok(2)) == Ok(2)
/// ```
///
/// ```gleam
/// assert or(Error("Error 1"), Error("Error 2")) == Error("Error 2")
/// ```
///
pub fn or(first: Result(a, e), second: Result(a, e)) -> Result(a, e) {
case first {
Ok(_) -> first
Error(_) -> 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
/// assert lazy_or(Ok(1), fn() { Ok(2) }) == Ok(1)
/// ```
///
/// ```gleam
/// assert lazy_or(Ok(1), fn() { Error("Error 2") }) == Ok(1)
/// ```
///
/// ```gleam
/// assert lazy_or(Error("Error 1"), fn() { Ok(2) }) == Ok(2)
/// ```
///
/// ```gleam
/// assert lazy_or(Error("Error 1"), fn() { Error("Error 2") })
/// == Error("Error 2")
/// ```
///
pub fn lazy_or(
first: Result(a, e),
second: fn() -> Result(a, e),
) -> Result(a, e) {
case first {
Ok(_) -> first
Error(_) -> 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
/// assert all([Ok(1), Ok(2)]) == Ok([1, 2])
/// ```
///
/// ```gleam
/// assert all([Ok(1), Error("e")]) == Error("e")
/// ```
///
pub fn all(results: List(Result(a, e))) -> Result(List(a), e) {
list.try_map(results, fn(result) { result })
}
/// 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
/// assert partition([Ok(1), Error("a"), Error("b"), Ok(2)])
/// == #([2, 1], ["b", "a"])
/// ```
///
pub fn partition(results: List(Result(a, e))) -> #(List(a), List(e)) {
partition_loop(results, [], [])
}
fn partition_loop(results: List(Result(a, e)), oks: List(a), errors: List(e)) {
case results {
[] -> #(oks, errors)
[Ok(a), ..rest] -> partition_loop(rest, [a, ..oks], errors)
[Error(e), ..rest] -> partition_loop(rest, oks, [e, ..errors])
}
}
/// Replace the value within a result
///
/// ## Examples
///
/// ```gleam
/// assert replace(Ok(1), Nil) == Ok(Nil)
/// ```
///
/// ```gleam
/// assert replace(Error(1), Nil) == Error(1)
/// ```
///
pub fn replace(result: Result(a, e), value: b) -> Result(b, e) {
case result {
Ok(_) -> Ok(value)
Error(error) -> Error(error)
}
}
/// Replace the error within a result
///
/// ## Examples
///
/// ```gleam
/// assert replace_error(Error(1), Nil) == Error(Nil)
/// ```
///
/// ```gleam
/// assert replace_error(Ok(1), Nil) == Ok(1)
/// ```
///
pub fn replace_error(result: Result(a, e), error: f) -> Result(a, f) {
case result {
Ok(x) -> Ok(x)
Error(_) -> Error(error)
}
}
/// Given a list of results, returns only the values inside `Ok`.
///
/// ## Examples
///
/// ```gleam
/// assert values([Ok(1), Error("a"), Ok(3)]) == [1, 3]
/// ```
///
pub fn values(results: List(Result(a, e))) -> List(a) {
list.filter_map(results, fn(result) { 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
/// assert Ok(1)
/// |> try_recover(with: fn(_) { Error("failed to recover") })
/// == Ok(1)
/// ```
///
/// ```gleam
/// assert Error(1)
/// |> try_recover(with: fn(error) { Ok(error + 1) })
/// == Ok(2)
/// ```
///
/// ```gleam
/// assert Error(1)
/// |> try_recover(with: fn(error) { Error("failed to recover") })
/// == Error("failed to recover")
/// ```
///
pub fn try_recover(
result: Result(a, e),
with fun: fn(e) -> Result(a, f),
) -> Result(a, f) {
case result {
Ok(value) -> Ok(value)
Error(error) -> fun(error)
}
}