#List

    The List package provides an immutable linked list data structure with a variety of utility functions for functional programming.

    #Table of Contents

    1. Overview
    2. Performance
    3. Usage
      • Create
      • Basic Operations
      • Access Elements
      • Iteration
      • Advanced Operations
      • Conversion
      • Equality
    4. Error Handling Best Practices
    5. Implementation Notes
    6. Comparison with Other Collections


    #Overview

    List is a functional, immutable data structure that supports efficient traversal, transformation, and manipulation. It is particularly useful for recursive algorithms and scenarios where immutability is required.


    #Performance

    • prepend: O(1)
    • length: O(n)
    • map/filter: O(n)
    • concatenate: O(n)
    • reverse: O(n)
    • nth: O(n)
    • sort: O(n log n)
    • flatten: O(n * m), where m is the average inner list length
    • space complexity: O(n)


    #Usage

    #Create

    You can create an empty list or a list from an array.

    ///|
    test {
    let empty_list : @list.List[Int] = @list.new()
    assert_true(empty_list.is_empty())
    let list = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(list, List([1, 2, 3, 4, 5]))
    }


    #Basic Operations

    #Prepend

    Add an element to the beginning of the list.

    ///|
    test {
    let list = @list.List([2, 3, 4, 5]).prepend(1)
    @debug.assert_eq(list, List([1, 2, 3, 4, 5]))
    }

    #Length

    Get the number of elements in the list.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @test.assert_eq(list.length(), 5)
    }

    #Check if Empty

    Determine if the list is empty.

    ///|
    test {
    let empty_list : @list.List[Int] = @list.new()
    @test.assert_eq(empty_list.is_empty(), true)
    }


    #Access Elements

    Get the first element of the list as an Option.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    assert_true(list.head() == Some(1))
    }

    #Tail

    Get the list without its first element.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(list.unsafe_tail(), List([2, 3, 4, 5]))
    }

    #Nth Element

    Get the nth element of the list as an Option.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    assert_true(list.nth(2) == Some(3))
    }


    #Iteration

    #Each

    Iterate over the elements of the list.

    ///|
    test {
    let arr = []
    @list.List([1, 2, 3, 4, 5]).each(x => arr.push(x))
    @debug.assert_eq(arr, [1, 2, 3, 4, 5])
    }

    #Map

    Transform each element of the list.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5]).map(x => x * 2)
    @debug.assert_eq(list, List([2, 4, 6, 8, 10]))
    }

    #Filter & Filter Map

    filter keeps elements matching a predicate. filter_map transforms and filters in one pass.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(list.filter(fn(x) { x % 2 == 0 }), List([2, 4]))
    let fm = list.filter_map(fn(x) { if x > 3 { Some(x * 10) } else { None } })
    @debug.assert_eq(fm, List([40, 50]))
    }

    #Fold

    fold reduces from left to right. foldi includes the index.

    ///|
    test {
    let list = @list.List([1, 2, 3])
    @test.assert_eq(list.fold(init=0, fn(acc, x) { acc + x }), 6)
    let indexed = list.foldi(init="", fn(i, acc, x) {
    acc + i.to_string() + ":" + x.to_string() + " "
    })
    inspect(indexed, content="0:1 1:2 2:3 ")
    }

    #Find, Any, All, Contains

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    assert_true(list.find(fn(x) { x > 3 }) == Some(4))
    assert_true(list.find_index(fn(x) { x == 3 }) == Some(2))
    @test.assert_eq(list.any(fn(x) { x > 4 }), true)
    @test.assert_eq(list.all(fn(x) { x > 0 }), true)
    @test.assert_eq(list.contains(3), true)
    @test.assert_eq(list.contains(9), false)
    }

    #Flat Map

    ///|
    test {
    let list = @list.List([1, 2, 3])
    let result = list.flat_map(fn(x) { List([x, x * 10]) })
    @debug.assert_eq(result, List([1, 10, 2, 20, 3, 30]))
    }


    #Advanced Operations

    #Take & Drop

    take(n) keeps the first n elements. drop(n) skips them. take_while and drop_while use a predicate.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(list.take(3), List([1, 2, 3]))
    @debug.assert_eq(list.drop(3), List([4, 5]))
    @debug.assert_eq(list.take_while(fn(x) { x < 4 }), List([1, 2, 3]))
    @debug.assert_eq(list.drop_while(fn(x) { x < 4 }), List([4, 5]))
    }

    #Remove

    remove(x) removes the first occurrence. remove_at(i) removes by index.

    ///|
    test {
    let list = @list.List([1, 2, 3, 2, 1])
    @debug.assert_eq(list.remove(2), List([1, 3, 2, 1]))
    @debug.assert_eq(list.remove_at(0), List([2, 3, 2, 1]))
    }

    #Last, Minimum, Maximum

    ///|
    test {
    let list = @list.List([3, 1, 4, 1, 5])
    assert_true(list.last() == Some(5))
    assert_true(list.minimum() == Some(1))
    assert_true(list.maximum() == Some(5))
    }

    #Reverse

    Reverse the list.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5]).rev()
    @debug.assert_eq(list, List([5, 4, 3, 2, 1]))
    }

    #Concatenate

    Concatenate two lists.

    ///|
    test {
    let list = @list.List([1, 2, 3]).concat(List([4, 5]))
    @debug.assert_eq(list, List([1, 2, 3, 4, 5]))
    }

    #Flatten

    Flatten a list of lists.

    ///|
    test {
    let list = @list.List([@list.List([1, 2]), List([3, 4])]).flatten()
    @debug.assert_eq(list, List([1, 2, 3, 4]))
    }

    #Sort

    Sort the list in ascending order.

    ///|
    test {
    let list = @list.List([3, 1, 4, 1, 5, 9]).sort()
    @debug.assert_eq(list, List([1, 1, 3, 4, 5, 9]))
    }

    #Intersperse & Intercalate

    intersperse inserts a separator between every pair of elements. intercalate joins a list of lists with a separator list.

    ///|
    test {
    let list = @list.List([1, 2, 3])
    @debug.assert_eq(list.intersperse(0), List([1, 0, 2, 0, 3]))
    let nested = @list.List([@list.List([1, 2]), List([3, 4]), List([5])])
    let sep = @list.List([0])
    @debug.assert_eq(nested.intercalate(sep), List([1, 2, 0, 3, 4, 0, 5]))
    }

    #Zip & Unzip

    ///|
    test {
    let a = @list.List([1, 2, 3])
    let b = @list.List(["a", "b", "c"])
    let zipped = @list.zip(a, b)
    @debug.assert_eq(zipped, List([(1, "a"), (2, "b"), (3, "c")]))
    let (xs, ys) = zipped.unzip()
    @debug.assert_eq(xs, List([1, 2, 3]))
    @debug.assert_eq(ys, List(["a", "b", "c"]))
    }

    #Scan

    scan_left produces a list of successive fold results. scan_right does the same from right to left.

    ///|
    test {
    let list = @list.List([1, 2, 3])
    @debug.assert_eq(
    list.scan_left(fn(acc, x) { acc + x }, init=0),
    List([0, 1, 3, 6]),
    )
    }

    #Prefix & Suffix

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @test.assert_eq(list.has_prefix(List([1, 2, 3])), true)
    @test.assert_eq(list.has_suffix(List([4, 5])), true)
    }

    #Lookup

    Look up a value in an association list (list of key-value pairs):

    ///|
    test {
    let assoc = @list.List([("a", 1), ("b", 2), ("c", 3)])
    assert_true(assoc.lookup("b") == Some(2))
    assert_true(assoc.lookup("z") == None)
    }

    #Unfold

    Build a list from a seed value. unfold produces elements in order; rev_unfold in reverse.

    ///|
    test {
    let list = @list.unfold(init=1, fn(n) {
    if n > 5 {
    None
    } else {
    Some((n, n + 1))
    }
    })
    @debug.assert_eq(list, List([1, 2, 3, 4, 5]))
    }


    #Iterators

    iter() returns an Iter. from_iter() constructs a list from an iterator.

    ///|
    test {
    let list = @list.List([1, 2, 3])
    debug_inspect(list.iter().to_array(), content="[1, 2, 3]")
    let list2 = @list.from_iter(4, 5, 6)
    @debug.assert_eq(list2, List([4, 5, 6]))
    }


    #Conversion

    #To Array

    Convert a list to an array.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(list.to_array(), [1, 2, 3, 4, 5])
    }

    #From Array

    Create a list from an array.

    ///|
    test {
    let list = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(list, List([1, 2, 3, 4, 5]))
    }


    #Equality

    Lists with the same elements in the same order are considered equal.

    ///|
    test {
    let list1 = @list.List([1, 2, 3])
    let list2 = @list.List([1, 2, 3])
    @test.assert_eq(list1 == list2, true)
    }


    #Error Handling Best Practices

    When accessing elements that might not exist, use pattern matching for safety:

    ///|
    fn safe_head(list : @list.List[Int]) -> Int {
    match list.head() {
    Some(value) => value
    None => 0 // Default value
    }
    }

    ///|
    test {
    let list = @list.List([1, 2, 3])
    @test.assert_eq(safe_head(list), 1)
    let empty_list : @list.List[Int] = @list.new()
    @test.assert_eq(safe_head(empty_list), 0)
    }

    #Additional Error Cases

    • nth() on an empty list or out-of-bounds index: Returns None.
    • unsafe_tail() on an empty list: Panics. Use pattern matching, or drop(1), which returns Empty.
    • sort() on elements without a Compare implementation: Rejected at compile time by the A : Compare bound; there is no runtime failure.


    #Implementation Notes

    The List is implemented as a singly linked list. Operations like prepend and head are O(1), while operations like length and map are O(n).

    Key properties of the implementation:
    • Immutable by design
    • Recursive-friendly
    • Optimized for functional programming patterns


    #Comparison with Other Collections

    • @array.Array: Provides O(1) random access but is mutable; use when random access is required.
    • @list.List: Immutable and optimized for recursive operations; use when immutability and functional patterns are required.

    Choose List when you need:
    • Immutable data structures
    • Efficient prepend operations
    • Functional programming patterns

    List

    pub enum List[A] {
    Empty
    More(A, mut tail~ : List[A])
    }

    Type List used by this package APIs.
    impl Add for List[A]
    impl Compare for List[A]
    impl Default for List[X]
    impl Eq for List[A]
    impl Hash for List[A]
    impl Show for List[A]
    impl ToJson for List[A]
    impl FromJson for List[A]

    List::List

    fn[A] List::List(arr : ArrayView[A]) -> List[A]

    test {
    let lst = @list.List([1, 2, 3, 4, 5])
    debug_inspect(
    lst,
    content=(
    #|<List: [1, 2, 3, 4, 5]>
    ),
    )
    }

    List::all

    fn[A] List::all(self : List[A], f : (A) -> Bool raise?) -> Bool raise?

    Test if all elements of the list satisfy the predicate.

    Returns true if every element satisfies the predicate, or if the list is empty. Returns false as soon as an element that doesn't satisfy the predicate is found.

    Example

    test {
    let ls = @list.List([2, 4, 6, 8])
    @test.assert_eq(ls.all(x => x % 2 == 0), true)
    let ls2 = @list.List([2, 3, 6, 8])
    @test.assert_eq(ls2.all(x => x % 2 == 0), false)
    }

    List::any

    fn[A] List::any(self : List[A], f : (A) -> Bool raise?) -> Bool raise?

    Test if any element of the list satisfies the predicate.

    Returns true as soon as an element that satisfies the predicate is found. Returns false if no element satisfies the predicate, or if the list is empty.

    Example

    test {
    let ls = @list.List([1, 3, 5, 6])
    @test.assert_eq(ls.any(x => x % 2 == 0), true)
    let ls2 = @list.List([1, 3, 5, 7])
    @test.assert_eq(ls2.any(x => x % 2 == 0), false)
    }

    List::compare

    fn[A : Compare + Eq] List::compare(self : List[A], other : List[A]) -> Int

    List::concat

    fn[A] List::concat(self : List[A], other : List[A]) -> List[A]

    Concatenate two lists.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5]).concat(List([6, 7, 8, 9, 10]))
    @debug.assert_eq(ls, List([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]))
    }

    List::cons

    #as_free_fn(construct, deprecated="Use cons instead")
    #as_free_fn
    fn[A] List::cons(head : A, tail : List[A]) -> List[A]

    Prepend an element to the list and create a new list.

    This function constructs a new list with the given element as the head and the provided list as the tail.

    Example

    test {
    let tail = @list.List([2, 3, 4])
    let ls = @list.cons(1, tail)
    @debug.assert_eq(ls, List([1, 2, 3, 4]))
    }

    List::contains

    fn[A : Eq] List::contains(self : List[A], value : A) -> Bool

    Check if the list contains the specified value.

    Returns true if any element in the list is equal to the given value, false otherwise.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    @test.assert_eq(ls.contains(3), true)
    @test.assert_eq(ls.contains(6), false)
    }

    List::drop

    fn[A] List::drop(self : List[A], n : Int) -> List[A]

    Drop first n elements of the list. If the list is shorter than n, return an empty list.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let r = ls.drop(3)
    @debug.assert_eq(r, List([4, 5]))
    }

    List::drop_while

    fn[A] List::drop_while(self : List[A], p : (A) -> Bool raise?) -> List[A] raise?

    Drop the longest prefix of a list of elements that satisfies a given predicate.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4])
    let r = ls.drop_while(x => x < 3)
    @debug.assert_eq(r, List([3, 4]))
    }

    List::each

    fn[A] List::each(self : List[A], f : (A) -> Unit raise?) -> Unit raise?

    Iterates over the list.

    Example

    test {
    let arr = []
    @list.List([1, 2, 3, 4, 5]).each(x => arr.push(x))
    @debug.assert_eq(arr, [1, 2, 3, 4, 5])
    }

    List::eachi

    fn[A] List::eachi(self : List[A], f : (Int, A) -> Unit raise?) -> Unit raise?

    Iterates over the list with index.

    Example

    test {
    let arr = []
    @list.List([1, 2, 3, 4, 5]).eachi((i, x) => arr.push("(\{i},\{x})"))
    @debug.assert_eq(arr, ["(0,1)", "(1,2)", "(2,3)", "(3,4)", "(4,5)"])
    }

    List::equal

    fn[A : Eq] List::equal(self : List[A], other : List[A]) -> Bool

    List::filter

    fn[A] List::filter(self : List[A], f : (A) -> Bool raise?) -> List[A] raise?

    Filter the list.

    Example

    test {
    @debug.assert_eq(
    @list.List([1, 2, 3, 4, 5]).filter(x => x % 2 == 0),
    List([2, 4]),
    )
    }

    List::filter_map

    fn[A, B] List::filter_map(self : List[A], f : (A) -> B? raise?) -> List[B] raise?

    Map over the list and keep all values for which the mapped result is Some(value).

    Example

    test {
    let ls = @list.List([4, 2, 2, 6, 3, 1])
    let r = ls.filter_map(x => if x >= 3 { Some(x) } else { None })
    @debug.assert_eq(r, List([4, 6, 3]))
    }

    List::find

    fn[A] List::find(self : List[A], f : (A) -> Bool raise?) -> A? raise?

    Find the first element in the list that satisfies f.

    Example

    test {
    assert_true(
    @list.List([1, 3, 5, 8]).find(element => element % 2 == 0) == Some(8),
    )
    assert_true(@list.List([1, 3, 5]).find(element => element % 2 == 0) == None)
    }

    List::find_index

    fn[A] List::find_index(self : List[A], f : (A) -> Bool raise?) -> Int? raise?

    Returns the index of the first element in the list that satisfies the predicate function, or None if no element satisfies the predicate.

    Parameters:

    • self : The input list to search through.
    • f : A function that takes an element of the list and returns a boolean indicating whether the element satisfies the search criteria.

    Returns an Option containing the index of the first matching element, or None if no element matches.

    Example:

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    debug_inspect(ls.find_index(x => x % 2 == 0), content="Some(1)")
    debug_inspect(ls.find_index(x => x > 10), content="None")
    }

    List::findi

    fn[A] List::findi(self : List[A], f : (A, Int) -> Bool raise?) -> A? raise?

    Find the first element in the list that satisfies f and passes the index as an argument.

    Example

    test {
    assert_true(
    @list.List([1, 3, 5, 8]).findi((element, index) => {
    element % 2 == 0 && index == 3
    }) ==
    Some(8),
    )
    assert_true(
    @list.List([1, 3, 8, 5]).findi((element, index) => {
    element % 2 == 0 && index == 3
    }) ==
    None,
    )
    }

    List::flat_map

    fn[A, B] List::flat_map(self : List[A], f : (A) -> List[B] raise?) -> List[B] raise?

    map over the list and concat all results.

    ls.flat_map(f) is equivalent to ls.map(f).fold(init=Empty, (acc, x) => acc.concat(x))

    Example

    test {
    let ls = @list.List([1, 2, 3])
    let r = ls.flat_map(x => List([x, x * 2]))
    @debug.assert_eq(r, List([1, 2, 2, 4, 3, 6]))
    }

    List::flatten

    fn[A] List::flatten(self : List[List[A]]) -> List[A]

    flatten a list of lists.

    Example

    test {
    let ls = @list.List([@list.List([1, 2, 3]), List([4, 5, 6]), List([7, 8, 9])]).flatten()
    @debug.assert_eq(ls, List([1, 2, 3, 4, 5, 6, 7, 8, 9]))
    }

    List::fold

    fn[A, B] List::fold(self : List[A], init~ : B, f : (B, A) -> B raise?) -> B raise?

    Fold the list from left.

    Example

    test {
    let r = @list.List([1, 2, 3, 4, 5]).fold(init=0, (acc, x) => acc + x)
    inspect(r, content="15")
    }

    List::foldi

    fn[A, B] List::foldi(self : List[A], init~ : B, f : (Int, B, A) -> B raise?) -> B raise?

    Fold the list from left with index.

    Similar to fold, but the accumulator function also receives the index of the current element.

    Example

    test {
    let ls = @list.List([10, 20, 30])
    let result = ls.foldi(init=0, (i, acc, x) => acc + x * i)
    inspect(result, content="80") // 0*10 + 1*20 + 2*30 = 80
    }

    List::from_array

    #deprecated("Use @list.List([...]) instead")
    #as_free_fn(of, deprecated="Use @list.List([...]) instead")
    #alias(of, deprecated="Use @list.List([...]) instead")
    #as_free_fn(deprecated="Use @list.List([...]) instead")
    fn[A] List::from_array(arr : ArrayView[A]) -> List[A]

    Convert array to list.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    @debug.assert_eq(ls, List([1, 2, 3, 4, 5]))
    }

    List::from_iter

    #as_free_fn(from_iterator, deprecated="Use List::from_iter instead.")
    #alias(from_iterator, deprecated="`from_iterator` is deprecated, use `from_iter` instead")
    #as_free_fn
    fn[A] List::from_iter(iter : Iter[A]) -> List[A]

    Convert an iterator into a list, preserving order of elements.

    Creates a list from an iterator, maintaining the same order as the iterator. If order is not important, consider using from_iter_rev for better performance.

    Example

    test {
    let arr = [1, 2, 3, 4, 5]
    let iter = arr.iter()
    let ls = @list.from_iter(iter)
    @debug.assert_eq(ls, List([1, 2, 3, 4, 5]))
    }

    List::from_iter_rev

    #as_free_fn(from_iterator_rev, deprecated="Use List::from_iter_rev instead.")
    #alias(from_iterator_rev, deprecated="`from_iterator_rev` is deprecated, use `from_iter_rev` instead")
    #as_free_fn
    fn[A] List::from_iter_rev(iter : Iter[A]) -> List[A]

    Convert an iterator into a list in reverse order.

    Creates a list from an iterator, but the resulting list will have elements in reverse order compared to the iterator. This is more efficient than from_iter when order doesn't matter.

    Example

    test {
    let arr = [1, 2, 3, 4, 5]
    let iter = arr.iter()
    let ls = @list.from_iter_rev(iter)
    @debug.assert_eq(ls, List([5, 4, 3, 2, 1]))
    }

    List::from_json

    Parse JSON into a list.

    Converts a JSON array into a list of the specified type.

    List::has_prefix

    #alias(is_prefix, deprecated="`is_prefix` is deprecated, use `has_prefix` instead")
    fn[A : Eq] List::has_prefix(self : List[A], prefix : List[A]) -> Bool

    Returns true if list starts with prefix.

    Example

    test {
    @test.assert_eq(@list.List([1, 2, 3, 4, 5]).has_prefix(List([1, 2, 3])), true)
    }

    List::has_suffix

    #alias(is_suffix, deprecated="`is_suffix` is deprecated, use `has_suffix` instead")
    fn[A : Eq] List::has_suffix(self : List[A], suffix : List[A]) -> Bool

    Returns true if list ends with suffix.

    Example

    test {
    @test.assert_eq(@list.List([1, 2, 3, 4, 5]).has_suffix(List([3, 4, 5])), true)
    }

    List::hash

    fn[A : Hash] List::hash(self : List[A]) -> Int

    List::head

    fn[A] List::head(self : List[A]) -> A?

    Get first element of the list.

    Example

    test {
    assert_true(@list.List([1, 2, 3, 4, 5]).head() == Some(1))
    }

    List::intercalate

    fn[A] List::intercalate(self : List[List[A]], sep : List[A]) -> List[A]

    Insert separator lists between lists and flatten the result.

    Similar to intersperse, but works with lists of lists. Inserts the separator list between each list in the input, then flattens everything into a single list.

    Example

    test {
    let ls = @list.List([@list.List([1, 2, 3]), List([4, 5, 6]), List([7, 8, 9])])
    let r = ls.intercalate(List([0]))
    @debug.assert_eq(r, List([1, 2, 3, 0, 4, 5, 6, 0, 7, 8, 9]))
    }

    List::intersperse

    fn[A] List::intersperse(self : List[A], separator : A) -> List[A]

    Insert separator to the list.

    Example

    test {
    let ls = @list.List(["1", "2", "3", "4", "5"]).intersperse("|")
    @debug.assert_eq(ls, List(["1", "|", "2", "|", "3", "|", "4", "|", "5"]))
    }

    List::is_empty

    fn[A] List::is_empty(self : List[A]) -> Bool

    Check if the list is empty.

    Returns true if the list contains no elements, false otherwise.

    Example

    test {
    let empty_list : @list.List[Int] = @list.empty()
    @test.assert_eq(empty_list.is_empty(), true)
    let non_empty = @list.List([1, 2, 3])
    @test.assert_eq(non_empty.is_empty(), false)
    }

    List::iter

    #alias(iterator, deprecated="`iterator` is deprecated, use `iter` instead")
    fn[A] List::iter(self : List[A]) -> Iter[A]

    Create an iterator over the list elements.

    Returns an iterator that yields each element of the list in order.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let iter = ls.iter()
    let sum = iter.fold(init=0, (acc, x) => acc + x)
    inspect(sum, content="15")
    }

    List::iter2

    #alias(iterator2, deprecated="`iterator2` is deprecated, use `iter2` instead")
    fn[A] List::iter2(self : List[A]) -> Iter2[Int, A]

    Create an iterator over the list elements with indices.

    Returns an iterator that yields pairs of (index, element) for each element in the list.

    Example

    test {
    let ls = @list.List([10, 20, 30])
    let iter = ls.iter2()
    debug_inspect(iter.to_array(), content="[(0, 10), (1, 20), (2, 30)]")
    }

    List::last

    fn[A] List::last(self : List[A]) -> A?

    Last element of the list.

    Example

    test {
    assert_true(@list.List([1, 2, 3, 4, 5]).last() == Some(5))
    }

    List::length

    fn[A] List::length(self : List[A]) -> Int

    Get the length of the list.

    List::lookup

    fn[A : Eq, B] List::lookup(self : List[(A, B)], v : A) -> B?

    Looks up a key in an association list.

    Example

    test {
    let ls = @list.List([(1, "a"), (2, "b"), (3, "c")])
    assert_true(ls.lookup(3) == Some("c"))
    }

    List::map

    fn[A, B] List::map(self : List[A], f : (A) -> B raise?) -> List[B] raise?

    Maps the list.

    Example

    test {
    @debug.assert_eq(
    @list.List([1, 2, 3, 4, 5]).map(x => x * 2),
    List([2, 4, 6, 8, 10]),
    )
    }

    List::mapi

    fn[A, B] List::mapi(self : List[A], f : (Int, A) -> B raise?) -> List[B] raise?

    Maps the list with index.

    Applies a function to each element and its index, creating a new list with the results.

    Example

    test {
    let ls = @list.List([10, 20, 30])
    let result = ls.mapi((i, x) => x + i)
    @debug.assert_eq(result, List([10, 21, 32]))
    }

    List::maximum

    fn[A : Compare + Eq] List::maximum(self : List[A]) -> A?

    Get the maximum element of the list.

    Returns Some(element) with the largest element, or None if the list is empty. Elements are compared using the Compare trait.

    Example

    test {
    let ls = @list.List([1, 3, 2, 5, 4])
    assert_true(ls.maximum() == Some(5))
    let empty : @list.List[Int] = @list.empty()
    assert_true(empty.maximum() == None)
    }

    List::minimum

    fn[A : Compare + Eq] List::minimum(self : List[A]) -> A?

    Get the minimum element of the list.

    Returns Some(element) with the smallest element, or None if the list is empty. Elements are compared using the Compare trait.

    Example

    test {
    let ls = @list.List([1, 3, 2, 5, 4])
    assert_true(ls.minimum() == Some(1))
    let empty : @list.List[Int] = @list.empty()
    assert_true(empty.minimum() == None)
    }

    List::new

    #as_free_fn(empty)
    #as_free_fn
    #alias(empty)
    fn[A] List::new() -> List[A]

    Creates an empty list.

    Example

    test {
    let ls : @list.List[Int] = @list.new()
    @debug.assert_eq(ls, @list.empty())
    }

    List::nth

    fn[A] List::nth(self : List[A], n : Int) -> A?

    Get the nth element of the list.

    Returns Some(element) if the index is valid, or None if the index is out of bounds.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    assert_true(ls.nth(2) == Some(3))
    assert_true(ls.nth(10) == None)
    }

    List::prepend

    #alias(add)
    fn[A] List::prepend(self : List[A], head : A) -> List[A]

    Prepend an element to the front of the list.

    Creates a new list with the given element added to the beginning.

    Example

    test {
    let ls = @list.List([2, 3, 4]).prepend(1)
    @debug.assert_eq(ls, List([1, 2, 3, 4]))
    }

    List::remove

    fn[A : Eq] List::remove(self : List[A], elem : A) -> List[A]

    Removes the first occurrence of the specified element from the list, if it is present.

    Example

    test {
    @debug.assert_eq(@list.List([1, 2, 3, 4, 5]).remove(3), List([1, 2, 4, 5]))
    }

    List::remove_at

    fn[A] List::remove_at(self : List[A], index : Int) -> List[A]

    Removes the element at the specified index in the list.

    Example

    test {
    @debug.assert_eq(@list.List([1, 2, 3, 4, 5]).remove_at(2), List([1, 2, 4, 5]))
    }

    List::repeat

    #as_free_fn
    fn[A] List::repeat(n : Int, x : A) -> List[A]

    Create a list of length n with the given value.

    Aborts if n is negative. When n is 0, returns the empty list.

    Example

    test {
    @debug.assert_eq(@list.repeat(5, 1), List([1, 1, 1, 1, 1]))
    }

    List::rev

    fn[A] List::rev(self : List[A]) -> List[A]

    Reverse the list.

    Example

    test {
    @debug.assert_eq(@list.List([1, 2, 3, 4, 5]).rev(), List([5, 4, 3, 2, 1]))
    }

    List::rev_concat

    fn[A] List::rev_concat(self : List[A], other : List[A]) -> List[A]

    Reverse the first list and concatenate it with the second.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5]).rev_concat(List([6, 7, 8, 9, 10]))
    @debug.assert_eq(ls, List([5, 4, 3, 2, 1, 6, 7, 8, 9, 10]))
    }

    List::rev_fold

    #deprecated("use `_.to_array().rev_fold(...)` instead")
    fn[A, B] List::rev_fold(self : List[A], init~ : B, f : (B, A) -> B) -> B

    Function rev_fold.

    List::rev_foldi

    #deprecated("use `_.rev().foldi(...)` instead")
    fn[A, B] List::rev_foldi(self : List[A], init~ : B, f : (Int, B, A) -> B) -> B

    Function rev_foldi.

    List::rev_map

    fn[A, B] List::rev_map(self : List[A], f : (A) -> B raise?) -> List[B] raise?

    Maps the list and reverses the result.

    list.rev_map(f) is equivalent to list.map(f).rev() but more efficient.

    Example

    test {
    @debug.assert_eq(
    @list.List([1, 2, 3, 4, 5]).rev_map(x => x * 2),
    List([10, 8, 6, 4, 2]),
    )
    }

    List::rev_unfold

    #as_free_fn
    fn[A, S] List::rev_unfold(f : (S) -> (A, S)? raise?, init~ : S) -> List[A] raise?

    Produces a list iteratively in reverse order.

    Similar to unfold, but the resulting list will be in reverse order compared to the generation order. This can be more efficient when you don't need to preserve the generation order.

    Example

    test {
    let r = @list.rev_unfold(
    i => if i == 3 { None } else { Some((i, i + 1)) },
    init=0,
    )
    @debug.assert_eq(r, List([2, 1, 0]))
    }

    List::scan_left

    fn[A, E] List::scan_left(self : List[A], f : (E, A) -> E raise?, init~ : E) -> List[E] raise?

    Fold a list and return a list of successive reduced values from the left

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let r = ls.scan_left((acc, x) => acc + x, init=0)
    @debug.assert_eq(r, List([0, 1, 3, 6, 10, 15]))
    }

    List::scan_right

    fn[A, B] List::scan_right(self : List[A], f : (B, A) -> B raise?, init~ : B) -> List[B] raise?

    Fold a list and return a list of successive reduced values from the right

    Note that the order of parameters on the accumulating function are reversed.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let r = ls.scan_right((acc, x) => acc + x, init=0)
    @debug.assert_eq(r, List([15, 14, 12, 9, 5, 0]))
    }

    List::singleton

    #as_free_fn
    fn[A] List::singleton(x : A) -> List[A]

    Create a list with a single element.

    Returns a list containing only the given element.

    Example

    test {
    let ls = @list.singleton(42)
    @debug.assert_eq(ls, List([42]))
    @test.assert_eq(ls.length(), 1)
    }

    List::sort

    fn[A : Compare + Eq] List::sort(self : List[A]) -> List[A]

    Sort the list in ascending order.

    Example

    test {
    let ls = @list.List([1, 123, 52, 3, 6, 0, -6, -76]).sort()
    @debug.assert_eq(ls, List([-76, -6, 0, 1, 3, 6, 52, 123]))
    }

    List::tail

    #deprecated("use `unsafe_tail` instead")
    fn[A] List::tail(self : List[A]) -> List[A]

    Function tail.

    List::take

    fn[A] List::take(self : List[A], n : Int) -> List[A]

    Take first n elements of the list. If the list is shorter than n, return the whole list.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let r = ls.take(3)
    @debug.assert_eq(r, List([1, 2, 3]))
    }

    List::take_while

    fn[A] List::take_while(self : List[A], p : (A) -> Bool raise?) -> List[A] raise?

    Take the longest prefix of a list of elements that satisfies a given predicate.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4])
    let r = ls.take_while(x => x < 3)
    @debug.assert_eq(r, List([1, 2]))
    }

    List::to_array

    fn[A] List::to_array(self : List[A]) -> Array[A]

    Convert list to array.

    Creates a new array containing all elements from the list in the same order.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let arr = ls.to_array()
    @debug.assert_eq(arr, [1, 2, 3, 4, 5])
    }

    List::to_json

    fn[A : ToJson] List::to_json(self : List[A]) -> Json

    Convert a list to JSON.

    Example

    test {
    let ls = @list.List([1, 2, 3])
    let json = ls.to_json()
    @debug.debug_inspect(json, content="Array([Number(1), Number(2), Number(3)])")
    }

    List::unfold

    #as_free_fn
    fn[A, S] List::unfold(f : (S) -> (A, S)? raise?, init~ : S) -> List[A] raise?

    Produces a collection iteratively.

    Example

    test {
    let r = @list.unfold(init=0, i => if i == 3 { None } else { Some((i, i + 1)) })
    @debug.assert_eq(r, List([0, 1, 2]))
    }

    List::unsafe_tail

    fn[A] List::unsafe_tail(self : List[A]) -> List[A]

    Get the tail (all elements except the first) of the list.

    Warning: This function panics if the list is empty. Use pattern matching or other safe methods for empty lists.

    Example

    test {
    let ls = @list.List([1, 2, 3, 4, 5])
    let tail = ls.unsafe_tail()
    @debug.assert_eq(tail, List([2, 3, 4, 5]))
    }

    Panics

    Panics if the list is empty.

    List::unzip

    fn[A, B] List::unzip(self : List[(A, B)]) -> (List[A], List[B])

    Unzip two lists.

    Example

    test {
    let (a, b) = @list.List([(1, 2), (3, 4), (5, 6)]).unzip()
    @debug.assert_eq(a, List([1, 3, 5]))
    @debug.assert_eq(b, List([2, 4, 6]))
    }

    List::zip

    #as_free_fn
    fn[A, B] List::zip(self : List[A], other : List[B]) -> List[(A, B)]

    Zip two lists together into a list of tuples.

    Combines elements from two lists pairwise. If the lists have different lengths, the result will have the length of the shorter list.

    Example

    test {
    let r = @list.zip(List([1, 2, 3, 4, 5]), List([6, 7, 8, 9, 10]))
    @debug.assert_eq(r, List([(1, 6), (2, 7), (3, 8), (4, 9), (5, 10)]))
    let r2 = @list.zip(List([1, 2]), List([6, 7, 8, 9, 10]))
    @debug.assert_eq(r2, List([(1, 6), (2, 7)]))
    }

    default

    fn[X] default() -> List[X]

    Return the default value for a list (empty list).

    Example

    test {
    let ls : @list.List[Int] = @list.default()
    @test.assert_eq(ls.is_empty(), true)
    }