Skip to main content

Collections

A collection groups several elements into one value. This page lists every operation on collections. This introduction gives the concepts you need before you read the entries: the kinds of collection, indexed and non-indexed collections, finite and infinite collections, lazy and eager collections, and element types.

Kinds of collection​

KindEpsil literalDescription
list[1, 2, 3]Elements in order, read by index. Duplicates are allowed.
set{1, 2, 3}Unique elements, not in order.
tuple(1, "a")A fixed number of elements, each with its own type.
dictionary{"a" -> 1, "b" -> 2}Key-value pairs. The keys are strings.
range1..10Numbers from a start to an end, with an optional step.
string"hello"The characters of the text, in order.

A set literal removes duplicates. The empty set is {}, and the empty dictionary is {->}:

{3, 1, 3, 2}
// ➔ Set(3, 1, 2)

Collections are immutable. An operation never changes a collection: it returns a new one.

let xs = [1, 2, 3]
let ys = append(xs, 4)
xs
// ➔ [1, 2, 3]

A string is a collection of its characters, so length, reverse, sort, filter and most other operations apply to it. An operation that selects or reorders the characters of a string (reverse, take, sort, unique, filter) returns a string. An operation that transforms the elements (map, flatMap, scan, zip) returns a list.

reverse("stressed")
// ➔ "desserts"
filter("banana", c => c != "a")
// ➔ "bnn"

Indexed and non-indexed collections​

An indexed collection has its elements in a fixed order, and you can read an element by its position. Lists, tuples, ranges and strings are indexed.

A non-indexed collection has no positions. You can enumerate its elements and test membership, but you cannot read an element by index. Sets and dictionaries are non-indexed. You read a dictionary value by its key.

The first element has index 1. A negative index counts from the end of a finite collection: -1 is the last element, -2 the element before it.

[2, 5, 7, 11][3]
// ➔ 7
[2, 5, 7, 11][-3]
// ➔ 5
{a -> 1, b -> 2}["b"]
// ➔ 2

An index that is out of range does not stop the program. It gives an absence marker: NaN when the elements are numbers, Missing otherwise. See at for the details.

Membership works on every collection:

3 in {1, 2, 3}
// ➔ True

Nested collections​

The elements of a collection are its top-level elements. A matrix (a list of lists) is a collection of rows. So count of a matrix is its number of rows, and first is its first row:

count([[2, 3, 4], [6, 7, 9]])
// ➔ 2
first([[2, 3, 4], [6, 7, 9]])
// ➔ [2, 3, 4]

To read one entry of a nested collection, give one index per level:

[[2, 3, 4], [6, 7, 9]][2, 3]
// ➔ 9

The Linear Algebra page has the operations on vectors, matrices and tensors.

Finite and infinite collections​

A collection can be finite (it has a definite number of elements) or infinite. 1..oo is the positive integers, and the number sets such as integers, realNumbers and primes are infinite sets.

count(1..oo)
// ➔ +oo

Lazy and eager collections​

An eager collection has all its elements computed when it is made. The list, set, tuple and dictionary literals are eager.

A lazy collection computes an element only when something reads it. A range, map, filter, take, a comprehension, cycle, iterate and repeat make lazy collections. Because of this, you can work with an infinite collection when you read only a finite part of it:

1..oo |> filter(isPrime) |> take(10) |> listFrom
// ➔ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

Only the first ten primes are computed here. The elements of a lazy collection are computed on the first read and kept, so a second read of the same collection does not compute them again. The kept elements are computed again when a value they depend on changes.

To materialize a lazy collection, that is to compute all its elements and make an eager collection, use listFrom or setFrom:

listFrom(1..10)
// ➔ [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

When a lazy collection is printed, only its first elements are computed. An ellipsis shows that more elements follow:

map(x => x^2, 1..oo)
// ➔ [1, 4, 9, 16, 25, …]

Use a range, not a number set, as an infinite indexed source​

integers and the other number sets are sets. They have no order and no indexes. The operations that need an indexed collection (at, take, drop, first, second, third, last, rest, most) reject them with an incompatible-type error. filter keeps the kind of its source, so filter(integers, x => x > 0) is a set too.

For an infinite source that you can index and take from, use 1..oo. To test membership in a number set, use in:

filter(1..30, x => x in primes)
// ➔ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]

The materialization cap​

The engine setting maxCollectionSize (default 10000) limits how many elements a lazy collection can have when the engine changes it into a list by itself, for example to print or evaluate a result. Such an automatic conversion keeps the lazy form when the list would be larger. You can still read the elements one at a time, and operations such as length still work. An explicit conversion with listFrom or setFrom does not check the setting: listFrom(1..20000) makes the whole list.

repeat(7, 3)
// ➔ [7, 7, 7]
repeat(7, 20000)
// ➔ Repeat(7, 20000)
length(repeat(7, 20000))
// ➔ 20000

The cap applies only to materialization. An operation applied to each element of a lazy collection (such as + over a range) is not limited by it.

Element types​

The type of a collection includes the type of its elements: list<integer>, set<string>, tuple<integer, string>, dictionary<number>. A dictionary with a fixed set of known keys has a record type, such as record{x: integer}. A list of numbers with a known length has a vector type, such as vector<integer^3>.

(type([1, 2, 3]), type({1, 2}), type((1, "a")), type({x -> 1}))
// ➔ (TypeFrom("vector<integer^3>"), TypeFrom("set<integer>"), TypeFrom("tuple<integer, string>"), TypeFrom("record{x: integer}"))

When the elements have different types, the element type is their union:

