List

The List module provides functions for working with immutable, ordered sequences of elements. Lists are one of the most commonly used data structures in Kit.

Bare vs Module Functions

Most list functions are available both as bare functions (map, filter) and with the module prefix (List.map, List.filter).

Important: Some accessor functions differ between bare and module forms: bare head, first, last return the element directly (raising an error on empty lists), while List.head, List.first, List.last return Option a for safe access.

Creating Lists

List Literal
[a] : List a
Create a list using square bracket notation.
numbers = [1, 2, 3, 4, 5]
names = ["Alice", "Bob", "Carol"]
empty = []
List.empty
List a
The empty list. Equivalent to [].
empty = List.empty
println (List.is-empty? empty)
# => true
List.range
Int -> Int -> List Int
Create a list of integers from start to end (exclusive). Also available as the built-in vec-range.
nums = List.range 1 6
# => [1, 2, 3, 4, 5]

evens = List.range 0 10 |> filter (fn(x) => x % 2 == 0)
# => [0, 2, 4, 6, 8]
List.replicate
Int -> a -> List a
Create a list containing n copies of a value.
zeros = List.replicate 5 0
# => [0, 0, 0, 0, 0]

greetings = List.replicate 3 "hello"
# => ["hello", "hello", "hello"]

Accessing Elements

head
List a -> a
Returns the first element of a list. Raises an error on empty list.
println (head [1, 2, 3])
# => 1
List.head
List a -> Option a
Returns Some first element of a list, or None if empty. Safe version of head.
println (List.head [1, 2, 3])
# => Some(1)

println (List.head [])
# => None
List.first
List a -> Option a
Returns Some first element of a list, or None if empty. Alias for List.head.
println (List.first ["a", "b"])
# => Some("a")
tail
List a -> List a
Returns all elements except the first. Also available as the built-ins rest and List.rest.
println (tail [1, 2, 3])
# => [2, 3]
List.second
List a -> a
Returns the second element of a list. Raises an error if the list has fewer than two elements.
println (List.second [1, 2, 3])
# => 2
last
List a -> a
Returns the last element of a list. Raises an error on empty list.
println (last [1, 2, 3])
# => 3
List.last
List a -> Option a
Returns Some last element of a list, or None if empty. Safe version of last.
println (List.last [1, 2, 3])
# => Some(3)

println (List.last [])
# => None
nth
Int -> List a -> Option a
Returns Some element at the given index (0-based), or None if out of bounds.
items = ["a", "b", "c"]
println (nth 1 items)
# => Some("b")

println (nth 10 items)
# => None
List.get
Int -> List a -> Option a
Returns Some element at the given index (0-based), or None if out of bounds. Alias for nth.
println (List.get 0 [10, 20, 30])
# => Some(10)
List.set
Int -> a -> List a -> List a
Returns a new list with the element at the given index replaced.
println (List.set 1 "X" ["a", "b", "c"])
# => ["a", "X", "c"]
List.init
List a -> List a
Returns all elements except the last. The opposite of tail.
println (List.init [1, 2, 3, 4])
# => [1, 2, 3]
length
List a -> Int
Returns the number of elements in a list. Also available as the built-ins len and count.
println (length [1, 2, 3, 4, 5])
# => 5
empty?
List a -> Bool
Returns true if the list has no elements.
println (empty? [])         # => true
println (empty? [1, 2])    # => false
List.is-empty?
List a -> Bool
Returns true if the list has no elements. Alias for empty?.
println (List.is-empty? [])         # => true
println (List.is-empty? [1, 2])    # => false

Transforming Lists

map
(a -> b) -> List a -> List b
Applies a function to every element of a list, returning a new list of results.
doubled = map (fn(x) => x * 2) [1, 2, 3]
# => [2, 4, 6]

