"Abstraction of [[ordinal types|Ordinal]] whose values may
be used as endpoints of a [[span]] or [[measure]].
An `Enumerable` type is characterized by each element
having well-defined [[offset]] and [[neighbour]] functions.
Given an instance `x` of an enumerable type `X`:
- for any integer-valued offset, there is a unique
_neighbour_ `y` of `X` with that offset, and
- if `y` is an instance of `X`, then there is a
well-defined integer-valued _offset_ of `x` from `y`.
The offset function must satisfy:
- `x.offset(x) == 0`, and
- `x.successor.offset(x) == 1` if `x!=x.successor`.
The neighbour function must satisfy:
- `x.neighbour(0) == x`,
- `x.neighbour(n-1) == x.neighbour(n).predecessor`, and
- `x.neighbour(n+1) == x.neighbour(n).successor`.
Of course, it follows that:
- `x.neighbour(-1) == x.predecessor`, and
- `x.neighbour(1) == x.successor`.
An enumerable type may be _linear_ or _recursive_. If `X`
is a linear enumerable type, then the offset function
satisfies:
- `x.predecessor.offset(x) == -1` if `x!=x.predecessor`,
- `x.offset(y) == -y.offset(x)` for any instance `y` of `X`,
and
- `x.offset(y) == x.offset(z) + z.offset(y)`.
Otherwise, `X` is a recursive enumerable type with a finite
list of enumerated instances of size `count`, and its
offset and neighbour functions must satisfy:
- `x.neighbour(count)==x`,
- `x.offset(y) >= 0` for any instance `y` of `X`, and
- `x.predecessor.offset(x) == count - 1`.
A range of values of an enumerable type may be specified
using:
- the _span operator_, written `first..last`, or
- the _segment operator_, written `first:length`."
see (`class Range`,
`function span`, `function measure`)
shared interface Enumerable<Other> of Other
satisfies Ordinal<Other>
given Other satisfies Enumerable<Other> {
"The indirect successor or predecessor at the given
[[offset]], where:
- `x.neighbour(0) == x`,
- `x.neighbour(i+1) == x.neighbour(i).successor`, and
- `x.neighbour(i-1) == x.neighbour(i).predecessor`."
throws (`class OverflowException`,
"if the neighbour cannot be represented as an
instance of the type")
since("1.1.0")
shared formal Other neighbour(Integer offset);
shared actual default Other successor => neighbour(1);
shared actual default Other predecessor => neighbour(-1);
"Compute the offset from the given value, where:
- `x.offset(x) == 0`, and
- `x.successor.offset(x) == 1` if `x!=x.successor`."
throws (`class OverflowException`,
"if the offset cannot be represented as an
integer")
since("1.1.0")
shared formal Integer offset(Other other);
"The sign of the offset from the given value."
since("1.1.0")
shared default Integer offsetSign(Other other)
=> offset(other).sign;
}