Iterators
functional helpers for easier block iteration (loops, filtering, mapping, etc)
Functions
Predicates
The Iterators module provides functional programming tools for working with collections. From simple loops to complex transformations, it offers a consistent way to process collections with elegant, expressive code.
Key Concepts
- Collection iteration with various strategies
- Functional transformations (map, filter, fold)
- Collection analysis (every?, some?, enumerate)
- Consistent behavior across all collection types
- Support for block-based predicate conditions
Basic Usage
Looping Through Collections
numbers: [1 2 3 4 5]
; basic iteration
loop numbers 'n ->
print ["Number:" n]
; Number: 1
; Number: 2
; Number: 3
; Number: 4
; Number: 5
; with index
loop.with:'i numbers 'n ->
print ["Item" i ":" n]
; Item 0 : 1
; Item 1 : 2
; Item 2 : 3
; Item 3 : 4
; Item 4 : 5
; dictionary iteration
user: #[name: "John" age: 30]
loop user [key value]->
print [key "->" value]
; name -> John
; age -> 30
Note
Iterator functions work uniformly with all collection types:
- Blocks:
loop [1 2 3] 'x [...]- Dictionaries:
loop #[a:1 b:2] [k v] [...]- Strings:
loop "hello" 'c [...]- Ranges:
loop 1..5 'x [...]- Numbers:
loop 3 'i [...](equivalent to1..3)
Transforming Collections
numbers: 1..5
; transform each element
doubled: map numbers 'x -> x * 2
print doubled ; 2 4 6 8 10
; using the => shorthand for simple transformations
squared: map numbers => [& ^ 2]
print squared ; 1 4 9 16 25
; chaining transformations
result: map numbers 'x ->
(to :string x) ++ "!"
; ["1!" "2!" "3!" "4!" "5!"]
Filtering Elements
numbers: 1..10
; keep elements matching condition
evens: select numbers 'n -> even? n
print evens ; 2 4 6 8 10
; remove elements matching condition
noEvens: filter numbers 'n -> even? n
print noEvens ; 1 3 5 7 9
; shorthand for simple predicates
odds: select numbers => odd?
print odds ; 1 3 5 7 9
Common Patterns
Testing Collections
numbers: [2 4 6 8]
; check if all elements match
every? numbers => even? ; => true
; check if any element matches
some? numbers => [& > 10] ; => false
; count matching elements
enumerate numbers 'x -> x > 5 ; => 3
Collecting and Grouping
data: ["apple" "banana" "apricot" "cherry"]
; group by first letter
byLetter: gather data 'word -> first word
print byLetter
; [a:[apple apricot] b:[banana] c:[cherry]]
; collect elements while condition is true
ascending: collect [1 2 3 2 4 5] 'x ->
x < 4
print ascending ; 1 2 3 2
Advanced Transformations
; fold (reduce) a collection
sum: fold 1..5 [acc val]->
acc + val
; 15
; with seed value
sumFrom100: fold.seed:100 1..5 [acc val]->
acc + val
; 115
; arrange (sort) with custom predicate
users: @[
#[name: "John" score: 42]
#[name: "Alice" score: 28]
#[name: "Bob" score: 35]
]
sorted: arrange users 'user -> user\score
print.lines map sorted 'u -> u\name
; Alice
; Bob
; John
Tip
The arrow operator (=>) is particularly useful with iterators for creating concise, readable code. For example:map nums => [& * 2]instead ofmap nums 'x -> x * 2
Working with Nested Data
; cluster similar items
temps: [22 22 23 25 25 25 24 24]
clusters: cluster temps 'temp -> temp
; [[22 22] [23] [25 25 25] [24 24]]
; chunk using predicate
data: 1..6
chunks: chunk data => [& < 3]
[1 2] [3 4 5 6]
; finding matches with collect
numbers: [1 2 3 2 1 4 5 4]
duplicates: collect.after numbers 'x ->
not? contains? first.n:3 numbers x
; 4 5 4
Pipe-based Transformations
; Sample data: list of orders
orders: @[
#[id: 1 items: ["book" "pen"] total: 25.50 status: "pending"]
#[id: 2 items: ["laptop"] total: 999.99 status: "completed"]
#[id: 3 items: ["phone" "case" "charger"] total: 699.00 status: "pending"]
#[id: 4 items: ["tablet"] total: 299.99 status: "cancelled"]
]
; Process orders using pipes for better readability
result: orders
| select 'order -> order\status = "pending" ; get pending orders
| map 'order -> #[ ; transform structure
orderId: order\id
itemCount: size order\items
cost: order\total
]
| arrange 'order -> order\cost ; sort by cost
| map 'order -> ~{
Order #|order\orderId|: |order\itemCount|
items @ $|order\cost|
}
print.lines result
; Order #1: 2
; items @ $25.5
; Order #3: 3
; items @ $699.0
Tip
Using pipes (|) can make complex data transformations more readable by breaking them into clear, sequential steps.
Parallel Iteration
Many iterators accept the .parallel attribute, fanning each element out into its own cooperative task - ideal for I/O-bound bodies (network, files):
; bare flag - unbounded fan-out, results in input order
results: map.parallel urls 'u [wait read.async u]
; integer cap - sliding-window concurrency (at most 8 at a time)
results: map.parallel: 8 urls 'u [wait read.async u]
; concurrent side effects (completion order undefined)
loop.parallel 1..10 'i [pause random 100 print i]
; predicates short-circuit and cancel the losers
every?.parallel 1..100 'x -> x < 1000 ; first false cancels the rest
some?.parallel 1..100 'x -> x = 99 ; first true cancels the rest
The following iterators opt in: map, loop, select, filter, enumerate, gather, arrange, maximum, minimum, every?, some?.
Note
Order-dependent iterators -fold,collect,cluster,chunk- are sync-only; they don't accept.parallel.
Warning
Each parallel body runs with a shallow copy of the surrounding scope, so writes don't leak back:u: 1 map.parallel 1..10 'a [u: u + 1] print u ; 1 (UNCHANGED)Also note parallelism here is cooperative - CPU-bound bodies won't actually overlap. It pays off for I/O. See the Tasks module for the concurrency model.