## 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-expression``range-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 `[>:]`.