Current section

Files

Jump to
gleam_stdlib src gleam list.gleam
Raw

src/gleam/list.gleam

import gleam/int
import gleam/pair
import gleam/order.{Order}
import gleam/result.{Option}
pub type LengthMismatch {
LengthMismatch
}
// Using the Erlang C BIF implementation.
//
pub external fn length(List(a)) -> Int = "erlang" "length"
// Using the Erlang C BIF implementation.
//
pub external fn reverse(List(a)) -> List(a) = "lists" "reverse"
pub fn is_empty(list: List(a)) -> Bool {
list == []
}
pub fn contains(list: List(a), has elem: a) -> Bool {
case list {
[] -> False
[head | rest] -> head == elem || contains(rest, elem)
}
}
pub fn head(list: List(a)) -> Option(a) {
case list {
[] -> result.none()
[x | _] -> Ok(x)
}
}
pub fn tail(list: List(a)) -> Option(List(a)) {
case list {
[] -> result.none()
[_ | xs] -> Ok(xs)
}
}
fn do_filter(list: List(a), fun: fn(a) -> Bool, acc: List(a)) -> List(a) {
case list {
[] -> reverse(acc)
[x | xs] -> {
let new_acc = case fun(x) {
True -> [x | acc]
False -> acc
}
do_filter(xs, fun, new_acc)
}
}
}
pub fn filter(list: List(a), for predicate: fn(a) -> Bool) -> List(a) {
do_filter(list, predicate, [])
}
fn do_map(list: List(a), fun: fn(a) -> b, acc: List(b)) -> List(b) {
case list {
[] -> reverse(acc)
[x | xs] -> do_map(xs, fun, [fun(x) | acc])
}
}
pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) {
do_map(list, fun, [])
}
fn do_index_map(
list: List(a),
fun: fn(Int, a) -> b,
index: Int,
acc: List(b),
) -> List(b) {
case list {
[] -> reverse(acc)
[x | xs] -> do_index_map(xs, fun, index + 1, [fun(index, x) | acc])
}
}
pub fn index_map(list: List(a), with fun: fn(Int, a) -> b) -> List(b) {
do_index_map(list, fun, 0, [])
}
fn do_traverse(
list: List(a),
fun: fn(a) -> Result(b, e),
acc: List(b),
) -> Result(List(b), e) {
case list {
[] -> Ok(reverse(acc))
[x | xs] ->
case fun(x) {
Ok(y) -> do_traverse(xs, fun, [y | acc])
Error(error) -> Error(error)
}
}
}
pub fn traverse(
list: List(a),
with fun: fn(a) -> Result(b, e),
) -> Result(List(b), e) {
do_traverse(list, fun, [])
}
pub fn drop(from list: List(a), up_to n: Int) -> List(a) {
case n <= 0 {
True -> list
False ->
case list {
[] -> []
[_ | xs] -> drop(xs, n - 1)
}
}
}
fn do_take(list: List(a), n: Int, acc: List(a)) -> List(a) {
case n <= 0 {
True -> reverse(acc)
False ->
case list {
[] -> reverse(acc)
[x | xs] -> do_take(xs, n - 1, [x | acc])
}
}
}
pub fn take(from list: List(a), up_to n: Int) -> List(a) {
do_take(list, n, [])
}
pub fn new() -> List(a) {
[]
}
pub external fn append(List(a), List(a)) -> List(a)
= "lists" "append";
fn do_flatten(lists: List(List(a)), acc: List(a)) -> List(a) {
case lists {
[] -> acc
[l | rest] -> do_flatten(rest, append(acc, l))
}
}
pub fn flatten(lists: List(List(a))) -> List(a) {
do_flatten(lists, [])
}
pub fn fold(list: List(a), from initial: b, with fun: fn(a, b) -> b) -> b {
case list {
[] -> initial
[x | rest] -> fold(rest, fun(x, initial), fun)
}
}
pub fn fold_right(
list: List(a),
from initial: b,
with fun: fn(a, b) -> b,
) -> b {
case list {
[] -> initial
[x | rest] -> fun(x, fold_right(rest, initial, fun))
}
}
pub fn find(
in haystack: List(a),
one_that is_desired: fn(a) -> Bool,
) -> Option(a) {
case haystack {
[] -> result.none()
[x | rest] ->
case is_desired(x) {
True -> Ok(x)
_ -> find(in: rest, one_that: is_desired)
}
}
}
pub fn find_map(
in haystack: List(a),
with fun: fn(a) -> Option(b),
) -> Option(b) {
case haystack {
[] -> result.none()
[x | rest] ->
case fun(x) {
Ok(x) -> Ok(x)
_ -> find_map(in: rest, with: fun)
}
}
}
pub fn all(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool {
case list {
[] -> True
[x | rest] ->
case predicate(x) {
True -> all(rest, predicate)
_ -> False
}
}
}
pub fn any(in list: List(a), satisfying predicate: fn(a) -> Bool) -> Bool {
case list {
[] -> False
[x | rest] ->
case predicate(x) {
False -> any(rest, predicate)
_ -> True
}
}
}
pub fn zip(xs: List(a), ys: List(b)) -> List(tuple(a, b)) {
case xs, ys {
[], _ -> []
_, [] -> []
[x | xs], [y | ys] -> [tuple(x, y) | zip(xs, ys)]
}
}
pub fn strict_zip(l1: List(a), l2: List(b)) -> Result(List(tuple(a, b)), LengthMismatch) {
case length(l1) == length(l2) {
True -> Ok(zip(l1, l2))
False -> Error(LengthMismatch)
}
}
pub fn intersperse(list: List(a), with elem: a) -> List(a) {
case list {
[] | [_] -> list
[x | rest] -> [x | [elem | intersperse(rest, elem)]]
}
}
pub fn at(in list: List(a), get index: Int) -> Option(a) {
case index < 0 {
True -> result.none()
False ->
case list {
[] -> result.none()
[x | rest] ->
case index == 0 {
True -> Ok(x)
False -> at(rest, index - 1)
}
}
}
}
pub fn unique(list: List(a)) -> List(a) {
case list {
[] -> []
[x | rest] -> [x | unique(filter(rest, fn(y) { y != x }))]
}
}
fn merge_sort(a: List(a), b: List(a), compare: fn(a, a) -> Order) -> List(a) {
case a, b {
[], _ -> b
_, [] -> a
[ax | ar], [bx | br] ->
case compare(ax, bx) {
order.Lt -> [ax | merge_sort(ar, b, compare)]
_ -> [bx | merge_sort(a, br, compare)]
}
}
}
fn do_sort(list: List(a), compare: fn(a, a) -> Order, list_length: Int) -> List(a) {
case list_length < 2 {
True -> list
False -> {
let split_length = list_length / 2
let a_list = take(list, split_length)
let b_list = drop(list, split_length)
merge_sort(
do_sort(a_list, compare, split_length),
do_sort(b_list, compare, list_length - split_length),
compare,
)
}
}
}
pub fn sort(list: List(a), sort_by compare: fn(a, a) -> Order) -> List(a) {
do_sort(list, compare, length(list))
}
pub fn range(from start: Int, to stop: Int) -> List(Int) {
case int.compare(start, stop) {
order.Eq -> []
order.Gt -> [start | range(start - 1, stop)]
order.Lt -> [start | range(start + 1, stop)]
}
}
fn do_repeat(a: a, times: Int, acc: List(a)) -> List(a) {
case times <= 0 {
True -> acc
False -> do_repeat(a, times - 1, [a | acc])
}
}
pub fn repeat(item a: a, times times: Int) -> List(a) {
do_repeat(a, times, [])
}
fn do_split(list: List(a), n: Int, taken: List(a)) -> tuple(List(a), List(a)) {
case n <= 0 {
True -> tuple(reverse(taken), list)
False ->
case list {
[] -> tuple(reverse(taken), [])
[x | xs] -> do_split(xs, n - 1, [x | taken])
}
}
}
pub fn split(list list: List(a), at index: Int) -> tuple(List(a), List(a)) {
do_split(list, index, [])
}
fn do_split_while(
list: List(a),
f: fn(a) -> Bool,
acc: List(a),
) -> tuple(List(a), List(a)) {
case list {
[] -> tuple(reverse(acc), [])
[x | xs] ->
case f(x) {
False -> tuple(reverse(acc), list)
_ -> do_split_while(xs, f, [x | acc])
}
}
}
pub fn split_while(
list list: List(a),
while predicate: fn(a) -> Bool,
) -> tuple(List(a), List(a)) {
do_split_while(list, predicate, [])
}
pub fn key_find(
in keyword_list: List(tuple(k, v)),
find desired_key: k,
) -> Option(v) {
find_map(keyword_list, fn(keyword) {
let tuple(key, value) = keyword
case key == desired_key {
True -> Ok(value)
False -> result.none()
}
})
}