# With pipe operator
result = [1, 2, 3] |> map (fn(x) => x * x)
# => [1, 4, 9]
reverse
List a -> List a
Returns a new list with elements in reverse order.
println (reverse [1, 2, 3])
# => [3, 2, 1]
List.sort
List a -> List a
Returns a new list with elements sorted in ascending order.
println (List.sort [3, 1, 4, 1, 5])
# => [1, 1, 3, 4, 5]
List.flat-map
(a -> List b) -> List a -> List b
Maps a function over a list and flattens the result. Equivalent to flatten (map f xs).
result = List.flat-map (fn(x) => [x, x * 10]) [1, 2, 3]
# => [1, 10, 2, 20, 3, 30]
List.scan
(b -> a -> b) -> b -> List a -> List b
Like fold, but returns a list of all intermediate accumulator values.
result = List.scan (fn(acc, x) => acc + x) 0 [1, 2, 3]
# => [1, 3, 6] (running sums)
List.intersperse
a -> List a -> List a
Inserts an element between all elements of a list.
println (List.intersperse 0 [1, 2, 3])
# => [1, 0, 2, 0, 3]
List.interleave
List a -> List a -> List a
Interleaves two lists, alternating elements.
println (List.interleave [1, 2, 3] [10, 20, 30])
# => [1, 10, 2, 20, 3, 30]

Filtering

filter
(a -> Bool) -> List a -> List a
Returns a new list containing only elements for which the predicate returns true.
evens = filter (fn(x) => x % 2 == 0) [1, 2, 3, 4, 5]
# => [2, 4]

positives = [-2, -1, 0, 1, 2] |> filter (fn(x) => x > 0)
# => [1, 2]
take
Int -> List a -> List a
Returns the first n elements of a list.
println (take 3 [1, 2, 3, 4, 5])
# => [1, 2, 3]
drop
Int -> List a -> List a
Returns the list without its first n elements.
println (drop 2 [1, 2, 3, 4, 5])
# => [3, 4, 5]
List.slice-from
Int -> List a -> List a
Returns a slice of the list from the given index to the end.
println (List.slice-from 2 [1, 2, 3, 4, 5])
# => [3, 4, 5]

items = ["a", "b", "c", "d"]
println (List.slice-from 1 items)
# => ["b", "c", "d"]
List.slice
Int -> Int -> List a -> List a
Returns a slice of the list from start index to end index (exclusive).
println (List.slice 1 4 [0, 1, 2, 3, 4])
# => [1, 2, 3]
List.take-while
(a -> Bool) -> List a -> List a
Takes elements from the front while the predicate holds.
println (List.take-while (fn(x) => x < 4) [1, 2, 3, 5, 2])
# => [1, 2, 3]
List.drop-while
(a -> Bool) -> List a -> List a
Drops elements from the front while the predicate holds.
println (List.drop-while (fn(x) => x < 4) [1, 2, 3, 5, 2])
# => [5, 2]
List.take-last
Int -> List a -> List a
Returns the last n elements of a list.
println (List.take-last 2 [1, 2, 3, 4, 5])
# => [4, 5]
List.drop-last
Int -> List a -> List a
Returns the list without its last n elements.
println (List.drop-last 2 [1, 2, 3, 4, 5])
# => [1, 2, 3]

Reducing

fold
(b -> a -> b) -> b -> List a -> b
Reduces a list to a single value by applying a function to an accumulator and each element, from left to right.
# Sum all numbers
total = fold (fn(acc, x) => acc + x) 0 [1, 2, 3, 4, 5]
# => 15

# Build a string
joined = fold (fn(acc, s) => acc ++ s) "" ["a", "b", "c"]
# => "abc"
reduce
(a -> a -> a) -> List a -> a
Like fold, but uses the first element as the initial accumulator.
product = reduce (fn(a, b) => a * b) [1, 2, 3, 4]
# => 24

largest = reduce max [3, 1, 4, 1, 5]
# => 5
sum
List Int -> Int
Returns the sum of all elements in a list of integers.
println (sum [1, 2, 3, 4, 5])
# => 15
product
List Int -> Int
Returns the product of all elements in a list of integers.
println (product [1, 2, 3, 4])
# => 24
List.frequencies
List a -> Map a Int
Returns a map where keys are unique elements from the list and values are the count of how many times each element appears.
counts = List.frequencies [1, 2, 1, 3, 2, 1]
# => {1: 3, 2: 2, 3: 1}

word-counts = List.frequencies ["apple", "banana", "apple", "cherry"]
# => {"apple": 2, "banana": 1, "cherry": 1}

Combining Lists

concat / ++
List a -> List a -> List a
Concatenates two lists. The ++ operator is an alias.
combined = concat [1, 2] [3, 4]
# => [1, 2, 3, 4]

