8.9 Ranges
A rangeSee Ranges in the Rhombus Guide for an introduction to ranges. represents a contiguous set of integers between two points. When the starting point is not #neginf, the range can be used as a stream or sequence; in addition, when the ending point is not #inf, the range is listable. Generally, the starting point must be less than or equal to the ending point, so that the lower bound is “less than or equal to” the upper bound by comparison on bounds.
A range supports membership tests using the in operator, which is the same as Range.contains.
annotation | |
| |
annotation | |
| |
annotation | |
The SequenceRange annotation matches a range that can be used as a stream or sequence. Such a range has a non-#neginf starting point.
The ListRange annotation matches a range that is listable. Such a range has a non-#neginf starting point and a non-#inf ending point.
Static information associated by SequenceRange or ListRange makes an expression acceptable as a sequence to for in static mode.
expression | |
| |
repetition | |
| |
binding operator | |
| |
expression | |
| |
repetition | |
| |
binding operator | |
| |
expression | |
| |
repetition | |
| |
binding operator | |
| |
expression | |
| |
repetition | |
| |
binding operator | |
| |
|
When start_expr .. end_expr or start_expr .. is used in an each clause of for, the optimization is more aggressive in that no intermediate range is created.
expression | |
| |
repetition | |
| |
binding operator | |
| |
expression | |
| |
repetition | |
| |
binding operator | |
| |
|
When start_expr ..= end_expr is used in an each clause of for, the optimization is more aggressive in that no intermediate range is created.
expression | |
| |
repetition | |
| |
binding operator | |
| |
expression | |
| |
repetition | |
| |
binding operator | |
| |
|
When start_expr <.. end_expr or start_expr <.. is used in an each clause of for, the optimization is more aggressive in that no intermediate range is created.
expression | |
| |
repetition | |
| |
binding operator | |
| |
|
When start_expr <..= end_expr is used in an each clause of for, the optimization is more aggressive in that no intermediate range is created.
function | |
| |
binding operator | |
function | |
| |
| |
binding operator | |
function | |
| |
| |
binding operator | |
function | |
| |
binding operator | |
function | |
| |
| |
binding operator | |
method | |
| |
method | |
method | |
| |
method | |
A range can count as empty even if real numbers exist between its bounds, as in 3 <.. 4, where the exclusive bounds 3 and 4 rule out all integers.
#false
#false
#true
#true
#true
start .. end, if rge.start() and rge.end() are both integers;
start .., if rge.start() is an integer and rge.end() is #inf;
.. end, if rge.start() is #neginf and rge.end() is an integer; or
Furthermore, if rge is already in canonical form, it is returned as-is.
> (1..5).canonicalize()
1 .. 5
> (1..).canonicalize()
1 ..
> (..5).canonicalize()
.. 5
> (..).canonicalize()
..
> (1..=5).canonicalize()
1 .. 6
> (..=5).canonicalize()
.. 6
> (1 <.. 5).canonicalize()
2 .. 5
> (1 <..).canonicalize()
2 ..
> (1 <..= 5).canonicalize()
2 .. 6
#true
#true
#false
#true
> Range.encloses()
#true
#true
#true
#false
#false
#true
> (2..=7).is_connected(3 <.. 8)
#true
> (2..=5).is_connected(5 <.. 8)
#true
> (2 <.. 5).is_connected(5 <.. 8)
#false
#true
#true
#false
2 ..= 5
2 .. 9
..= 6
.. 9
5 <.. 8
4 .. 6
8 .. 8
#false
method | ||
| ||
function | ||
|
> Range.intersect()
..
2 ..= 8
4 <..= 8
4 <.. 6
2 <..= 5
#false
[0, 1, 2, 3, 4]
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
method | ||
|
i
[0, 1, 2, 3, 4]
i
[0, 1, 2, 3, 4]
method | ||
When invoked as rge.step_by(step) in an each clause of for, the sequence is optimized, in cooperation with the optimization in .., ..=, <.., or <..=.
i
[0, 2, 4]
i
[1, 4, 7, 10]
property | |
| |
property | |
The SequenceRange.rest property produces a range that is inclusive for its start and end points the same as rge, except that a range constructed by ..= or Range.from_to_inclusive cannot be empty, so the result uses ...
10
11 ..
1 <..= 10
2 .. 2
annotation | |
| |
annotation | |
Since the resulting sequence is in descending order, generally, the starting point must be greater than (as opposed to less than) or equal to the ending point. Moreover, each DescendingRange form corresponds to one of the SequenceRange forms. In particular, the same kind of optimization in SequenceRange forms also applies to DescendingRange forms.
The DescendingListRange matches a DescendingRange object that is also listable. These are precisely the possible results of ListRange.descending.
A descending range can be used as a stream or sequence.
expression | ||
| ||
repetition | ||
| ||
expression | ||
| ||
repetition | ||
| ||
function | ||
| ||
function | ||
|
expression | ||
| ||
repetition | ||
| ||
expression | ||
| ||
repetition | ||
| ||
function | ||
| ||
| ||
function | ||
|
expression | |||
| |||
repetition | |||
| |||
function | |||
|
method | |
|
When invoked as rge.descending() in an each clause of for, the sequence is optimized, in cooperation with the optimization in .., ..=, <.., or <..=.
i
[4, 3, 2, 1, 0]
i
[4, 2, 0]
i
[10, 7, 4, 1]
> (0..5).descending().to_list()
[4, 3, 2, 1, 0]
[4, 3, 2, 1, 0]
> (0 <..= 5).descending().to_list()
[5, 4, 3, 2, 1]
[5, 4, 3, 2, 1]
[5, 4, 3, 2, 1]
[4, 3, 2, 1, 0]
method | ||
|
i
[5, 4, 3, 2, 1]
> for List (i in (5 >=.. 0).to_sequence()): // non-optimizing
i
[5, 4, 3, 2, 1]
method | ||
When invoked as rge.step_by(step) in an each clause of for, the sequence is optimized, in cooperation with the optimization in >=.., >=..=, >.., >..=, or ListRange.descending.
i
[5, 3, 1]
i
[9, 6, 3, 0]
property | |
| |
property | |
| |
method | |
The DescendingRange.rest property produces a descending range that is inclusive for its start and end points the same as rge, except that a range constructed by >=..= or DescendingRange.from_to_inclusive cannot be empty, so the result uses >..=.
9
9 >.. 0
#false
0 >..= 0
#true