Nanyx

collections

Operations on collections such as lists, maps, and sets

The collections module provides functions for working with lists, maps, sets, and other collection types.

List

Since lists are immutable, all transform operations on lists return new lists.

These functions are attached definitions on List, so xs \map(f) and xs.map(f) both resolve to List.map without qualification when xs is a list.

all

List.all: (list(a), (a -> bool)) -> bool

Returns true if all elements satisfy the predicate.

[1, 2, 3] \List.all { > 0 }
-- true

Note: it can seem counter intuitive, but List.all always returns true for an empty list, since there are no elements that fail the predicate.


any

List.any: (list(a), (a -> bool)) -> bool

Returns true if any element satisfies the predicate.

[1, 2, 3] \List.any { > 2 }
-- true

Note: it can seem counter intuitive, but List.any returns false for an empty list, since there are no elements that satisfy the predicate.


append

List.append: (list(a), a) -> list(a)

Returns a new list with the element added to the end.

[1, 2] \List.append(3)
-- [1, 2, 3]

distinct

List.distinct: list(a) -> list(a)

Returns a new list with duplicate values removed, keeping first occurrence order.

List.distinct([1, 2, 2, 3, 1])
-- [1, 2, 3]

filter

List.filter: (list(a), (a -> bool)) -> list(a)

Keeps only elements that satisfy the predicate.

[1, 2, 3, 4, 5] \List.filter { > 3 }
-- [4, 5]

find

List.find: (list(a), (a -> bool)) -> #some(a) | #notFound

Returns the first element matching the predicate.

[1, 2, 3] \List.find { > 1 }
-- #some(2)

flatten

List.flatten: list(list(a)) -> list(a)

Flattens a list of lists into a single list.

List.flatten([[1, 2], [3, 4]])
-- [1, 2, 3, 4]

List.head: list(a) -> #some(a) | #emptyList

Returns the first element if the list is non-empty.

List.head([10, 20, 30])
-- #some(10)

fold

List.fold: (list(a), b, ((b, a) -> b)) -> b

Reduces a list to a single value. Runs through the list from left to right, applying the function to an accumulator and each element.

[1, 2, 3] \List.fold(0) { + }
-- 6

foldBack

List.foldBack: (list(a), b, ((b, a) -> b)) -> b

Reduces a list to a single value. Runs through the list backwards (from right to left), applying the function to an accumulator and each element.

[1, 2, 3] \List.foldBack(0) { - }
-- -6, i.e. ((0 - 3) - 2) - 1

groupBy

List.groupBy: (list(a), (a -> b)) -> map(b, list(a))

Groups elements of a list by a key function, returning a map from keys to lists of elements.

[1, 2, 3, 4] \List.groupBy { % 2 }
-- Map [ 0 => [2, 4], 1 => [1, 3] ]

length

List.length: list(a) -> int

Returns the number of elements.

List.length([1, 2, 3])
-- 3

map

List.map: (list(a), (a -> b)) -> list(b)

Applies a function to every element in a list, collecting the results in a new list. The resulting list always has the same length as the input list.

[1, 2, 3] \List.map { * 2 }
-- [2, 4, 6]

reverse

List.reverse: list(a) -> list(a)

Returns a new list with elements in reverse order.

List.reverse([1, 2, 3])
-- [3, 2, 1]

skip

List.skip: (list(a), int) -> list(a)

Returns a list without the first count elements.

List.skip([1, 2, 3, 4], 2)
-- [3, 4]

sortBy

List.sortBy: (list(a), (a -> b)) -> list(a)

Sorts a list using the projection function as the key.

List.sortBy(["bbb", "a", "cc"], { .length })
-- ["a", "cc", "bbb"]

take

List.take: (list(a), int) -> list(a)

Returns the first count elements.

List.take([1, 2, 3, 4], 2)
-- [1, 2]

select

List.select: (list(a), [Yield(b)] (a -> ())) -> list(b)

For every element in the input list, runs the function with a Yield context that allows it to yield any number of output elements. Collects all yielded elements into a new list.

select can be thought of as a map and a filter at the same time, or a map followed by a flatten (but more efficient since it doesn’t create intermediate lists).

type Color = #red | #green | #blue | #other(string)

def f: list(Color) -> list(string) = { items ->
    items \List.select { item ->
        if #other(v) = item then yield(v)
    }
}

selectOne

List.selectOne: (list(a), [Yield(b)] (a -> ())) -> #some(b) | #emptyList

For every element in the input list, runs the function with a Yield context that allows it to yield any number of output elements. Immediately returns the first yielded element wrapped in #some, or #emptyList if no elements were yielded.

selectOne can be thought of as a map and a find at the same time.

type Color = #red | #green | #blue | #other(string)

def f: list(Color) -> #some(string) | #emptyList = { items ->
    items \List.selectOne { item ->
        if #other(v) = item then yield(v)
    }
}

unfold

List.unfold: (b, (b -> #some(a, b) | #done)) -> list(a)

Generates a sequence from an initial state value and a function that produces either #done to end the sequence or #some(element, newState) to yield an element and a new state for the next step. Returns a list of all yielded elements.

def fibonacci = List.unfold((0, 1)) { current, next ->
    if current > 100 then #done
    else #some(current, (next, current + next))
}

zip

List.zip: (list(a), list(b)) -> list((a, b))

Combines two lists element-by-element into tuples. Length is the smaller input length.

List.zip([1, 2, 3], ["a", "b"])
-- [(1, "a"), (2, "b")]