Beanstalk uses a single loop keyword: loop.
to / to & select range semantics (exclusive vs inclusive)|...| syntaxreverse keyword; direction is inferred from the boundsby controls step size and works with both directionsLoops come in two forms:
A conditional loop repeats for as long as its condition stays true.
loop is_connected():
io("still connected")
;
Conditional loops usually do not need bindings.
Iteration loops evaluate the loop header as an iterable source and can optionally bind values for each iteration.
Iteration can step through either:
Bindings are written after the loop condition using `|...|`.
loop items |item|:
io(item.to_string())
;
A second binding can be added to receive the current zero-based index:
loop items |item, index|:
io([index]: [item])
;
The form is determined entirely by the loop header:
loop 0 to 10 |i|:
io(i.to_string())
;
-- yields: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
loop 0 to & 10 |i|:
io(i.to_string())
;
-- yields: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
loop to 5 |i|:
io(i.to_string())
;
-- equivalent to: loop 0 to 5 |i|:
Range loops can also bind a zero-based iteration index:
loop 10 to 15 |value, index|:
io([index]: [value])
;
-- yields: 0: 10
-- yields: 1: 11
-- yields: 2: 12
-- yields: 3: 13
-- yields: 4: 14
You can specify a step using `by`.
loop 0 to 10 by 2 |i|:
io(i.to_string())
;
-- yields: 0, 2, 4, 6, 8
Beanstalk automatically determines the iteration direction from the bounds:
With no `by`, the default step is `+1` for ascending ranges and `-1` for descending ranges.
loop 10 to 0 |i|:
io(i.to_string())
;
-- yields: 10, 9, 8, 7, 6, 5, 4, 3, 2, 1
You can also supply an explicit step:
loop 10 to & 0 by 2 |i|:
io(i.to_string())
;
-- yields: 10, 8, 6, 4, 2, 0
Float ranges are supported, but `by` should be considered required to prevent ambiguous or non-terminating loops.
loop 0.0 to 1.0 by 0.1 |t|:
io(t.to_string())
;