8.1 Lists
Lists can be constructed using the syntax [expr, ...], which creates list containing the values of the exprs as elements. More precisely, a use of square brackets without a preceding expression implicitly uses the #%brackets form, which is normally bound to construct a list.
A list is indexable using […] to access a list
element by position—
annotation | ||||||||
| ||||||||
annotation | ||||||||
| ||||||||
annotation | ||||||||
| ||||||||
| ||||||||
annotation | ||||||||
| ||||||||
| ||||||||
| ||||||||
| ||||||||
|
The List.tuple_of annotation matches a list whose elements each match the corresponding annot. If the last annot is not followed by ellipsis, then the annotation matches only lists that have the same number of elements as the number of annots. If the last annot is followed by ellipsis, then the annotation matches lists that have at least as many elements as annots except the last one, and all additional elements must match the last annot. For example, List.tuple_of[String, ...] is the same as List.of(String). If any annot is a converter annotation, then the List.tuple_of annotation is also a converter annotation where a converted list has converted elements. When all annots are predicate annotations, then List.tuple_of(annot, ...) is equivalent to matching(List[_ :: annot, ...]).
The #%brackets form is implicitly used when […] is used in a annotation position. See also Implicit Forms. A #%brackets annotation is equivalent to a List.tuple_of annotation, so [String, ...] is also the same as List.of(String).
Static information associated by List or List.of makes an expression acceptable as a sequence to for in static mode.
function | ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
| ||||||||||||
repetition | ||||||||||||
| ||||||||||||
| ||||||||||||
expression | ||||||||||||
| ||||||||||||
| ||||||||||||
repetition | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
|
The #%brackets form is implicitly used when […] is used in an expression position. See also Implicit Forms.
> lst
[1, 2, 3]
> lst[0]
1
> lst ++ [4, 5]
[1, 2, 3, 4, 5]
> #%brackets [1, 2, 3]
[1, 2, 3]
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
binding operator | ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
| ||||||||||||
|
> y
3
> also_y
3
> xs
[2, 3]
> [x, ...]
[2, 3]
> [x, ...]
[2]
> [x, ...]
[2]
def: value does not satisfy annotation
value: [1, 3]
annotation: matching(List(1, _, ... ~nonempty, 3))
def: value does not satisfy annotation
value: [1, 2, 2, 3]
annotation: matching(List(1, _, ... ~once, 3))
If multiple splices are present, matching is greedy: the first splice matches as many elements as possible to achieve a successful match, and so on for subsequent matches with the remaining elements.
> [[x, ...], [z, ...]]
[[1, 2, "c", 5], []]
> [[x, ...], [z, ...]]
[[1, 2, "c"], [5]]
> [[x, ...], [z, ...]]
[[1, 2, "c"], [5]]
> [[x, ...], y, [z, ...]]
[[1, 2], "c", ["d", 5]]
For a & list_repet_bind , ellipsis splice repetition, list_repet_bind is matched greedily to a non-empty sequence for each repetition of the splice.
> [[x, ...], ...]
[[1, 2, 3, 4]]
> def List(& [x :: Int, ..., y], ..., z, ...) = [1, 2, "c", 4, "e", 6]
> [[[x, ...], ...], [y, ...], [z, ...]]
[[[1, 2], [4], []], ["c", "e", 6], []]
When splice does not impose a predicate or conversion on a matching value (e.g., repet_bind or list_bind is an identifier), then the corresponding elements of a matching value are not traversed, which means that matching takes only the time needed by List.sublist (practically constant time) for a single such splice. Using this repetition in a new list similarly avoids traversing the elements.
A splice of the form & list_bind may have a statically known length. In particular, static information with the key statinfo_meta.list_bounds_key is associated with the overall pattern, so if list_bind is based on a list pattern, it may report its bounds via that key. The list matcher will not attempt to matches that are inconsistent with known bounds, and a multi-splice pattern using & list_bind splices is potentially deterministic and efficient if bounds can be determined statically. The same is true for list_repet_bind in a splice repetition, but the list matcher can only recompute expected bounds for a list size, not an expected modulus for a list size.
When multiple splices are present, the search for a match to each repet_bind , ellipsis splice first builds up a candidate sequence as long as possible by stopping when an element doesn’t satisfy repet_bind, and then the matcher backtracks to shorter sequences as needed to find an overall match. The search for a match to & list_bind tries first matching the longest plausible sequence to list_bind, then backtracks as needed by trying smaller sequences. Matching a splice repetition combines these strategies: search uses the longer plausible candidiate for a given repetition, and it builds up repetitions until no (non-empty) match is found for a repetition.
In the case of a & list_bind splice or & list_repet_bind , ellipsis splice repetition, static information associated by List is propagated to list_bind or list_repet_bind.
The #%brackets form is implicitly used when […] is used in a binding position. See also Implicit Forms.
annotation | |
| |
annotation | |
> [1] :: NonemptyList
[1]
> [] :: NonemptyList
::: value does not satisfy annotation
value: []
annotation: NonemptyList
reducer | |
method | ||
|
> List.insert(["a", "b", "c"], 1, "x")
["a", "x", "b", "c"]
> List.add([2, 3], 1)
[2, 3, 1]
[2, 3, 1]
> block:
[2, 3, 1]
> List.cons(1, [2, 3])
[1, 2, 3]
[1, 2, 3]
> x
1
> y
[2, 3]
value | |
| |
| |
binding operator | |
"b"
> ["a", "b", "c"][1]
"b"
property | ||
|
> List.first(["a", "b", "c"])
"a"
"a"
property | ||
|
> List.last(["a", "b", "c"])
"c"
"c"
property | ||
|
> List.rest(["a", "b", "c"])
["b", "c"]
["b", "c"]
> List.delete(["a", "b", "c"], 1)
["a", "c"]
method | ||
|
["a", "beta", "c"]
["a", "beta", "c"]
3
0
[8, 4, 1]
method | ||
| ||
| ||
function | ||
|
[1, 2, 3, 4, 5, 6]
> List.append([1, 2, 3], [4, 5], [6])
[1, 2, 3, 4, 5, 6]
> List.append()
[]
method | ||
| ||
| ||
method | ||
|
[1, 2]
[4, 5]
List.take: index is out of range
index: 2
valid range: [0, 1]
list: [1]
method | ||
| ||
| ||
method | ||
|
[3, 4, 5]
[1, 2, 3]
List.drop: index is out of range
index: 2
valid range: [0, 1]
list: [1]
method | |||
| |||
| |||
method | |||
|
When given one argument, rge is used to derive start and end as in String.substring.
[2, 3]
[2, 3]
[2, 3, 4]
[2, 3, 4, 5]
[1, 2, 3]
[1, 2, 3, 4, 5]
#true
#false
#true
> 2 in [1, 2, 3]
#true
1
#false
1
method | ||
| ||
| ||
method | ||
|
2
#false
> [1, 2, 3].find_index((_ mod 2 .= 0))
1
> [1, 2, 3].find_index((_ mod 10 .= 9))
#false
[1, 3, 2]
method | ||
| ||
| ||
method | ||
[2, 3, 4]
[2, 3, 4]
1
2
3
method | ||||||
| ||||||
| ||||||
method | ||||||
|
The List.partition function returns two lists that are like lst, but with complementary elements: the first result list has elements for which pred returns a true value, and the second result list has elements for which pred returns #false.
[1, 2]
[-1, -2]
[-1]
[1, 2]
[-1, -2]
method | ||
|
> List.sort([1, 3, 2])
[1, 2, 3]
[3, 2, 1]
> List.iota(3)
[0, 1, 2]
> List.iota(0)
[]
MutableList[1, 2, 3]
method | ||
|
repetition | |
> block:
[x+1, ...]
[2, 3, 4]
> [List.repet(lst) + 1, ...]
[2, 3, 4]