LOOPS

Loops Syntax

Beanstalk uses a single loop keyword: loop.

Loops come in two forms:

  1. Conditional loops (repeat while a condition is true)
  2. Iteration loops (iterate over a collection or a numeric range)

Conditional loops

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

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:

Range loops


    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
    

Direction is inferred from bounds

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())
    ;