type(["a", 1])
// ➔ TypeFrom("list<integer | string>")

In a signature, collection means any collection, indexed or not, finite or infinite. indexed_collection means a collection that you can read by index, such as a list, a tuple, a range or a string.

Functions as arguments​

Many operations take a function: a predicate for filter, any or countIf, a key for sort or groupBy, a reducer for reduce. You can write it as an anonymous function, x => x > 5, or as an expression with the placeholder _, _ > 5:

countIf([5, 2, 10, 18], _ > 5)
// ➔ 2

The pipe |> passes a collection to the next operation, so a sequence of operations reads from left to right. The collection fills the argument slot the operation is missing: xs |> filter(isPrime) is filter(xs, isPrime), and xs |> map(f) is map(f, xs), because the function is map's first argument. A comprehension is another way to make a filtered and transformed list:

1..10 |> filter(isPrime) |> map(x => x^2)
// ➔ [4, 9, 25, 49]
[x^2 for x in 1..10 if x % 2 == 1]
// ➔ [1, 9, 25, 49, 81]

See Pipe for the complete rules of the pipe.

Each definition is listed under its Epsil spelling (the MathJSON name when it has none), with its signature in the engine's type syntax. The Standard Library page is the one-page index of every category.

Definitions​

adjoin​

MathJSON Adjoin · (set<any>, any+) -> set

The ring obtained by adjoining one or more elements to a base ring.

Adjoin(Integers, Sqrt(2)) is ℤ[√2]; Adjoin(Integers, ["Complex", 0, 1]) is the Gaussian integers ℤ[i]; Adjoin(Integers, "x") is the polynomial ring ℤ[x].

Inert: the adjunction is not expanded, and membership in it is not decided.

adjoin(integers, sqrt(2))
// ➔ Adjoin("Integers", sqrt(2))

all​

MathJSON All · (collection<T>, predicate: ((T) any -> boolean)?) -> boolean where T

Return True if the predicate holds for every element of the collection (or if every element is True when no predicate is given).

all([2, 4, 6], x => x % 2 == 0)
// ➔ "True"

any​

MathJSON Any · (collection<T>, predicate: ((T) any -> boolean)?) -> boolean where T

Return True if the predicate holds for at least one element of the collection (or if any element is True when no predicate is given).

To test membership of a specific value, use Contains(xs, v) — the structural-identity specialization Any(xs, (e) => e === v).

any([1, 3, 4], x => x % 2 == 0)
// ➔ "True"

append​

MathJSON Append · (collection<any>, (missing | value)+) -> collection

Add one or more elements to the end of a collection.

append([1, 2], 3, 4)
// ➔ [1,2,3,4]

argMax​

MathJSON ArgMax · (indexed_collection<T>, key: ((T) any -> unknown)?) -> integer where T

Return the 1-based index of the element that maximizes the given key function (or the element itself when no key is given).

argMax([3, 9, 2])
// ➔ 2

argMin​

MathJSON ArgMin · (indexed_collection<T>, key: ((T) any -> unknown)?) -> integer where T

Return the 1-based index of the element that minimizes the given key function (or the element itself when no key is given).

argMin([3, 9, 2])
// ➔ 3

At​

(value: any, index: (boolean | indexed_collection<any> | number | string)+) -> unknown

Access an element of an indexed collection.

If the index is negative, it is counted from the end.

Multiple indices can be provided to access nested collections (e.g., matrices).

If the index is a finite collection of booleans, returns the elements where the mask is True (a mask is a filter, and its length must match the collection length; otherwise it is an error).

If the index is a finite collection of integers, returns the elements at those indices, preserving position: an out-of-range index yields the absence marker, it is not dropped.

Out-of-band access (an out-of-range index, or a dictionary key that is not present) yields a POSITION-PRESERVING marker: NaN when the collection’s elements are numeric, Missing otherwise. It never yields Nothing, which would erase the position.

An index that is provably not an integer (2.5, 3/2, 5 + √17), as a scalar or as an entry of an index list, selects no element and yields the same marker. An index that cannot be decided (an unknown, an exact constant within rounding of an integer) leaves At unevaluated.

[10, 20, 30][2]
// ➔ 20
[10, 20, 30][-1]
// ➔ 30

chunk​

MathJSON Chunk · ((S, integer) -> list<string> where S: string) & ((collection, integer) -> list<list>)

Split the collection into k nearly equal-sized groups. See Partition for splitting into fixed-size chunks.

chunk([1, 2, 3, 4, 5, 6], 3)
// ➔ [[1,2],[3,4],[5,6]]

chunkBy​

MathJSON ChunkBy · ((S, key: (character) any -> unknown) -> list<string> where S: string) & ((collection<T>, key: (T) any -> unknown) -> list<list<T>> where T)

Split the collection into maximal runs of consecutive elements over which the key function yields the same value.

Returns a list of lists. Unlike GroupBy, only adjacent elements are grouped, so a key value that recurs after a different run starts a new chunk.

chunkBy([1, 3, 2, 4, 5], x => x % 2)
// ➔ [[1,3],[2,4],[5]]

closed​

MathJSON Closed · (number) -> number

Closed(x): the endpoint x of an Interval, marked as included. A marker with no value of its own; Interval normalizes it away.

1 in interval(0, closed(1))
// ➔ "True"

complement​

MathJSON Complement · (set<any>+) -> set

Return the elements of the first set that are not in any of the subsequent sets.

listFrom(complement({1, 2, 3, 4}, {2, 4}))
// ➔ [1,3]

complexNumbers​

