Ranges

A range is an immutable sequence of values that increase “linearly” - i.e. by a fixed amount. Most commonly it’s a sequence of consequtive integers. An example of the syntax is [3 <: 7] which evaluates to the sequence [3 4 5 6]. You can specify an explicit increment with a by: option. There are multiple ways to specify when the sequence stops. For example [3 by 2 <=: 7] is the even numbers from 3 up to 7 (inclusive, because of the <=).

Ranges are very useful for loop indexes, or selecting a sub-sequence. If you have a sequence q and a range r, and you use the syntax (q r) to “apply”q with the argument r, is result is to select elements of q with indexes in r.

("ABCDEFG" [1 by: 2 <: 7])  ⇒ "BDF"

A range can be unbounded, or non-finite, if you leave off the end value. For example [3 by: 2] is the odd integers starting at 3.

unbounded-range ::=
  [ start-expression by: step-expression ]
  | [ start-expression <: ]

The expression [start by: step] evaluates to an infinite sequence of values, starting with start, and followed by (+ start step), (+ start (* 2 step)), and so on.

The syntax [start-expression <:] is shorthand for [start-expression by: 1].

bounded-range ::= [ start-expression [by: step-expressionrange-end ]
range-end ::= <: end-expression
  | <=: end-expression
  | >: end-expression
  | >=: end-expression
  | size: size-expression

A bounded range takes an initial subsequence of the unbounded range specified by the start-expression and optional step-expression. The different end-expression variants provide different ways to specify the initial subsequence.

If size: size is specified, then the resulting range is the first size elements of unbounded sequence.

In the <: end or <=: end cases then the sequence counts up: The step must be positive, and defaults to 1. The resulting values are those x such that (< x end), or (<= x end), respectively.

In the >: end or >=: end cases then the sequence counts down: The step must be negative, and defaults to -1. The resulting values are those x such that (> x end), or (>= x end), respectively.

The start-expression, step-expression, and size-expression must evaluate to real numbers, not necessarily integers. For example: [1 by: 0.5 <=: 3.0] is [1.0 1.5 2.0 2.5 3.0].

The two pseudo-ranges [<:] and [>:] are useful as array indexes. They mean “all of the valid indexes” of the array being indexed. For increasing index values use [<:]; for decreasing index values (i.e. reversing) use [>:].