combined2 = [1, 2] ++ [3, 4]
# => [1, 2, 3, 4]
cons
a -> List a -> List a
Prepends an element to the front of a list.
result = cons 0 [1, 2, 3]
# => [0, 1, 2, 3]
append
List a -> a -> List a
Appends an element to the end of a list.
result = append [1, 2, 3] 4
# => [1, 2, 3, 4]
flatten
List (List a) -> List a
Flattens a list of lists into a single list.
nested = [[1, 2], [3, 4], [5]]
println (flatten nested)
# => [1, 2, 3, 4, 5]
zip-with
(a -> b -> c) -> List a -> List b -> List c
Combines two lists element-wise using a function.
sums = zip-with (fn(a, b) => a + b) [1, 2, 3] [10, 20, 30]
# => [11, 22, 33]
List.zip
List a -> List b -> List (a, b)
Combines two lists into a list of pairs. Stops at the length of the shorter list.
println (List.zip [1, 2, 3] ["a", "b", "c"])
# => [(1, "a"), (2, "b"), (3, "c")]
List.unzip
List (a, b) -> (List a, List b)
Splits a list of pairs into two lists. The inverse of List.zip.
(nums, strs) = List.unzip [(1, "a"), (2, "b"), (3, "c")]
# nums => [1, 2, 3]
# strs => ["a", "b", "c"]
List.zip3
List a -> List b -> List c -> List (Tuple a b c)
Combines three lists into a list of 3-tuples. Stops at the length of the shortest list.
numbers = [1, 2, 3]
letters = ["a", "b", "c"]
bools = [true, false, true]

result = List.zip3 numbers letters bools
# => [(1, "a", true), (2, "b", false), (3, "c", true)]

Searching

contains?
a -> List a -> Bool
Returns true if the list contains the given element.
println (contains? 3 [1, 2, 3, 4])
# => true

println (contains? 5 [1, 2, 3, 4])
# => false
each
(a -> ()) -> List a -> ()
Applies a function to each element for its side effects.
[1, 2, 3] |> each (fn(x) => println x)
# Prints: 1, 2, 3 (each on new line)
List.find
(a -> Bool) -> List a -> Option a
Returns the first element matching the predicate, or None if none match.
result = List.find (fn(x) => x > 3) [1, 2, 5, 4]
# => Some(5)

result = List.find (fn(x) => x > 10) [1, 2, 3]
# => None
List.find-index
(a -> Bool) -> List a -> Option Int
Returns the index of the first element matching the predicate, or None if none match.
result = List.find-index (fn(x) => x > 3) [1, 2, 5, 4]
# => Some(2)
List.find-by
(a -> b) -> b -> List a -> Option a
Finds an element by applying a key function and comparing the result.
users = [{name: "Alice", id: 1}, {name: "Bob", id: 2}]
result = List.find-by (fn(u) => u.id) 2 users
# => Some({name: "Bob", id: 2})
List.any?
(a -> Bool) -> List a -> Bool
Returns true if any element matches the predicate.
println (List.any? (fn(x) => x > 3) [1, 2, 5])
# => true

println (List.any? (fn(x) => x > 10) [1, 2, 3])
# => false
List.all?
(a -> Bool) -> List a -> Bool
Returns true if all elements match the predicate.
println (List.all? (fn(x) => x > 0) [1, 2, 3])
# => true

println (List.all? (fn(x) => x > 2) [1, 2, 3])
# => false
List.count
(a -> Bool) -> List a -> Int
Counts elements matching the predicate. Different from bare count which returns list length.
println (List.count (fn(x) => x > 2) [1, 2, 3, 4, 5])
# => 3
List.binary-search
a -> List a -> Option Int
Binary search in a sorted list. Returns Some index if found, None otherwise.
sorted = [1, 3, 5, 7, 9]
println (List.binary-search 5 sorted)
# => Some(2)
List.binary-search-by
(a -> b) -> b -> List a -> Option Int
Binary search by a key function. Returns Some index if found, None otherwise.
users = [{id: 1, name: "Alice"}, {id: 3, name: "Bob"}, {id: 5, name: "Carol"}]
println (List.binary-search-by (fn(u) => u.id) 3 users)
# => Some(1)
List.lower-bound
a -> List a -> Int
Returns the index of the first element not less than the given value in a sorted list.
sorted = [1, 3, 3, 5, 7]
println (List.lower-bound 3 sorted)
# => 1
List.upper-bound
a -> List a -> Int
Returns the index of the first element greater than the given value in a sorted list.
sorted = [1, 3, 3, 5, 7]
println (List.upper-bound 3 sorted)
# => 3