MathJSON ComplexNumbers · constant set<complex>

The set of all finite complex numbers.

2 + 3i in complexNumbers
// ➔ "True"

contains​

MathJSON Contains · (collection<any>, element: any) -> boolean

Return True if the collection contains the given element (structural identity, like ===), False otherwise. An absent element is found where the same marker sits: Contains([1, NaN], NaN) is True.

Equivalent to Any(xs, (e) => e === v); use Any to test an arbitrary predicate instead of a specific value.

contains([1, 2, 3], 2)
// ➔ "True"

containsSequence​

MathJSON ContainsSequence · (indexed_collection<T>, indexed_collection<T>) -> boolean where T

Return True when needle occurs as a contiguous subsequence of the indexed collection.

Unlike Contains, which tests membership of a single element, the needle is read as a sequence: ContainsSequence("abc", "ab") is True while Contains("abc", "ab") is False.

containsSequence([1, 2, 3, 4], [2, 3])
// ➔ "True"

count​

MathJSON Count · (collection<any>, any?) -> infinity | integer

Count(xs): the number of elements in the collection.

Count(xs, v): how many elements are structurally the same as v.

Count(xs, p): how many elements satisfy the predicate p.

count([1, 2, 1, 3, 1], 1)
// ➔ 3

countIf​

MathJSON CountIf · (collection<T>, predicate: (T) any -> boolean) -> integer where T

Return the number of elements in the collection satisfying the predicate.

countIf([1, 4, 9, 16], x => x > 5)
// ➔ 2

cycle​

MathJSON Cycle · (list<any>) -> list

Produce an infinite sequence by cycling through the elements of a finite collection.

take(cycle([1, 2]), 5)
// ➔ [1,2,1,2,1]

dedup​

MathJSON Dedup · (collection<any>) -> collection

Return the collection with consecutive duplicate elements collapsed to a single element.

Only immediately-adjacent equal elements are removed; unlike Unique, a value that recurs after a different element is kept.

dedup([1, 1, 2, 2, 1])
// ➔ [1,2,1]

deleteAt​

MathJSON DeleteAt · ((T, integer) -> T where T: string) & ((indexed_collection<T>, integer) -> list<T> where T)

Return a copy of the indexed collection with the element at the 1-based index removed.

A negative index counts from the end. An out-of-range, zero, or non-integer index leaves the expression unevaluated.

Deleting from a string yields a string.

deleteAt([1, 2, 3, 4], 2)
// ➔ [1,3,4]

Dictionary​

(tuple<string, unknown>*) -> dictionary

A collection of key -> value entries with string keys ({x -> 1, y -> 2} in Epsil).

{"a" -> 1, "b" -> 2}["b"]
// ➔ 2

dictionaryFrom​

MathJSON DictionaryFrom · (collection<any>) -> dictionary

Create a dictionary from the elements of a collection of (key, value) pairs.

dictionaryFrom([("a", 1), ("b", 2)])
// ➔ {"a" -> 1, "b" -> 2}

differences​

MathJSON Differences · (collection<any>) -> indexed_collection

Return the successive differences of a collection: a collection whose k-th element is x(k+1) − xk, of length one less than the input.

differences([1, 4, 9, 16])
// ➔ [3,5,7]

drop​

MathJSON Drop · ((xs: T, count: number) -> T where T: string) & ((xs: indexed_collection<T>, count: number) -> list<T> where T)

Return the indexed collection without its first n elements.

A negative n counts from the end: Drop(xs, -n) is the collection without its last n elements.

A count past the length is clamped: the result is empty.

drop([1, 2, 3, 4, 5], 2)
// ➔ [3,4,5]
drop([1, 2, 3, 4, 5], -2)
// ➔ [1,2,3]

dropWhile​

MathJSON DropWhile · (collection<T>, predicate: (T) any -> boolean) -> collection where T

Return the collection with its leading elements for which the predicate returns True removed; the remaining elements are returned unfiltered.

dropWhile([1, 2, 3, 10, 4], x => x < 5)
// ➔ [10,4]

Element​

(any, any, boolean?) -> boolean

Test whether a value is an element of a collection. Optional third argument is a boolean expression (condition) for filtered iteration in Sum/Product.

Element supports two modes of operation:

  1. Set membership: Element(3, [List, 1, 2, 3]) checks if 3 is in the list
  2. Type-style membership: Element(x, integer) checks if x has type integer

Type-style membership works with:

  • Mathematical sets: Integers, RealNumbers, ComplexNumbers, etc.
  • Type names: integer, rational, real, number, positive_integer, etc.
  • Invalid type names remain unevaluated (e.g., Element(2, "Booleans"))
3 in {1, 2, 3}
// ➔ "True"

emptySet​

MathJSON EmptySet · constant set

The empty set, a set containing no elements.

isEmpty(emptySet)
// ➔ "True"

endsWith​

MathJSON EndsWith · (indexed_collection<T>, suffix: indexed_collection<T>) -> boolean where T

Return True when the indexed collection ends with suffix as a contiguous subsequence.

On a string the suffix is matched character by character, so a suffix that would begin inside a grapheme cluster does not match. An empty suffix matches everything.

endsWith([1, 2, 3], [2, 3])
// ➔ "True"

extendedComplexNumbers​

MathJSON ExtendedComplexNumbers · constant set<complex | infinity>

The set of all complex numbers, including infinities.

complexInfinity in extendedComplexNumbers
// ➔ "True"

extendedIntegers​

MathJSON ExtendedIntegers · constant set<integer | signed_infinity>

The set of all integers, including infinities.

