On this page:
...
...
&
&
~&
~&
8.12

6.11 Repetitions🔗ℹ

A repetition represents a sequence of values, and it can be used in designated repetition positions (in much the same way that expressions appear in expression positions and bindings in binding positions). For example, a repetition can be used at the end of a list with ... after it.

One way to create a repetition is through a binding that uses .... Some expression-like forms are also repetition forms, creating new repetitions from one or more repetitions. For example, if x is bound as a repetition, then x+1 can be used as a repetition to add 1 to each element of x:

> def [x, ...] = [1, 2, 3]

> [x+1, ...]

[2, 3, 4]

When + is used as a repetition operator, then it expects a repetition for both arguments, but a literal value like 1 works as a repetition via #%literal.

A repetition has a depth, and each repetition context expects a repetition of a particular depth, typically based on how many ...s appear after the repetition context. In the above example, x is bound as a repetition of depth 1, and it is used in a context of depth 1, since there is one ... after x+1 to form the list. Using multiple ... in a bininding context typically binds at a greater depth, as in this example that binds and uses z at depth 2:

> def [[z, ...], ...] = [[1, 2, 3], [4, 5]]

> [[z+1, ...], ...]

[[2, 3, 4], [5, 6]]

More precisely, in this example, the outer list construction expects a repetition of depth 1 before its ..., and [z+1, ...] creates a repetition of depth 1. The [z+1, ...] repetition is depth 1, because a list repetition subtracts one from the depth of a repetition before (another) ..., and z+1 has depth 2 due to the z binding.

When a repetition is followed by multiple ...s in a row, as opposed to nested ...s, then the repetitions that would be accessed by nesting are flattend into a single repetition. This flattening has the effect of appending sequences.

> def [[z, ...], ...] = [[1, 2, 3], [4, 5]]

> [z, ..., ...]

[1, 2, 3, 4, 5]

When a repetition form combines multiple repetitions, then unless documented otherwise, elements at the same repetition depth are drawn from the repetitions in parallel.

> def [x, ...] = [1, 2, 3]

> def [y, ...] = ["a", "b", "c"]

> [[x, y], ...]

[[1, "a"], [2, "b"], [3, "c"]]

When combined repetitions are at different depths, the shallower repetition is repeated for outer layers of the deeper repetition. That’s why the x+1 and z+1 examples above work: a literal 1 works as repetition of depth 0, but it is repeated as needed to match the x repetition of depth 1 or the z repetition of depth 2. A repetition of depth 2 can be similarly repeated to match a repetition of depth 2:

> def [[z, ...], ...] = [[1, 2, 3], [4, 5, 6]]

> def [y, ...] = [10, 100, 1000]

> [[z+y, ...], ...]

[[11, 102, 1003], [14, 105, 1006]]

In other words, unless otherwise documented, the depth of a repetition formed by combining repetitions is the maximum of the depths of the combined repetitions, so z+y is a repetition of depth 2.

When an identifier is bound as a repetition, it is bound in the repet space, but also in the expr. The expr binding reports an error, but the intent of the binding is to shadow any existing expression binding for the identifier.

binding operator

...

 

expression

...

The ... “binding” form or ... “expression” form is not really allowed as an binding or expression, but it can appear in places where an binding or expression would otherwise be allowed.

In a binding-like position, ... tends to change a nearby binding into a repetition binding. For example, in fun (x, ...): body, the ... causes x to be bound to a repetition.

In an expression-like position, ... tends to change a nearby expression position into a repetition position, which is a place where a repetition binding or operator can be used. For example, the list expression [x, ...] has x in a repetition position, which would make sense as part of the body of fun (x, ...): body, since x is bound there as a repetition.

Function arguments, list patterns, and syntax patterns are among the places that recognize ... to create repetition bindings. Function calls, list constructs, and syntax templates are among the places that recognize ... to use repetition positions.

expression

& list_expr

 

binding operator

& list_bind

Provided both normally and as meta.

The & expression operator and binding operator can only be used in places where it’s specifically recognized, normally either to reference or bind the “rest” of a data structure. The List constructor, Map constructor, fun form, and the #%call form are among the places that recognize &.

> def [a, b, & others] = [1, 2, 3, 4]

> others

[3, 4]

> [0, & others]

[0, 3, 4]

expression

~& map_expr

 

binding operator

~& map_bind

Provided both normally and as meta.

The ~& expression operator and binding operator can only be used in places where it’s specifically recognized, normally to bind the “rest” of a map with keywords as keys. The fun and #%call forms are among the places that recognize ~&.

> fun roster(~manager: who, ~& players):

    players

> roster(~pitcher: "Dave", ~manager: "Phil", ~catcher: "Johnny")

{#'~catcher: "Johnny", #'~pitcher: "Dave"}