Current section

Files

Jump to
on src on.gleam
Raw

src/on.gleam

import gleam/option.{type Option, Some, None}
// ************
// * Result/1 *
// ************
/// Given a Result(a, b) and a callback f(a) -> Result(c, b) applies
/// the callback if the Result has type Ok else maps the Error variant
/// of type Result(a, b) to the Error variant of type Result(c, b).
///
/// Equivalent to result.try and to error_ok(_, fn(e) -> {Error(e)}, _).
///
/// ### Example 1
///
/// ```gleam
/// use ok_payload <- on.ok(Ok(3))
/// // -> execution proceeds, ok_payload == 3; the current scope must
/// // return a Result(c, b) for some c, b
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use ok_payload <- on.ok(Error("Joe"))
/// // -> execution discontinues, scope returns Error("Joe")
/// ```
///
pub fn ok(
result: Result(a, b),
on_ok f2: fn(a) -> Result(c, b),
) -> Result(c, b) {
case result {
Error(e) -> Error(e)
Ok(a) -> f2(a)
}
}
/// Given a Result(a, b) and a callback f(b) -> Result(a, c) applies
/// the callback if the Result has type Error else maps the Ok variant
/// of type Result(a, b) to the Ok variant of type Result(c, b).
///
/// Equivalent to on.ok_error(_, fn(o) -> {Ok(o)}, _).
///
/// ### Example 1
///
/// ```gleam
/// use error_payload <- on.error(Ok(3))
/// // -> execution discontinues, scope returns Ok(3)
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use error_payload <- on.error(Error("Joe"))
/// // -> execution proceeds, error_payload == "Joe";
/// // the scope must return a Result(a, c)
/// ```
///
pub fn error(
result: Result(a, b),
on_error f2: fn(b) -> Result(a, c),
) -> Result(a, c) {
case result {
Ok(a) -> Ok(a)
Error(e) -> f2(e)
}
}
// ************
// * Result/2 *
// ************
/// Given a Result(a, b), a value of type c and a callback f(a) -> c,
/// returns the value of type c if the Result is an Error(_), else the
/// evaluation of the second callback at a1 if the Result is Ok(a1).
///
/// ### Example 1
///
/// ```gleam
/// use ok_payload <- on.eager_error_ok(
/// Ok(3),
/// on_error: option.None
/// )
/// // -> execution proceeds, ok_payload == 3; the scope must return
/// // an Option(a) value to match the on_error return value
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use ok_payload <- on.eager_error_ok(
/// Error("Joe"),
/// on_error: option.None
/// )
/// // -> execution discontinues, scope returns option.None
/// ```
///
pub fn eager_error_ok(
result: Result(a, b),
on_error c: c,
on_ok f2: fn(a) -> c,
) -> c {
case result {
Error(_) -> c
Ok(a) -> f2(a)
}
}
/// Given a Result(a, b) and callbacks f(b) -> c, f(a) -> c
/// returns the evaluation of the first callback at b1 if the
/// Result is Error(b1) and the evaluation of the second callback
/// at a1 if the Result is Ok(a1).
///
/// ### Example 1
///
/// ```gleam
/// use ok_payload <- on.error_ok(
/// Ok(3),
/// on_error: fn(e) { "hi " <> e <> "!" },
/// )
/// // -> execution proceeds, ok_payload == 3; the scope must return
/// // a String to match the return value of the on_error callback
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use ok_payload <- on.error_ok(
/// Error("Joe"),
/// on_error: fn(e) { "hi " <> e <> "!" },
/// )
/// // -> execution discontinues, scope returns "hi Joe!"
/// ```
///
pub fn error_ok(
result: Result(a, b),
on_error f1: fn(b) -> c,
on_ok f2: fn(a) -> c,
) -> c {
case result {
Error(b) -> f1(b)
Ok(a) -> f2(a)
}
}
/// Given a Result(a, b), a value of type c and a callback f(b) -> c,
/// returns the value of type c if the Result is an Ok(_), else the
/// evaluation of the second callback at b1 if the Result is Error(b1).
///
/// ### Example 1
///
/// ```gleam
/// use error_payload <- on.eager_ok_error(
/// Ok(3),
/// on_ok: 7,
/// )
/// // -> execution discontinues, scope returns 7
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use error_payload <- on.eager_ok_error(
/// Error("Joe"),
/// on_ok: 7,
/// )
/// // -> execution proceeds, error_payload == "Joe"; the scope
/// // must return an Int to match the on_ok return value
/// ```
///
pub fn eager_ok_error(
result: Result(a, b),
on_ok c: c,
on_error f2: fn(b) -> c,
) -> c {
case result {
Ok(_) -> c
Error(b) -> f2(b)
}
}
/// Given a Result(a, b) and callbacks f(b) -> c, f(a) -> c
/// returns the evaluation of the first callback at a1 if the
/// Result is Ok(a1) and the evaluation of the second callback
/// at b1 if the Result is Error(b1).
///
/// ### Example 1
///
/// ```gleam
/// use error_payload <- on.ok_error(
/// Ok(3),
/// on_ok: fn(x) { x + 1 },
/// )
/// // -> execution discontinues, scope returns 4
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use error_payload <- on.ok_error(
/// Error("Joe"),
/// on_ok: fn(x) { x + 1 },
/// )
/// // -> execution proceeds, error_payload == "Joe"; the scope
/// // must return an Int to match the return value of the on_ok
/// // callback
/// ```
///
pub fn ok_error(
result: Result(a, b),
on_ok f1: fn(a) -> c,
on_error f2: fn(b) -> c,
) -> c {
case result {
Ok(a) -> f1(a)
Error(b) -> f2(b)
}
}
// **********
// * Bool/1 *
// **********
/// Given a Bool returns False if the bool is False, else
/// returns a lazily evaluated callback.
///
/// Equivalent to on.eager_false_true(_, False, _).
///
/// ### Example 1
///
/// ```gleam
/// use <- on.true(True)
/// // -> execution proceeds, scope must return a Bool
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.true(False)
/// // -> execution discontinues, scope returns False
/// ```
///
pub fn true(
bool: Bool,
on_true f2: fn() -> Bool,
) -> Bool {
case bool {
False -> False
True -> f2()
}
}
/// Given a Bool returns True if the bool is True, else
/// returns a lazily evaluated callback.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.false(True)
/// // -> execution discontinues, scope returns True
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.false(False)
/// // -> execution proceeds, scope must return a Bool
/// ```
///
pub fn false(
bool: Bool,
on_false f2: fn() -> Bool,
) -> Bool {
case bool {
True -> True
False -> f2()
}
}
// **********
// * Bool/2 *
// **********
/// Given a Bool, a value of type c and a callback f() -> c,
/// returns the value of type c if the bool is False, else the
/// evaluation of the callback.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.eager_false_true(
/// True,
/// on_false: "Joe",
/// )
/// // -> execution proceeds, the scope must return a String to
/// // match the return value of the on_false argument
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.eager_false_true(
/// False,
/// on_false: "Joe",
/// )
/// // -> execution discontinues, scope returns "Joe"
/// ```
///
pub fn eager_false_true(
bool: Bool,
on_false c: c,
on_true f2: fn() -> c,
) -> c {
case bool {
False -> c
True -> f2()
}
}
/// Given a Bool and two callbacks f() -> c returns the
/// evaluation of the first callback if the bool is False,
/// else the second callback.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.false_true(
/// True,
/// on_false: fn() { "Joe" },
/// )
/// // -> execution proceeds, the scope must return a String
/// // to match the return value of the on_false argument
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.false_true(
/// False,
/// on_false: fn() { "Joe" },
/// )
/// // -> execution discontinues, scope returns "Joe"
/// ```
///
pub fn false_true(
bool: Bool,
on_false f1: fn() -> c,
on_true f2: fn() -> c,
) -> c {
case bool {
False -> f1()
True -> f2()
}
}
/// Given a Bool, a value of type c and a callback f() -> c,
/// returns the value of type c if the bool is True, else the
/// evaluation of the callback.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.eager_true_false(
/// True,
/// on_true: "Joe",
/// )
/// // -> execution discontinues, scope returns "Joe"
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.eager_true_false(
/// False,
/// on_true: "Joe",
/// )
/// // -> execution proceeds, the scope must return a String to
/// // match the return value of the on_true argument
/// ```
///
pub fn eager_true_false(
bool: Bool,
on_true c: c,
on_false f2: fn() -> c,
) -> c {
case bool {
True -> c
False -> f2()
}
}
/// Given a Bool and two callbacks f() -> c returns the
/// evaluation of the first callback if the bool is True,
/// else the second callback.
///
///
/// ### Example 1
///
/// ```gleam
/// use <- on.true_false(
/// True,
/// on_true: fn() { "Joe" },
/// )
/// // -> execution discontinues, scope returns "Joe"
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.true_false(
/// False,
/// on_true: fn() { "Joe" },
/// )
/// // -> execution proceeds, the scope must return a String to
/// // match the return value of the on_false argument
/// ```
///
pub fn true_false(
bool: Bool,
on_true f1: fn() -> c,
on_false f2: fn() -> c,
) -> c {
case bool {
True -> f1()
False -> f2()
}
}
// ************
// * Option/1 *
// ************
/// Given an Option(a) and a callback f(a) -> Option(c)
/// applies the callback to the payload a if the option is Some(a),
/// else returns None.
///
/// Equivalent to:
/// - on.eager_none_some(_, None, _).
/// - option.then
///
/// ### Example 1
///
/// ```gleam
/// use payload <- on.some(Some(3))
/// // -> execution proceeds, payload == 3; the scope must return
/// // an Option(c)
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use payload <- on.some(None)
/// // -> execution discontinues, scope returns None
/// ```
///
pub fn some(
option: Option(a),
on_some f2: fn(a) -> Option(c),
) -> Option(c) {
case option {
None -> None
Some(a) -> f2(a)
}
}
/// Given an Option(a) and a callback f() -> Option(a), applies
/// the callback if the option is None, else returns the option
/// unchanged.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.none(Some(3))
/// // -> execution discontinues, scope returns Some(3)
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.none(None)
/// // -> execution proceeds, the scope must return an Option(a)
/// ```
///
pub fn none(
option: Option(a),
on_none f2: fn() -> Option(a),
) -> Option(a) {
case option {
Some(a) -> Some(a)
None -> f2()
}
}
// ************
// * Option/2 *
// ************
/// Given an Option(a), a value of type c and a callback f(a) -> c,
/// returns the value of type c if the option is None, else
/// applies the callback to the option's payload.
///
/// ## Examples
///
/// ```gleam
/// use payload <- on.eager_none_some(
/// Some(3),
/// on_none: "Bob",
/// )
/// // -> execution proceeds, payload == 3; the scope must return a
/// // String to match the return value of the on_none return value
/// ```
///
/// ```gleam
/// use payload <- on.eager_none_some(
/// None,
/// on_none: "Bob",
/// )
/// // -> execution discontinues, scope returns "Bob"
/// ```
///
pub fn eager_none_some(
option: Option(a),
on_none c: c,
on_some f2: fn(a) -> c,
) -> c {
case option {
None -> c
Some(a) -> f2(a)
}
}
/// Given an Option(a), a callback f() -> c and a callback
/// f(a) -> c evaluates the first callback if the option is
/// None, else evaluates the second callback on the option's
/// payload.
///
/// ### Example 1
///
/// ```gleam
/// use payload <- on.none_some(
/// Some(3),
/// on_none: fn() { "Bob" },
/// )
/// // -> execution proceeds, payload == 3; the scope must return
/// // a String to match the return value of the on_none return
/// // value
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use payload <- on.none_some(
/// None,
/// on_none: fn() { "Bob" },
/// )
/// // -> execution discontinues, scope returns "Bob"
/// ```
///
pub fn none_some(
option: Option(a),
on_none f1: fn() -> c,
on_some f2: fn(a) -> c,
) -> c {
case option {
None -> f1()
Some(a) -> f2(a)
}
}
/// Given an Option(a), a value of type c and a callback
/// f() -> c, returns the value if the Option is Some(x),
/// else evaluates the second callback if the option is
/// None.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.eager_some_none(
/// Some(3),
/// on_some: "q",
/// )
/// // -> execution discontinues, scope returns "q"
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.eager_some_none(
/// None,
/// on_some: "q",
/// )
/// // -> execution proceeds, the scope must return a String to match
/// // the on_some return value
/// ```
///
pub fn eager_some_none(
option: Option(a),
on_some c: c,
on_none f2: fn() -> c,
) -> c {
case option {
Some(_) -> c
None -> f2()
}
}
/// Given an Option(a), a callback f(a) -> c and a callback
/// f() -> c, evaluates the first callback on the option's
/// payload, else evaluates the second callback if the option
/// is None.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.some_none(
/// Some(3),
/// on_some: fn(x) { x + 1 },
/// )
/// // -> execution discontinues, scope returns 4
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.some_none(
/// None,
/// on_some: fn(x) { x + 1 },
/// )
/// // -> execution proceeds, the scope must return an Int to match
/// // the return value of the on_some return value
/// ```
///
pub fn some_none(
option: Option(a),
on_some f1: fn(a) -> c,
on_none f2: fn() -> c,
) -> c {
case option {
Some(a) -> f1(a)
None -> f2()
}
}
// **********
// * List/1 *
// **********
/// Given a List(a) and a callback
/// f(a, List(a)) -> List(c), returns the empty list if the
/// list is empty, else evaluates the callback on (first, rest)
/// where 'first' is the first element and 'tail' is the tail of
/// the list.
///
/// ### Example 1
///
/// ```gleam
/// use first, rest <- on.nonempty([1, 4, 7])
/// // -> execution proceeds, first == 1, rest == [1, 7];
/// // scope must return a List(c)
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, rest <- on.nonempty([])
/// // -> execution discontinues, scope returns []
/// ```
///
pub fn nonempty(
list: List(a),
on_nonempty f2: fn(a, List(a)) -> List(c),
) -> List(c) {
case list {
[] -> []
[first, ..rest] -> f2(first, rest)
}
}
/// Given a List(a) and a callback f() -> List(a)
/// returns the list if the is nonempty, else evaluates
/// the callback.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.empty([1, 4, 7])
/// // -> execution discontinues, scope returns [1, 4, 7]
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.empty([])
/// // -> execution proceeds, the scope must return a List(c)
/// ```
///
pub fn empty(
list: List(a),
on_empty f2: fn() -> List(a),
) -> List(a) {
case list {
[_, .._] -> list
[] -> f2()
}
}
// **********
// * List/2 *
// **********
/// Given a List(a), a value of type c, and callback
/// f(a, List(a)) -> c, returns either the value of type c
/// if the list is empty or else applies the callback to
/// the head: a and tail: List(a) of the list.
///
/// ### Example 1
///
/// ```gleam
/// use first, rest <- on.eager_empty_nonempty(
/// [1, 4, 7],
/// on_empty: "Joe",
/// )
/// // -> execution proceeds, first == 1, rest == [4, 7];
/// // scope must return a String to match the empty list
/// // return value
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, rest <- on.eager_empty_nonempty(
/// [],
/// on_empty: "Joe",
/// )
/// // -> execution discontinues, scope returns "Joe"
/// ```
///
pub fn eager_empty_nonempty(
list: List(a),
on_empty c: c,
on_nonempty f2: fn(a, List(a)) -> c,
) -> c {
case list {
[] -> c
[first, ..rest] -> f2(first, rest)
}
}
/// Given a List(a), a callback fn() -> c and a callback
/// f(a, List(a)) -> c, evaluates the first callback if the
/// list is empty else applies the second callback to the
/// head: a and tail: List(a) of the list.
///
/// ### Example 1
///
/// ```gleam
/// use first, rest <- on.empty_nonempty(
/// [1, 4, 7],
/// on_empty: fn() { "Joe" },
/// )
/// // -> execution proceeds, first == 1, rest == [4, 7];
/// // scope must return a String to match the empty list
/// // callback return value
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, rest <- on.empty_nonempty(
/// [],
/// on_empty: fn() { "Joe" },
/// )
/// // -> execution discontinues, scope returns "Joe"
/// ```
///
pub fn empty_nonempty(
list: List(a),
on_empty f1: fn() -> c,
on_nonempty f2: fn(a, List(a)) -> c,
) -> c {
case list {
[] -> f1()
[first, ..rest] -> f2(first, rest)
}
}
/// Given a List(a), a value of type c, and
/// a callback f() -> c, returns either the value of type
/// c if the list is nonempty, and otherwise evaluates the
/// second callback, if the list is empty.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.eager_nonempty_empty(
/// [1, 4, 7],
/// "z",
/// )
/// // -> execution discontinues, scope returns "z"
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.eager_nonempty_empty(
/// [],
/// "z",
/// )
/// // -> execution proceeds, the scope must return a
/// // String to match the eager nonempty return value
/// ```
///
pub fn eager_nonempty_empty(
list: List(a),
on_nonempty c: c,
on_empty f2: fn() -> c,
) -> c {
case list {
[_, ..] -> c
[] -> f2()
}
}
/// Given a List(a), a callback f(a, List(a)) -> c, and
/// a callback f() -> c, returns either the first callback
/// evaluated on the first element and tail of the list if
/// the list is nonempty, and otherwise evaluates the
/// second callback, if the list is empty.
///
/// ### Example 1
///
/// ```gleam
/// use <- on.nonempty_empty(
/// [1, 4, 7],
/// fn(first, _rest) { first + 1 },
/// )
/// // -> execution discontinues, scope returns 2
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.nonempty_empty(
/// [],
/// fn(first, _rest) { first + 1 },
/// )
/// // -> execution proceeds, the scope must return an
/// // integer to match the return value of the first
/// // callback
/// ```
///
pub fn nonempty_empty(
list: List(a),
on_nonempty f1: fn(a, List(a)) -> c,
on_empty f2: fn() -> c,
) -> c {
case list {
[first, ..rest] -> f1(first, rest)
[] -> f2()
}
}
// **********
// * List/3 *
// **********
/// Given a List(a), two values c1 and c2of type c, and a callback
/// f(a, a, List(a)) -> c, returns:
///
/// - the c1 if the list is empty
/// - the c2 if the list has one element
/// - the callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
///
/// ### Example 1
///
/// ```gleam
/// use first, second, ..rest <- on.eager_empty_eager_singleton_gt1(
/// [1, 4, 7],
/// on_empty: 0,
/// on_singleton: 300,
/// )
/// // -> execution proceeds, first == 1, second == 4, rest == [7];
/// // scope must return an Int to match the on_empty, on_singleton callbacks
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, second, ..rest <- on.eager_empty_eager_singleton_gt1(
/// [4],
/// on_empty: 0,
/// on_singleton: 300,
/// )
/// // -> execution discontinues, scope resturns 300
/// ```
///
pub fn eager_empty_eager_singleton_gt1(
list: List(a),
on_empty c1: c,
on_singleton c2: c,
on_gt1 f3: fn(a, a, List(a)) -> c,
) -> c {
case list {
[] -> c1
[_] -> c2
[first, second, ..rest] -> f3(first, second, rest)
}
}
/// Given a List(a), a value of type c, and callbacks
/// f(a) -> c, f(a, a, List(a)) -> c, returns:
///
/// - the value of type c if the list is empty
/// - the first callback evaluated with argument a1 if the list as the form [a1]
/// - the second callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
///
/// ### Example 1
///
/// ```gleam
/// use first, second, ..rest <- on.eager_empty_singleton_gt1(
/// [1, 4, 7],
/// on_empty: 0,
/// on_singleton: fn(first) { first },
/// )
/// // -> execution proceeds, first == 1, second == 4, rest == [7];
/// // scope must return an Int to match the on_empty, on_singleton callbacks
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, second, ..rest <- on.eager_empty_singleton_gt1(
/// [4],
/// on_empty: 0,
/// on_singleton: fn(first) { first },
/// )
/// // -> execution discontinues, scope resturns 4
/// ```
///
pub fn eager_empty_singleton_gt1(
list: List(a),
on_empty c: c,
on_singleton f2: fn(a) -> c,
on_gt1 f3: fn(a, a, List(a)) -> c,
) -> c {
case list {
[] -> c
[first] -> f2(first)
[first, second, ..rest] -> f3(first, second, rest)
}
}
/// Given a List(a), a value c1 of type c and a callback
/// f(a, a, List(a)) -> c, returns:
///
/// - the evaluation of the first callback if the list is empty
/// - c1 if the list has one element
/// - the third callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
///
/// ### Example 1
///
/// ```gleam
/// use first, second, ..rest <- on.empty_eager_singleton_gt1(
/// [1, 4, 7],
/// on_empty: fn() { 200 },
/// on_singleton: 300,
/// )
/// // -> execution proceeds, first == 1, second == 4, rest == [7];
/// // scope must return an Int to match the on_empty, on_singleton callbacks
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, second, ..rest <- on.empty_singleton_gt1(
/// [4],
/// on_empty: fn() { 200 },
/// on_singleton: 300,
/// )
/// // -> execution discontinues, scope resturns 300
/// ```
///
pub fn empty_eager_singleton_gt1(
list: List(a),
on_empty f1: fn() -> c,
on_singleton c: c,
on_gt1 f3: fn(a, a, List(a)) -> c,
) -> c {
case list {
[] -> f1()
[_] -> c
[first, second, ..rest] -> f3(first, second, rest)
}
}
/// Given a List(a), and callbacks f() -> c, f(a) -> c,
/// f(a, a, List(a)) -> c, returns:
///
/// - the evaluation of the first callback if the list is empty
/// - the second callback evaluated with argument a1 if the list as the form [a1]
/// - the third callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
///
/// ### Example 1
///
/// ```gleam
/// use first, second, ..rest <- on.empty_singleton_gt1(
/// [1, 4, 7],
/// on_empty: 0,
/// on_singleton: fn(first) { first },
/// )
/// // -> execution proceeds, first == 1, second == 4, rest == [7];
/// // scope must return an Int to match the on_empty, on_singleton callbacks
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first, second, ..rest <- on.empty_singleton_gt1(
/// [4],
/// on_empty: 0,
/// on_singleton: fn(first) { first },
/// )
/// // -> execution discontinues, scope resturns 4
/// ```
///
pub fn empty_singleton_gt1(
list: List(a),
on_empty f1: fn() -> c,
on_singleton f2: fn(a) -> c,
on_gt1 f3: fn(a, a, List(a)) -> c,
) -> c {
case list {
[] -> f1()
[first] -> f2(first)
[first, second, ..rest] -> f3(first, second, rest)
}
}
/// Given a List(a), values c1 and c2 of type c, and a callback
/// f(a) -> c, returns:
///
/// - c1 if the list is empty
/// - c2 if the list as more than one element
/// - the second callback evaluated with argument a1 if the list as the form [a1]
///
/// ### Example 1
///
/// ```gleam
/// use first <- on.eager_empty_eager_gt1_singleton(
/// [1, 4, 7],
/// on_empty: Error("empty list"),
/// on_gt1: Error("> 1 element in list"),
/// )
/// // -> execution discontinues, scope returns Error("> 1 element in list")
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first <- on.eager_empty_eager_gt1_singleton(
/// [4],
/// on_empty: Error("empty list"),
/// on_gt1: Error("> 1 element in list"),
/// )
/// // -> execution proceeds, first == 4;
/// // scope must return a Result(c, String) to match the on_empty
/// // and on_gt1 values
/// ```
///
pub fn eager_empty_eager_gt1_singleton(
list: List(a),
on_empty c1: c,
on_gt1 c2: c,
on_singleton f3: fn(a) -> c,
) -> c {
case list {
[] -> c1
[_, _, ..] -> c2
[first] -> f3(first)
}
}
/// Given a List(a), a value of type c, and callbacks
/// f(a, a, List(a)) -> c, f(a) -> c, returns:
///
/// - the value of type c if the list is empty
/// - the first callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
/// - the second callback evaluated with argument a1 if the list as the form [a1]
///
/// ### Example 1
///
/// ```gleam
/// use first <- on.eager_empty_gt1_singleton(
/// [1, 4, 7],
/// on_empty: Error("empty list"),
/// on_gt1: fn(_, _, rest) { Error(string.inspect(2 + list.length(rest) <> " > 1 elements in list") },
/// )
/// // -> execution discontinues, scope returns Error("3 > 1 elements in list")
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first <- on.eager_empty_gt1_singleton(
/// [4],
/// on_empty: Error("empty list"),
/// on_gt1: fn(_, _, rest) { Error(string.inspect(2 + list.length(rest) <> " > 1 elements in list") },
/// )
/// // -> execution discontinues, first == 4
/// // scope must return a Result(c, String)
/// ```
///
pub fn eager_empty_gt1_singleton(
list: List(a),
on_empty c: c,
on_gt1 f2: fn(a, a, List(a)) -> c,
on_singleton f3: fn(a) -> c,
) -> c {
case list {
[] -> c
[first, second, ..rest] -> f2(first, second, rest)
[first] -> f3(first)
}
}
/// Given a List(a), a callback f() -> c, a value c1 of type c
/// and a second callback f(a, a, List(a)) -> c, f(a) -> c, returns:
///
/// - the evaluation of the first callback if the list is empty
/// - c1 if the list has more than one element
/// - the third callback evaluated with argument a1 if the list as the form [a1]
///
/// ### Example 1
///
/// ```gleam
/// use first <- on.empty_eager_gt1_singleton(
/// [1, 4, 7],
/// on_empty: fn() { Error("empty list") },
/// on_gt1: Error("> 1 elements in list"),
/// )
/// // -> execution discontinues, scope returns Error("> 1 elements in list")
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first <- on.empty_gt1_singleton(
/// [4],
/// on_empty: fn() { Error("empty list") },
/// on_gt1: Error("> 1 elements in list"),
/// )
/// // -> execution proceeds, first == 4;
/// // scope must return a Result(c, String)
/// ```
///
pub fn empty_eager_gt1_singleton(
list: List(a),
on_empty f1: fn() -> c,
on_gt1 c: c,
on_singleton f3: fn(a) -> c,
) -> c {
case list {
[] -> f1()
[_, _, ..] -> c
[first] -> f3(first)
}
}
/// Given a List(a) and callbacks f() -> c,
/// f(a, a, List(a)) -> c, f(a) -> c, returns:
///
/// - the evaluation of the first callback if the list is empty
/// - the second callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
/// - the third callback evaluated with argument a1 if the list as the form [a1]
///
/// ### Example 1
///
/// ```gleam
/// use first <- on.empty_gt1_singleton(
/// [1, 4, 7],
/// on_empty: fn() { Error("empty list") },
/// on_gt1: fn(_, _, rest) {Error(string.inspect(2 + list.length(rest)) <> " > 1 elements in list")},
/// )
/// // -> execution discontinues, scope returns Error("3 > 1 elements in list")
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use first <- on.empty_gt1_singleton(
/// [4],
/// on_empty: fn() { Error("empty list") },
/// on_gt1: fn(_, _, rest) {Error(string.inspect(2 + list.length(rest)) <> " > 1 elements in list")},
/// )
/// // -> execution proceeds, first == 4;
/// // scope must return a Result(c, String) to match the on_empty
/// // and on_gt1 callbacks
/// ```
///
pub fn empty_gt1_singleton(
list: List(a),
on_empty f1: fn() -> c,
on_gt1 f2: fn(a, a, List(a)) -> c,
on_singleton f3: fn(a) -> c,
) -> c {
case list {
[] -> f1()
[first, second, ..rest] -> f2(first, second, rest)
[first] -> f3(first)
}
}
/// Given a List(a), values c1, c2 of type c and a callback
/// f() -> c, returns:
///
/// - c1 if the list has one element
/// - c2 if the list has more than one element
/// - the evaluation of the third callback if the list is empty
///
/// ### Example 1
///
/// ```gleam
/// use <- on.eager_singleton_eager_gt1_empty(
/// [1, 4, 7],
/// on_singleton: 55,
/// on_gt1: 66,
/// )
/// // -> execution discontinues, scope returns 66
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.eager_singleton_eager_gt1_empty(
/// [],
/// on_singleton: 55,
/// on_gt1: 66,
/// )
/// // -> execution proceeds, scope must return an Int to
/// // match the on_singleton, on_gt1 callbacks
///
/// ```
///
pub fn eager_singleton_eager_gt1_empty(
list: List(a),
on_singleton c1: c,
on_gt1 c2: c,
on_empty f3: fn() -> c,
) -> c {
case list {
[_] -> c1
[_, _, ..] -> c2
[] -> f3()
}
}
/// Given a List(a), a value of type c and callbacks fn(a, a, List(a)) -> c,
/// fn() -> c, returns:
///
/// - the value of type c if the list has one elemnt
/// - the second callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
/// - the evaluation of the third callback if the list is empty
///
/// ### Example 1
///
/// ```gleam
/// use <- on.eager_singleton_gt1_empty(
/// [4],
/// on_singleton: 23,
/// on_gt1: fn(first, second, ..rest) { first + second},
/// )
/// // -> execution discontinues, scope returns 23
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.eager_singleton_gt1_empty(
/// [],
/// on_singleton: 23,
/// on_gt1: fn(first, second, ..rest) { first + second},
/// )
/// // -> execution proceeds, scope must return an Int
///
/// ```
///
pub fn eager_singleton_gt1_empty(
list: List(a),
on_singleton c: c,
on_gt1 f2: fn(a, a, List(a)) -> c,
on_empty f3: fn() -> c,
) -> c {
case list {
[_] -> c
[first, second, ..rest] -> f2(first, second, rest)
[] -> f3()
}
}
/// Given a List(a) and a callback f(a) -> c,
/// f(a, a, List(a)) -> c, f() -> c, returns:
///
/// - the first callback evaluated with argument a1 if the list as the form [a1]
/// - the second callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
/// - the evaluation of the third callback if the list is empty
///
/// ### Example 1
///
/// ```gleam
/// use <- on.singleton_eager_gt1_empty(
/// [2, 4, 7],
/// on_singleton: fn(x) { x + 1 },
/// on_gt1: 66,
/// )
/// // -> execution discontinues, scope returns 66
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.singleton_eager_gt1_empty(
/// [],
/// on_singleton: fn(x) { x + 1 },
/// on_gt1: 66,
/// )
/// // -> execution proceeds, scope must return an Int
///
/// ```
///
pub fn singleton_eager_gt1_empty(
list: List(a),
on_singleton f1: fn(a) -> c,
on_gt1 c: c,
on_empty f3: fn() -> c,
) -> c {
case list {
[first] -> f1(first)
[_, _, ..] -> c
[] -> f3()
}
}
/// Given a List(a) and callbacks f(a) -> c,
/// f(a, a, List(a)) -> c, f() -> c, returns:
///
/// - the first callback evaluated with argument a1 if the list as the form [a1]
/// - the second callback evaluated with arguments a1, a2, rest if the list has the form [a1, a2, ..rest]
/// - the evaluation of the third callback if the list is empty
///
/// ### Example 1
///
/// ```gleam
/// use <- on.singleton_gt1_empty(
/// [2, 4, 7],
/// on_singleton: fn(x) { x + 1 },
/// on_gt1: fn(first, second, ..rest) { first + second},
/// )
/// // -> execution discontinues, scope returns 6 (= 2 + 4)
/// ```
///
/// ### Example 2
///
/// ```gleam
/// use <- on.singleton_gt1_empty(
/// [],
/// on_singleton: fn(x) { x + 1 },
/// on_gt1: fn(first, second, ..rest) { first + second},
/// )
/// // -> execution proceeds, scope must return an Int to
/// // match the on_singleton, on_gt1 callbacks
///
/// ```
///
pub fn singleton_gt1_empty(
list: List(a),
on_singleton f1: fn(a) -> c,
on_gt1 f2: fn(a, a, List(a)) -> c,
on_empty f3: fn() -> c,
) -> c {
case list {
[first] -> f1(first)
[first, second, ..rest] -> f2(first, second, rest)
[] -> f3()
}
}
// ****************
// * Return(a, b) *
// ****************
/// A choice type whose semantics indicate intent to return from local
/// scope or not, to be paired with [on.stay](#stay).
pub type Return(a, b) {
Return(a)
Stay(b)
}
/// Given a value of type Return(a, b) and a callback f(b) -> a, returns
/// f(b1) if the value has the form Stay(b1) and returns a1
/// if the value has the form Return(a1).
///
/// ### Example 1
///
/// ```gleam
/// let #(string1, string2) = #("bob", "")
/// use _ <- on.stay(case string2 {
/// "" -> on.Return(#(string1, string1))
/// _ -> on.Stay(Nil)
/// })
/// // -> execution discontinues, scope returns #("bob", "bob")
/// ```
///
/// ### Example 2
///
/// ```gleam
/// let #(string1, string2) = #("bob", "alice")
/// use _ <- on.stay(case string2 {
/// "" -> on.Return(#(string1, string1))
/// _ -> on.Stay(Nil)
/// })
/// // -> execution proceeds; the current scope must return a #(String, String)
/// ```
///
pub fn stay(
r: Return(a, b),
on_stay f: fn(b) -> a,
) -> a {
case r {
Return(a) -> a
Stay(b) -> f(b)
}
}