Infinity in extendedIntegers
// ➔ "True"

extendedRationalNumbers​

MathJSON ExtendedRationalNumbers · constant set<rational | signed_infinity>

The set of all rational numbers, including infinities.

-Infinity in extendedRationalNumbers
// ➔ "True"

extendedRealNumbers​

MathJSON ExtendedRealNumbers · constant set<real | signed_infinity>

The set of all real numbers, including infinities.

-Infinity in extendedRealNumbers
// ➔ "True"

field​

MathJSON Field · (value: any, field: string) -> unknown

Access a named field of a value: p.x in Epsil.

On a record or dictionary value, Field(d, "x") behaves exactly as d["x"] (At semantics, including the absence marker for a key a dictionary may not have).

On a value of a NOMINAL type whose definition body has named fields (a record body, or a named-tuple body), the field is resolved through the type definition — the sanctioned accessor window of the nominal-types design (D6/§4.5b D16). This does not make the value a collection: First(p) and p["x"] keep rejecting.

A field name that is not in a record/named-tuple definition is a static defect (the result type is error); on an unknown-typed operand the expression stays symbolic.

{x -> 1, y -> 2}.y
// ➔ 2

fill​

MathJSON Fill · (function, tuple) -> list

Produce a 2D list (matrix) by applying a function to each pair of row and column indexes.

fill((i, j) => 10i + j, (2, 3))
// ➔ [[11,12,13],[21,22,23]]

filter​

MathJSON Filter · (collection<T>, predicate: (T) any -> boolean) -> collection where T

Return the elements of the collection for which the predicate function returns True.

Equivalent to [x for x in xs if p(x)].

filter([1, 2, 3, 4, 5, 6], x => x % 2 == 0)
// ➔ [2,4,6]

find​

MathJSON Find · (collection<T>, predicate: (T) any -> boolean) -> any where T

Return the first element of the collection satisfying the predicate, or Nothing if none found.

find([1, 4, 9, 16], x => x > 5)
// ➔ 9

first​

MathJSON First · (xs: indexed_collection<any>) -> any

The first element of a collection.

first([7, 8, 9])
// ➔ 7

flatMap​

MathJSON FlatMap · (collection<T>, mapping: (T) any -> U) -> list where T, U

Map a function over a collection and concatenate the results into a single list, splicing collection-valued results and keeping scalar results as single elements.

flatMap([1, 2, 3], x => [x, x])
// ➔ [1,1,2,2,3,3]

fold​

MathJSON Fold · (reducer: (unknown, T) any -> unknown, initial: value, collection<T>) -> value where T

Fold a collection to a single value, applying a binary function f(accumulator, element) left to right from an initial value.

fold((a, b) => a + b, 0, [1, 2, 3, 4])
// ➔ 10

groupBy​

MathJSON GroupBy · (collection<T>, key: (T) any -> unknown) -> dictionary<list> where T

Partition the collection into a dictionary of lists based on the key returned by the function.

groupBy(["apple", "fig", "pear", "kiwi"], length)
// ➔ {"3" -> ["fig"], "4" -> ["pear","kiwi"], "5" -> ["apple"]}

imaginaryNumbers​

MathJSON ImaginaryNumbers · constant set<imaginary>

The set of all imaginary numbers.

3i in imaginaryNumbers
// ➔ "True"

indexOf​

MathJSON IndexOf · (indexed_collection<any>, any) -> integer

Return the 1-based index of the first occurrence of value in collection, or 0 if not found. The comparison is structural, so an absent value is found where the same marker sits: IndexOf([1, NaN], NaN) is 2. Stays unevaluated when the collection cannot be searched (a symbol with no value, an unbounded source with no match).

indexOf([10, 20, 30], 20)
// ➔ 2

indexWhere​

MathJSON IndexWhere · (indexed_collection<T>, predicate: (T) any -> boolean) -> integer where T

Return the 1-based index of the first element satisfying the predicate, or 0 if not found. Stays unevaluated when the collection cannot be searched (a symbol with no value, an unbounded source with no match).

indexWhere([1, 4, 9, 16], x => x > 5)
// ➔ 3

insert​

MathJSON Insert · (indexed_collection<T>, integer, T) -> list<T> where T

Return a copy of the indexed collection with value inserted before the 1-based index.

index may range from 1 to n+1 (n+1 appends). A negative index counts from the end, with -1 appending at the end (Elixir semantics).

An out-of-range, zero, or non-integer index leaves the expression unevaluated.

insert([1, 2, 4], 3, 3)
// ➔ [1,2,3,4]

integers​

MathJSON Integers · constant set<integer>

The set of all finite integers.

-7 in integers
// ➔ "True"

intersection​

MathJSON Intersection · (any+) -> set

Return the intersection of one or more collections as a set.

intersection({1, 2, 3}, {2, 3, 4})
// ➔ Set(2, 3)

interval​

MathJSON Interval · (number, number) -> set<real>

A set of real numbers between two endpoints. The endpoints may or may not be included.

0.5 in interval(0, 1)
// ➔ "True"

isEmpty​

MathJSON IsEmpty · (collection<any>) -> boolean

Return True if the collection is empty, False otherwise.

isEmpty([])
// ➔ "True"

iterate​

MathJSON Iterate · (function, initial: any?) -> list

Produce an infinite sequence by repeatedly applying a function to the previous value, starting with an initial value.

The function is invoked as f(index, acc): index is the 1-based position of the element being produced, and acc is the previous element — the initial value when producing element 1. Element k is therefore f(k, element(k-1)).