Sorting

List.sort-by
(a -> b) -> List a -> List a
Sorts by applying a key function to each element.
users = [{name: "Bob"}, {name: "Alice"}]
sorted = List.sort-by (fn(u) => u.name) users
# => [{name: "Alice"}, {name: "Bob"}]
List.sort-with
(a -> a -> Int) -> List a -> List a
Sorts using a custom comparator function that returns -1, 0, or 1.
# Sort descending
desc = List.sort-with (fn(a, b) => b - a) [3, 1, 4]
# => [4, 3, 1]
List.minimum
List a -> Option a
Returns the minimum element, or None if the list is empty.
println (List.minimum [3, 1, 4])
# => Some(1)

println (List.minimum [])
# => None
List.maximum
List a -> Option a
Returns the maximum element, or None if the list is empty.
println (List.maximum [3, 1, 4])
# => Some(4)
List.min-by
(a -> b) -> List a -> Option a
Returns the element with the minimum key, or None if empty.
users = [{name: "Alice", age: 30}, {name: "Bob", age: 25}]
youngest = List.min-by (fn(u) => u.age) users
# => Some({name: "Bob", age: 25})
List.max-by
(a -> b) -> List a -> Option a
Returns the element with the maximum key, or None if empty.
users = [{name: "Alice", age: 30}, {name: "Bob", age: 25}]
oldest = List.max-by (fn(u) => u.age) users
# => Some({name: "Alice", age: 30})
List.min-with
(a -> a -> Int) -> List a -> Option a
Returns the minimum element using a custom comparator, or None if empty.
items = ["banana", "apple", "cherry"]
shortest = List.min-with (fn(a, b) => length(a) - length(b)) items
# => Some("apple")
List.max-with
(a -> a -> Int) -> List a -> Option a
Returns the maximum element using a custom comparator, or None if empty.
items = ["banana", "apple", "cherry"]
longest = List.max-with (fn(a, b) => length(a) - length(b)) items
# => Some("banana")

Partitioning

List.partition
(a -> Bool) -> List a -> (List a, List a)
Splits a list into two: elements matching the predicate and those that don't.
(evens, odds) = List.partition (fn(x) => x % 2 == 0) [1, 2, 3, 4, 5]
# evens => [2, 4]
# odds => [1, 3, 5]
List.split-at
Int -> List a -> (List a, List a)
Splits a list at the given index into two parts.
(before, after) = List.split-at 2 [1, 2, 3, 4, 5]
# before => [1, 2]
# after => [3, 4, 5]
List.unique
List a -> List a
Removes duplicate elements, keeping the first occurrence.
println (List.unique [1, 2, 1, 3, 2])
# => [1, 2, 3]
List.unique-by
(a -> b) -> List a -> List a
Removes duplicates based on a key function.
users = [{name: "Alice", dept: "A"}, {name: "Bob", dept: "A"}]
unique-depts = List.unique-by (fn(u) => u.dept) users
# => [{name: "Alice", dept: "A"}]
List.group-by
(a -> b) -> List a -> List (List a)
Groups elements by a key function.
items = [{type: "a", val: 1}, {type: "b", val: 2}, {type: "a", val: 3}]
grouped = List.group-by (fn(x) => x.type) items
# => [[{type: "a", val: 1}, {type: "a", val: 3}], [{type: "b", val: 2}]]
List.partition-by
(a -> b) -> List a -> List (List a)
Partitions into groups of consecutive elements with the same key.
result = List.partition-by (fn(x) => x % 2) [1, 3, 2, 4, 5]
# => [[1, 3], [2, 4], [5]]

Built-ins

These functions are available without a module prefix.

first
List a -> a
Returns the first element of a list. Equivalent to head.
println (first ["a", "b", "c"])
# => "a"
rest
List a -> List a
Returns all elements except the first. Equivalent to tail.
println (rest ["a", "b", "c"])
# => ["b", "c"]
len
a -> Int
Returns the number of elements in any collection. Equivalent to length for lists.
println (len ["a", "b", "c"])
# => 3
count
a -> Int
Returns the number of elements in any collection. Equivalent to len.
println (count [10, 20])
# => 2
vec-range
Int -> Int -> List Int
Creates a list of integers from start to end (exclusive). Equivalent to List.range.
println (vec-range 0 5)
# => [0, 1, 2, 3, 4]