Current section
Files
Jump to
Current section
Files
src/gleamy/non_empty_list.gleam
//// This module provides a type and functions for working with non-empty lists,
//// which are lists that are guaranteed to have at least one element.
import gleam/list
/// The `NonEmptyList(a)` type represents a non-empty list of elements of type `a`.
/// It has two cases: `End(first: a)` for a list with a single element, and
/// `Next(first: a, rest: NonEmptyList(a))` for a list with multiple elements.
pub type NonEmptyList(a) {
End(first: a)
Next(first: a, rest: NonEmptyList(a))
}
/// Applies a function to every element in the non-empty list, accumulating
/// the results with the provided initial accumulator value.
pub fn fold(
over list: NonEmptyList(a),
from initial: b,
with fun: fn(b, a) -> b,
) -> b {
case list {
End(item) -> fun(initial, item)
Next(x, xs) -> fold(xs, fun(initial, x), fun)
}
}
/// Returns the count (number of elements) in the non-empty list.
/// Time complexity: O(n)
pub fn count(list: NonEmptyList(a)) -> Int {
fold(list, 0, fn(acc, _) { acc + 1 })
}
/// Applies a transformation function to every element in the non-empty list
/// and returns a new non-empty list with the transformed elements.
pub fn map(list: NonEmptyList(a), transform: fn(a) -> b) -> NonEmptyList(b) {
case list {
End(x) -> End(transform(x))
Next(x, xs) ->
fold(xs, End(transform(x)), fn(acc, item) { Next(transform(item), acc) })
|> reverse
}
}
/// Filters the elements of the non-empty list based on a predicate function
/// and returns a (potentially empty) list with the elements that satisfy the predicate.
pub fn filter(list: NonEmptyList(a), predicate: fn(a) -> Bool) -> List(a) {
fold(list, [], fn(acc, item) {
case predicate(item) {
True -> [item, ..acc]
False -> acc
}
})
|> list.reverse()
}
/// Converts the non-empty list to a regular (potentially empty) list.
pub fn to_list(list: NonEmptyList(a)) -> List(a) {
fold(list, [], fn(acc, item) { [item, ..acc] })
|> list.reverse()
}
/// Tries to create a non-empty list from a regular (potentially empty) list.
/// Returns an error if the input list is empty.
pub fn from_list(list: List(a)) -> Result(NonEmptyList(a), Nil) {
case list {
[] -> Error(Nil)
[x, ..xs] -> Ok(list.fold(xs, End(x), fn(acc, item) { Next(item, acc) }))
}
}
/// Reverses the order of elements in the non-empty list.
pub fn reverse(list: NonEmptyList(a)) -> NonEmptyList(a) {
case list {
End(_) -> list
Next(x, xs) -> fold(xs, End(x), fn(acc, x) { Next(x, acc) })
}
}