A function whose type says it is UNARY is applied to the accumulator alone (Iterate(2 * _, 1) produces [2, 4, 8, 16, …]); a statically-unknown arity keeps the two-argument form.

take(iterate(x => 2x, 1), 5)
// ➔ [2,4,8,16,32]

join​

MathJSON Join · ((T+) -> T where T: string) & ((collection<any>*) -> collection)

Join the elements of some collections into a flat collection.

A tuple operand is appended as a single element, not spliced.

A scalar operand is appended as a single element too: Join([1, 2], 3) is [1, 2, 3].

When every operand is a string, the result is their concatenation as a string: Join is the variadic string concatenation.

join([1, 2], [3, 4])
// ➔ [1,2,3,4]
join("ab", "cd")
// ➔ "abcd"

KeyValuePair​

(key: string, value: T) -> tuple<string, T> where T

A key/value pair

Dictionary(KeyValuePair("a", 1), KeyValuePair("b", 2))
// ➔ {"a" -> 1, "b" -> 2}

keys​

MathJSON Keys · (dictionary<any>) -> list<string>

Return a list of the keys of a dictionary.

keys({"a" -> 1, "b" -> 2})
// ➔ ["a","b"]

last​

MathJSON Last · (xs: indexed_collection<any>) -> any

The last element of a collection.

last([7, 8, 9])
// ➔ 9

length​

MathJSON Length · (any) -> infinity | integer

Number of elements in a collection. Returns +oo for an infinite collection (an unbounded Range, Integers, Repeat(5), an interval), as Count does, an incompatible-type error for an operand that is decidably not a collection, NaN for an absent operand (Missing), and stays unevaluated for a collection whose size is not known (a Filter over an infinite source).

length([5, 6, 7])
// ➔ 3
length("hello")
// ➔ 5

linspace​

MathJSON Linspace · (start: number, end: number?, count: number?) -> list<number>

A sequence of evenly spaced numbers between a start and end value, both endpoints included.

linspace(0, 1, 5)
// ➔ [0,0.25,0.5,0.75,1]

List​

(any*) -> list

An ordered collection of elements (a list).

List(1, 2, 3)
// ➔ [1,2,3]

listFrom​

MathJSON ListFrom · (value*) -> list

Create a list from the elements of a collection.

listFrom({1, 2}, 3..4)
// ➔ [1,2,3,4]

ListJoin​

(collection<any>*) -> list

Join the elements of some collections into a list.

This is the canonical form of a list literal with a spread: [...a, 0] is ListJoin(a, [0]).

The result is a list whatever the kind of the operands: the elements of a set operand are included in the iteration order of the set, without deduplication.

A tuple operand is included as a single element, and so is a scalar operand.

ListJoin(Set(3, 1), [0])
// ➔ [3,1,0]

map​

MathJSON Map · (mapping: (T) any -> U, collection<T>+) -> indexed_collection where T, U

Return the collection where each element has been transformed by the mapping function.

With a single collection, equivalent to [f(x) for x in xs]. With

multiple collections, combines them element-wise (like zipWith):

Map(f, xs, ys) = [f(x1, y1), f(x2, y2), …], with the length of the

shortest input. The mapping function is always the FIRST argument.

map(x => x^2, [1, 2, 3])
// ➔ [1,4,9]

maxBy​

MathJSON MaxBy · (collection<T>, key: (T) any -> unknown) -> value where T

Return the element of the collection that maximizes the given key function.

maxBy(["pear", "fig", "apple"], length)
// ➔ "apple"

MemberCall​

(receiver: any, member: string, arguments: any*) -> unknown

Call the member name of a value with the value as its first argument: c.area(2) in Epsil.

A parse-level node. Canonicalization rewrites it to Apply(Field(c, "area"), 2) when the receiver's type declares a field area (a stored function is called), or to the bare protocol call area(c, 2) when area is a protocol function member; a canonical expression never contains it.

minBy​

MathJSON MinBy · (collection<T>, key: (T) any -> unknown) -> value where T

Return the element of the collection that minimizes the given key function.

minBy(["pear", "fig", "apple"], length)
// ➔ "fig"

most​

MathJSON Most · ((T) -> T where T: string) & ((indexed_collection<T>) -> list<T> where T)

Return the collection without the last element.

If the collection has only one element, return an empty collection.

most([7, 8, 9])
// ➔ [7,8]

negativeIntegers​

MathJSON NegativeIntegers · constant set<integer>

The set of all negative integers.

-3 in negativeIntegers
// ➔ "True"

negativeNumbers​

MathJSON NegativeNumbers · constant set<real>

The set of all negative real numbers.

-0.5 in negativeNumbers
// ➔ "True"

nonNegativeIntegers​

MathJSON NonNegativeIntegers · constant set<integer>

The set of all non-negative integers.

0 in nonNegativeIntegers
// ➔ "True"

nonNegativeNumbers​

MathJSON NonNegativeNumbers · constant set<real>

The set of all non-negative real numbers.

0 in nonNegativeNumbers
// ➔ "True"

nonPositiveIntegers​

MathJSON NonPositiveIntegers · constant set<integer>

The set of all non-positive integers.

0 in nonPositiveIntegers
// ➔ "True"

nonPositiveNumbers​

MathJSON NonPositiveNumbers · constant set<real>

The set of all non-positive real numbers.

0 in nonPositiveNumbers
// ➔ "True"

NotElement​

(any, any) -> boolean

Test whether a value is not an element of a collection.

4 !in {1, 2, 3}
// ➔ "True"

NotSubset​

(lhs: any, rhs: any) -> boolean

