Range
Range module: integer ranges as first-class values.
A range is a record {start: Int, stop: Int, step: Int}. Ranges are half-open: [start, stop) when step > 0, (stop, start] when step < 0. step must be non-zero; new/2 defaults to step = 1. Every function that walks a range (to_list, each, and the ones built on to_list) takes it refined as {v : IntRange | v.step != 0} and panics on a zero step, which would otherwise never advance.
Types
The record every function here takes. Records are structural, so a plain {start: ..., stop: ..., step: ...} literal is one; the name exists so a refinement can read its step.
Functions
Returns true if every element satisfies f (true for an empty range).
Examples
march> Range.all(Range.new(1, 5), fn x -> x > 0)
true
march> Range.all(Range.new(0, 0), fn x -> x > 100)
trueReturns true if at least one element satisfies f (false for an empty range).
Examples
march> Range.any(Range.new(1, 5), fn x -> x == 4)
true
march> Range.any(Range.new(1, 5), fn x -> x == 5)
falseReturns true if n is one of the range's elements: within the bounds and on a step boundary. O(1).
Examples
march> Range.contains(Range.new_step(0, 10, 3), 6)
true
march> Range.contains(Range.new_step(0, 10, 3), 7)
false
march> Range.contains(Range.new(0, 5), 5)
false
march> Range.contains(Range.new_step(5, 0, -1), 1)
trueCalls f on each element in iteration order, for side effects. Returns (). Panics if the step is zero (also a refinement precondition).
Examples
Range.each(Range.new(0, 3), fn i -> println(int_to_string(i)))
-- prints 0, 1 and 2 on separate linesReturns the list of elements satisfying predicate f, in iteration order. Every element of the result is known to satisfy f (an abstract refinement p, as for List.filter).
Examples
march> Range.filter(Range.new(0, 10), fn x -> x % 4 == 0)
[0, 4, 8]Returns Some of the first element (start), or None if the range is empty.
Examples
march> Range.first(Range.new(3, 6))
Some(3)
march> Range.first(Range.new(6, 3))
NoneReturns true if the range contains no elements. O(1).
Examples
march> Range.is_empty(Range.new(2, 2))
true
march> Range.is_empty(Range.new_step(2, 0, -1))
falseReturns Some of the last element, or None if the range is empty. O(1); the last element is the final step boundary, not necessarily stop - 1.
Examples
march> Range.last(Range.new(3, 6))
Some(5)
march> Range.last(Range.new_step(0, 10, 3))
Some(9)
march> Range.last(Range.new(6, 3))
NoneApplies f to each element in iteration order, returning a list of results.
Examples
march> Range.map(Range.new(1, 4), fn x -> x * x)
[1, 4, 9]
march> Range.map(Range.new(1, 1), fn x -> x * x)
[]Creates the half-open range [start, stop) with step 1. The range is empty when stop <= start.
Examples
march> Range.to_list(Range.new(0, 4))
[0, 1, 2, 3]
march> Range.to_list(Range.new(3, 3))
[]Creates a range with an explicit step. With step > 0 it covers [start, stop) counting up; with step < 0 it covers (stop, start] counting down. Panics if step is zero (also a refinement precondition).
Examples
march> Range.to_list(Range.new_step(0, 10, 3))
[0, 3, 6, 9]
march> Range.to_list(Range.new_step(5, 0, -2))
[5, 3, 1]
march> Range.to_list(Range.new_step(0, 5, -1))
[]Left fold over the range in iteration order; f is called as f(acc, element).
Examples
march> Range.reduce(Range.new(1, 5), 1, fn (acc, x) -> acc * x)
24
march> Range.reduce(Range.new_step(3, 0, -1), [], fn (acc, x) -> Cons(x, acc))
[1, 2, 3]Returns a range with the same elements iterated in the opposite direction (start becomes the last element, step is negated). An empty range is returned unchanged. O(n): the elements are materialised to find the last one.
Examples
march> Range.to_list(Range.reverse(Range.new(0, 4)))
[3, 2, 1, 0]
march> Range.to_list(Range.reverse(Range.new_step(0, 10, 3)))
[9, 6, 3, 0]
march> Range.to_list(Range.reverse(Range.new(2, 2)))
[]Returns the number of elements in the range, computed arithmetically in O(1).
Examples
march> Range.size(Range.new(0, 10))
10
march> Range.size(Range.new_step(0, 10, 3))
4
march> Range.size(Range.new(5, 2))
0Returns the sum of all elements in the range (0 for an empty range).
Examples
march> Range.sum(Range.new(1, 101))
5050
march> Range.sum(Range.new_step(10, 0, -5))
15
march> Range.sum(Range.new(5, 5))
0Converts the range to a list of integers, in iteration order. O(n). Panics if the step is zero (also a refinement precondition).
Examples
march> Range.to_list(Range.new(1, 4))
[1, 2, 3]
march> Range.to_list(Range.new_step(3, 0, -1))
[3, 2, 1]