Loops
Flow supports for and while loops with break and continue for flow control. Loops are statements — they execute side effects and don’t return values.
For Loops
Iterate over the elements of an array with for T name in collection { ... }:
use "@std"
Int[] nums = (list 1 2 3 4 5)
for Int n in nums {
(print (str n))
}Open in playgroundThe loop variable is declared with its type (no : required here) and is scoped to the loop body. break and continue only work inside for or while — using them outside raises a parse error.
Iterating a Range
Combine with range to loop a fixed number of times. range is half-open: (range 0 10) produces [0, 1, ..., 9]. The 3-arg overload (range start end step) lets you control the stride:
use "@std"
for Int i in (range 0 10) {
(print (str i))
}
for Int i in (range 0 20 2) { Note: 0, 2, 4, ..., 18
(print (str i))
}Open in playgroundNested For Loops
use "@std"
for Int i in [1, 2, 3] {
for Int j in [10, 20] {
(print (str (mul i j)))
}
}Open in playgroundEmpty Arrays
Looping over an empty array runs the body zero times:
use "@std"
Int[] nothing = []
for Int x in nothing {
(print "never runs")
}Open in playgroundLooping Over Notes
The loop variable can be any type:
use "@std"
Note[] melody = (list C4 D4 E4 F4)
for Note n in melody {
(print (str n))
}Open in playgroundLooping Over Dict Entries
(each dict cb) is usually clearer than building keys/values arrays, but a for loop over (keys d) works too:
use "@std"
Dict<Symbol, Int> bpms = (dict #verse 120 #chorus 140)
for Symbol k in (keys bpms) {
(print $"{k} = {(get bpms k)}")
}Open in playgroundWhile Loops
Execute a block repeatedly while a condition is true. Use the prefix arithmetic builtins for counter math:
use "@std"
Int count = 0
while (lt count 5) {
count = (add count 1)
}
(print (str count)) Note: 5Open in playgroundInfinite Loop + break
A common pattern is while true combined with break:
use "@std"
Int i = 0
while true {
i = (add i 1)
(if (equals i 5) lazy (break) lazy ((Nothing)))
}Open in playgroundNote that if requires both branches to be lazy () — for a side-effect-only branch that does nothing, lazy ((Nothing)) is the canonical no-op.
Countdown
use "@std"
Int counter = 10
while (gt counter 0) {
counter = (sub counter 1)
}Open in playgroundbreak
break exits the innermost enclosing loop immediately:
use "@std"
for Int i in (range 0 100) {
(if (gt i 5) lazy (break) lazy ((Nothing)))
(print (str i))
}
Note: prints 0 through 5 then exitsOpen in playgroundcontinue
continue skips the rest of the current iteration and proceeds to the next:
use "@std"
Int ci = 0
while (lt ci 3) {
ci = (add ci 1)
continue
Note: anything after continue is skipped
(print "never runs")
}Open in playgroundIteration Safety Limit
Loops have a configurable maximum iteration count (default 10000) to prevent runaway execution. Adjust with:
use "@std"
(setMaxIterations 1000000)Open in playgroundWhen the limit is exceeded, the interpreter reports Iteration limit of N exceeded in for loop (or while loop) and halts that loop. Long-running batch loops may need to raise the cap.
Loops and Music
Loops combine naturally with note-building patterns. For example, to build sequences programmatically:
use "@std"
Int[] intervals = (list 0 2 4 5 7 9 11 12)
for Int semitones in intervals {
Sequence step = | C4 | -> transpose semitones
(print (str step))
}Open in playgroundFor rhythmic variations, use seeded randomness inside loops:
use "@std"
(??set 42)
for Int i in (range 0 4) {
Sequence bar = | (?? C4 E4 G4) (?? C4 E4 G4) |
(print (str bar))
}Open in playgroundComparison: Recursion vs Loops vs Combinators
Flow supports recursion too, but loops are usually clearer for imperative counting, and collection combinators (map / filter / reduce) are often more idiomatic for transformations:
use "@std"
Note: imperative loop
Int sum = 0
for Int n in (range 1 11) {
sum = (add sum n)
}
(print (str sum)) Note: 55
Note: functional reduce
Int sumF = (reduce (range 1 11) 0 (fn Int acc, Int n => (add acc n)))
(print (str sumF)) Note: 55Open in playgroundPick whichever reads more naturally. Loops shine for stateful iteration or early exit; combinators win for pure transformations.
See Also
- Language Basics - Variables, prefix arithmetic, pattern matching, scoping
- Collections -
map,filter,reducealternatives, andDict<K, V> - Generative Music - Using loops alongside Markov / L-systems / Tidal combinators