Test whether the first collection is not a strict subset of the second.

NotSubset({1, 4}, {1, 2, 3})
// ➔ "True"

NotSuperset​

(lhs: any, rhs: any) -> boolean

Test whether the first collection is not a strict superset of the second.

NotSuperset({1, 2}, {1, 2, 3})
// ➔ "True"

NotSupersetEqual​

(lhs: any, rhs: any) -> boolean

Test whether the first collection is not a superset (possibly equal) of the second.

NotSupersetEqual({1, 2}, {1, 2, 3})
// ➔ "True"

numbers​

MathJSON Numbers · constant set<number>

The set of all numbers.

2 + 3i in numbers
// ➔ "True"

open​

MathJSON Open · (number) -> number

Open(x): the endpoint x of an Interval, marked as excluded. A marker with no value of its own.

0 in interval(open(0), 1)
// ➔ "False"

ordering​

MathJSON Ordering · (indexed_collection<T>, order: (((T) any -> unknown) | ((any, any) any -> boolean | number))?) -> list<integer> where T

Return the indexes that would sort the collection.

ordering([30, 10, 20])
// ➔ [2,3,1]

Pair​

(first: T, second: U) -> tuple<T, U> where T, U

A tuple of two elements

Pair(1, 2)
// ➔ (1, 2)

partition​

MathJSON Partition · (collection<T>, ((T) any -> boolean) | integer, integer?) -> list<list<T>> where T

Partition a collection into consecutive chunks each of size n; the trailing chunk may be shorter when n does not divide the length.

With a third argument step, produce sliding windows of length n whose starts are step apart, keeping only complete windows.

With a predicate function instead of an integer, split into two groups: elements for which the predicate is true, and those for which it is false.

Asymmetry: with no step, the trailing partial chunk is included; with an explicit step, only complete windows are returned.

See Chunk for splitting into a given number of nearly-equal groups.

partition([1, 2, 3, 4, 5], 2)
// ➔ [[1,2],[3,4],[5]]
partition([1, 2, 3, 4, 5], x => x % 2 == 0)
// ➔ [[2,4],[1,3,5]]

pointList​

MathJSON PointList · (any+) -> any

A list of points: zips collection components into a List of point-tuples (Desmos point-list idiom); a plain point when no component is a collection.

pointList([1, 2, 3], [4, 5, 6])
// ➔ [(1, 4),(2, 5),(3, 6)]

pointX​

MathJSON PointX · (xs: collection<any> | tuple) -> any

The x-coordinate of a point, broadcasting over a list of points.

pointX((3, 4))
// ➔ 3
pointX([(1, 2), (3, 4)])
// ➔ [1,3]

pointY​

MathJSON PointY · (xs: collection<any> | tuple) -> any

The y-coordinate of a point, broadcasting over a list of points.

pointY((3, 4))
// ➔ 4

pointZ​

MathJSON PointZ · (xs: collection<any> | tuple) -> any

The z-coordinate of a point, broadcasting over a list of points.

pointZ((3, 4, 5))
// ➔ 5

position​

MathJSON Position · (collection<T>, predicate: (T) any -> boolean) -> list<integer> where T

Return a list of indexes of elements in the collection satisfying the predicate.

position([1, 4, 9, 16], x => x > 5)
// ➔ [3,4]

positiveIntegers​

MathJSON PositiveIntegers · constant set<integer>

The set of all positive integers.

0 in positiveIntegers
// ➔ "False"

positiveNumbers​

MathJSON PositiveNumbers · constant set<real>

The set of all positive real numbers.

0 in positiveNumbers
// ➔ "False"

primes​

MathJSON Primes · constant set<integer>

The set of all prime numbers.

filter(1..30, x => x in primes)
// ➔ [2,3,5,7,11,13,17,19,23,29]

quotientRing​

MathJSON QuotientRing · (set<any>, any) -> set

The quotient of a ring by the ideal generated by the second argument.

QuotientRing(Integers, n) is ℤ/nℤ, the integers modulo n.

For an integer literal n ≥ 1 it is a finite collection with n elements, and Count answers. A symbolic modulus, or a base other than Integers, stays inert.

The elements of ℤ/nℤ are ResidueClass(0, n) … ResidueClass(n - 1, n), which it lists, and the element type is value. Element(ResidueClass(k, n), ℤ/nℤ) is True. An integer is not an element: Element(7, ℤ/5ℤ) is False, because 7 is a representative of a class, not the class.

quotientRing(integers, 5)
// ➔ QuotientRing("Integers", 5)

randomShuffle​

MathJSON RandomShuffle · ((T) random -> T where T: string) & ((indexed_collection<T>) random -> list<T> where T)

Randomize the order of the elements in the collection. Shuffling a string yields a string. Wrap the call in WithRandomSeed(seed, ...) to make it deterministic.

randomShuffle([1, 2, 3, 4])

Range​

(number, number?, step: number?) -> list<number>

A sequence of numbers from a start to an end value with an optional step.

1..5
// ➔ [1,2,3,4,5]
Range(1, 10, 3)
// ➔ [1,4,7,10]

rangeOf​

MathJSON RangeOf · (indexed_collection<T>, indexed_collection<T>, from: integer?) -> nothing | range where T

Return the 1-based inclusive index span of the first occurrence of needle as a contiguous subsequence of the indexed collection, or Nothing when it does not occur.

The search starts at index from (1 by default) and the span is always expressed in the original collection's indices, so RangeOf(xs, needle, Last(r) + 1) finds the next non-overlapping occurrence and the loop ends at Nothing.

