rectify
Rectify - Railway-oriented programming utilities for Gleam
A port of FsToolkit.ErrorHandling concepts:
- Validation: Applicative functor for collecting multiple errors
- Result/Option utilities for composing fallible operations
Types
Validation applicative - collect multiple errors instead of fail-fast.
Unlike Result which stops at the first Error, Validation accumulates
all errors before returning them together.
pub type Validation(a, e) {
Valid(a)
Invalid(List(e))
}
Constructors
-
Valid(a) -
Invalid(List(e))
Values
pub fn apply(
vf: Validation(fn(a) -> b, e),
va: Validation(a, e),
) -> Validation(b, e)
Apply a validation containing a function to a validation containing a value.
Examples
apply(valid(fn(x) { x * 2 }), valid(21))
// -> Valid(42)
apply(invalid("e1"), invalid("e2"))
// -> Invalid(["e1", "e2"])
pub fn bind(
v: Validation(a, e),
f: fn(a) -> Validation(b, e),
) -> Validation(b, e)
Bind/flatMap for validation (note: doesn’t accumulate errors across binds).
Use this when determining the next validation step depends on the success value of the previous step. Errors from the first step are preserved, but errors do not accumulate with operations in the second step, because the second step is never executed if the first step fails.
Examples
valid(1) |> bind(fn(x) { valid(x * 2) })
// -> Valid(2)
invalid("e") |> bind(fn(x) { valid(x * 2) })
// -> Invalid(["e"])
pub fn default_to(v: Validation(a, e), default: a) -> a
Run a validation and return the value or a default.
Examples
default_to(valid(42), 0)
// -> 42
default_to(invalid("e"), 0)
// -> 0
pub fn default_with(v: Validation(a, e), f: fn() -> a) -> a
Run a validation with a lazy default.
Examples
default_with(valid(42), fn() { 0 })
// -> 42
default_with(invalid("e"), fn() { 0 })
// -> 0
pub fn errors(v: Validation(a, e)) -> List(e)
Get errors from a validation, or empty list if Valid.
Examples
errors(valid(1))
// -> []
errors(invalid_many(["a", "b"]))
// -> ["a", "b"]
pub fn flatten(
v: Validation(Validation(a, e), e),
) -> Validation(a, e)
Flatten a nested validation.
Examples
flatten(valid(valid(1)))
// -> Valid(1)
flatten(valid(invalid("e")))
// -> Invalid(["e"])
pub fn invalid(e: e) -> Validation(a, e)
Create a failed validation with a single error.
pub fn invalid_many(es: List(e)) -> Validation(a, e)
Create a failed validation with multiple errors.
pub fn is_invalid(v: Validation(a, e)) -> Bool
Check if validation has errors.
Examples
is_invalid(invalid("e"))
// -> True
is_invalid(valid(1))
// -> False
pub fn is_valid(v: Validation(a, e)) -> Bool
Check if validation is valid.
Examples
is_valid(valid(1))
// -> True
is_valid(invalid("e"))
// -> False
pub fn map(
validation: Validation(a, e),
f: fn(a) -> b,
) -> Validation(b, e)
Map a function over a validation.
Examples
valid(5) |> map(fn(n) { n * 2 })
// -> Valid(10)
invalid("error") |> map(fn(n) { n * 2 })
// -> Invalid(["error"])
pub fn map2(
v1: Validation(a, e),
v2: Validation(b, e),
f: fn(a, b) -> c,
) -> Validation(c, e)
Map over two validations, combining their errors if both fail.
Examples
map2(valid(2), valid(3), fn(a, b) { a + b })
// -> Valid(5)
map2(invalid("e1"), invalid("e2"), fn(a, b) { a + b })
// -> Invalid(["e1", "e2"])
pub fn map3(
v1: Validation(a, e),
v2: Validation(b, e),
v3: Validation(c, e),
f: fn(a, b, c) -> d,
) -> Validation(d, e)
Map over three validations.
Similar to map2, but for three validations. Gathers all errors if any
of the validations are invalid.
pub fn map4(
v1: Validation(a, e),
v2: Validation(b, e),
v3: Validation(c, e),
v4: Validation(d, e),
f: fn(a, b, c, d) -> g,
) -> Validation(g, e)
Map over four validations.
Similar to map2, but for four validations. Gathers all errors if any
of the validations are invalid.
pub fn map5(
v1: Validation(a, e),
v2: Validation(b, e),
v3: Validation(c, e),
v4: Validation(d, e),
v5: Validation(g, e),
f: fn(a, b, c, d, g) -> h,
) -> Validation(h, e)
Map over five validations.
Similar to map2, but for five validations. Gathers all errors if any
of the validations are invalid.
pub fn map_errors(
v: Validation(a, e),
f: fn(e) -> f,
) -> Validation(a, f)
Transform errors in a validation.
Examples
invalid("e") |> map_errors(fn(e) { "Error: " <> e })
// -> Invalid(["Error: e"])
pub fn of_result(r: Result(a, e)) -> Validation(a, e)
Convert Result to Validation.
Examples
of_result(Ok(42))
// -> Valid(42)
of_result(Error("e"))
// -> Invalid(["e"])
pub fn of_result_list(r: Result(a, List(e))) -> Validation(a, e)
Convert Result with multiple errors to Validation.
Examples
of_result_list(Ok(42))
// -> Valid(42)
of_result_list(Error(["e1", "e2"]))
// -> Invalid(["e1", "e2"])
pub fn to_result(v: Validation(a, e)) -> Result(a, List(e))
Convert validation to Result (all errors as list).
Examples
to_result(valid(42))
// -> Ok(42)
to_result(invalid_many(["a", "b"]))
// -> Error(["a", "b"])