On a string the needle is matched character by character, so a match never begins or ends inside a grapheme cluster.

rangeOf([10, 20, 30, 40], [30, 40])
// ➔ [3,4]

rationalNumbers​

MathJSON RationalNumbers · constant set<rational>

The set of all finite rational numbers.

sqrt(2) in rationalNumbers
// ➔ "False"

realNumbers​

MathJSON RealNumbers · constant set<real>

The set of all finite real numbers.

i in realNumbers
// ➔ "False"

reduce​

MathJSON Reduce · (collection<T>, reducer: (unknown, T) any -> unknown, initial: value?) -> value where T

Reduce (fold) a collection to a single value by repeatedly applying a binary function, with an optional initial value.

reduce([1, 2, 3, 4], (a, b) => a * b)
// ➔ 24

repeat​

MathJSON Repeat · (value: any, count: integer?) -> list

Produce a sequence by repeating a single value. With 1 argument, returns an infinite sequence; with 2 arguments (value, count), returns a finite list of count copies.

repeat(0, 3)
// ➔ [0,0,0]

replaceAt​

MathJSON ReplaceAt · (indexed_collection<T>, integer, T) -> list<T> where T

Return a copy of the indexed collection with the element at the 1-based index replaced by value.

A negative index counts from the end. An out-of-range, zero, or non-integer index leaves the expression unevaluated.

replaceAt([1, 2, 3], 2, 20)
// ➔ [1,20,3]

residueClass​

MathJSON ResidueClass · (any, any) -> value

An element of ℤ/nℤ: the class of the integer k modulo n.

The canonical form reduces k into 0…n−1, so ResidueClass(7, 5) is ResidueClass(2, 5), and two classes are equal when their canonical forms are. n must be an exact integer literal ≥ 1, and k an exact integer (or a rational with a denominator that is a unit mod n); any other call stays inert, a float k or n included.

Sums, differences, products and integer powers of classes of one modulus are classes. An exact integer or rational next to a class is read in its ring: ResidueClass(5, 7) + 3 is ResidueClass(1, 7). A float is not. Arithmetic on classes of different moduli stays unevaluated. The inverse, a division and a negative power need a unit: when gcd(k, n) ≠ 1 they stay unevaluated.

Classes are not ordered, and Mod is not this: Mod(7, 5) is the integer remainder 2. The elements of QuotientRing(Integers, n) are the classes ResidueClass(0, n) … ResidueClass(n - 1, n).

LaTeX: \overline{k}_{n}, for integer literals k and n ≥ 1.

residueClass(7, 5)
// ➔ ResidueClass(2, 5)
residueClass(5, 7) + residueClass(4, 7)
// ➔ ResidueClass(2, 7)
1 / residueClass(3, 7)
// ➔ ResidueClass(5, 7)

rest​

MathJSON Rest · ((T) -> T where T: string) & ((indexed_collection<T>) -> list<T> where T)

Return the collection without the first element.

If the collection has only one element, return an empty collection.

rest([7, 8, 9])
// ➔ [8,9]

reverse​

MathJSON Reverse · ((T) -> T where T: string) & ((T) -> T where T: list) & ((indexed_collection<T>) -> list<T> where T)

Reverse the order of the elements of an indexed collection.

reverse([1, 2, 3])
// ➔ [3,2,1]

rotateLeft​

MathJSON RotateLeft · ((T, integer?) -> T where T: string) & ((T, integer?) -> T where T: list) & ((indexed_collection<T>, integer?) -> list<T> where T)

Rotate the elements of the collection to the left by n positions.

rotateLeft([1, 2, 3, 4])
// ➔ [2,3,4,1]

rotateRight​

MathJSON RotateRight · ((T, integer?) -> T where T: string) & ((T, integer?) -> T where T: list) & ((indexed_collection<T>, integer?) -> list<T> where T)

Rotate the elements of the collection to the right by n positions.

rotateRight([1, 2, 3, 4])
// ➔ [4,1,2,3]

scan​

MathJSON Scan · (collection<T>, reducer: (unknown, T) any -> unknown, initial: value?) -> indexed_collection where T

Return the cumulative fold of a collection: a same-length collection whose k-th element is the running result of applying a binary function left to right (optionally seeded by an initial value).

scan([1, 2, 3, 4], (a, b) => a + b)
// ➔ [1,3,6,10]

second​

MathJSON Second · (xs: indexed_collection<any>) -> any

The second element of a collection.

second([7, 8, 9])
// ➔ 8

Set​

(any*) -> set

An unordered collection of distinct elements (a set).

{3, 1, 2, 1}
// ➔ Set(3, 1, 2)

setFrom​

MathJSON SetFrom · (value*) -> set

Create a set from the elements of a collection.

setFrom([1, 2, 2, 3])
// ➔ Set(1, 2, 3)

setMinus​

MathJSON SetMinus · (set<any>, value*) -> set

Return the set difference between the first set and subsequent values.

setMinus({1, 2, 3, 4}, 2, 4)
// ➔ Set(1, 3)

Single​

(value: T) -> tuple<T> where T

A tuple with a single element

Single(5)
// ➔ (5)

slice​

MathJSON Slice · ((value: T, span: range) -> T where T: string) & ((value: T, span: nothing | range) -> T | nothing where T: string) & ((value: T, start: number, end: number) -> T where T: string) & ((value: indexed_collection<T>, span: range) -> list<T> where T) & ((value: indexed_collection<T>, span: nothing | range) -> list<T> | nothing where T) & ((value: indexed_collection<T>, start: number, end: number) -> list<T> where T)

Return a contiguous run of elements from an indexed collection.

Given start and end (1-based, inclusive), a negative index is counted from the end and out-of-bounds indices are clamped.

Given a range (an ascending index span such as 2..4), returns the elements at those indices: Slice(xs, r) is Slice(xs, First(r), Last(r)).

slice([10, 20, 30, 40, 50], 2, 4)
// ➔ [20,30,40]

sort​

MathJSON Sort · ((T, order: (((character) any -> unknown) | ((character, character) any -> boolean | number))?) -> T where T: string) & ((indexed_collection<T>, order: (((T) any -> unknown) | ((any, any) any -> boolean | number))?) -> list<T> where T)

Return the elements of the collection sorted according to the given comparison function.

sort([3, 1, 2])
// ➔ [1,2,3]
sort(["pear", "fig", "apple"], length)
// ➔ ["fig","pear","apple"]

startsWith​

MathJSON StartsWith · (indexed_collection<T>, prefix: indexed_collection<T>) -> boolean where T

Return True when the indexed collection begins with prefix as a contiguous subsequence.

On a string the prefix is matched character by character, so a prefix that would end inside a grapheme cluster does not match. An empty prefix matches everything.

startsWith([1, 2, 3], [1, 2])
// ➔ "True"

subset​

MathJSON Subset · (any, any*) -> boolean

Test whether the first collection is a strict subset of the second.

subset({1, 2}, {1, 2, 3})
// ➔ "True"

subsetEqual​

MathJSON SubsetEqual · (any, any*) -> boolean

Test whether the first collection is a subset (possibly equal) of the second.

subsetEqual({1, 2, 3}, {1, 2, 3})
// ➔ "True"

superset​

MathJSON Superset · (any, any*) -> boolean

Test whether the first collection is a strict superset of the second.

superset({1, 2, 3}, {1, 2})
// ➔ "True"

supersetEqual​

MathJSON SupersetEqual · (any, any*) -> boolean

Test whether the first collection is a superset (possibly equal) of the second.

supersetEqual({1, 2}, {1, 2})
// ➔ "True"

symmetricDifference​

MathJSON SymmetricDifference · (set<any>, set<any>) -> set

Return the symmetric difference of two sets (elements in either set but not both).

symmetricDifference({1, 2, 3}, {2, 3, 4})
// ➔ Set(1, 4)

table​

MathJSON Table · (function, integer, integer?) -> collection

An alias for Tabulate (the preferred name) that additionally accepts

Mathematica-style iterator specs, e.g. Table(i^2, {i, 1, n}) or

Table(i, {i, lo, hi, step}), and the equivalent tuple spelling

Table(i^2, (i, 1, n)).

table(i^2, (i, 1, 5))
// ➔ [1,4,9,16,25]

tabulate​

MathJSON Tabulate · (generator: function, integer, integer?) -> list

Create a collection by applying a function to each index in the specified dimensions.

tabulate((i, j) => i * j, 2, 3)
// ➔ [[1,2,3],[2,4,6]]

take​

MathJSON Take · ((xs: T, count: number) -> T where T: string) & ((xs: indexed_collection<T>, count: number) -> list<T> where T)

Return the first n elements of an indexed collection.

A negative n counts from the end: Take(xs, -n) is the last n elements.

A count past the length is clamped: the result is the whole collection.

take([1, 2, 3, 4, 5], 2)
// ➔ [1,2]
take([1, 2, 3, 4, 5], -2)
// ➔ [4,5]

takeWhile​

MathJSON TakeWhile · (collection<T>, predicate: (T) any -> boolean) -> collection where T

Return the leading elements of the collection for which the predicate returns True, stopping at the first element that does not.

takeWhile([1, 2, 3, 10, 4], x => x < 5)
// ➔ [1,2,3]

tally​

MathJSON Tally · (collection<T>) -> tuple<list<T>, list<integer>> where T

Return a tuple with the unique elements of the collection and their respective counts.

tally(["a", "b", "a", "c", "a"])
// ➔ (["a","b","c"], [3,1,1])

third​

MathJSON Third · (xs: indexed_collection<any>) -> any

The third element of a collection.

third([7, 8, 9])
// ➔ 9

Triple​

(first: T, second: U, third: V) -> tuple<T, U, V> where T, U, V

A tuple of three elements

Triple(1, 2, 3)
// ➔ (1, 2, 3)

Tuple​

(any*) -> tuple

A fixed number of heterogeneous elements

(1, "a", True)
// ➔ (1, "a", "True")

tupleFrom​

MathJSON TupleFrom · (value*) -> tuple

Create a tuple from the elements of a collection.

tupleFrom([1, 2, 3])
// ➔ (1, 2, 3)

union​

MathJSON Union · (any+) -> set

Return the union of two or more collections as a set.

union({1, 2}, {2, 3})
// ➔ Set(1, 2, 3)

unique​

MathJSON Unique · ((T) -> T where T: string) & ((collection<T>) -> list<T> where T)

Return a list of the unique elements of the collection.

unique([1, 2, 1, 3, 2])
// ➔ [1,2,3]

values​

MathJSON Values · (dictionary<any>) -> list

Return a list of the values of a dictionary.

values({"a" -> 1, "b" -> 2})
// ➔ [1,2]

zip​

MathJSON Zip · (indexed_collection<any>+) -> list

Combine multiple collections element-wise into a list of tuples. The result has the length of the shortest input.

zip([1, 2, 3], ["a", "b", "c"])
// ➔ [(1, "a"),(2, "b"),(3, "c")]