Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 78 additions & 1 deletion src/foreach.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ stylistic.

We can use the `foreach` syntax to iterate through any collection type that
implements the `ForEach` trait. In particular, the `ForEach` trait
defines a single signature:
defines a single signature:

```flix
///
Expand All @@ -103,3 +103,80 @@ trait ForEach[t] {
```

> **Note:** Flix expects the expression body of a `foreach` to have type `Unit`.

## ForEach Combinators

The `ForEach` module provides four combinators that transform how a collection is
iterated: `withIndex`, `withFilter`, `withMap`, and `withZip`. Each combinator
wraps a collection and returns a new `ForEach`-compatible value that can be used
directly with the `foreach` syntax.

### Iterating with an Index

The `withIndex` combinator pairs each element with its zero-based index:

```flix
use ForEach.withIndex;
def main(): Unit \ IO =
let langs = List#{"Flix", "Haskell", "Scala"};
foreach ((i, lang) <- withIndex(langs)) {
println("${i}: ${lang}")
}
```

This prints:

```
0: Flix
1: Haskell
2: Scala
```

### Filtering Elements

The `withFilter` combinator skips elements that do not satisfy a predicate:

```flix
use ForEach.withFilter;
def main(): Unit \ IO =
let numbers = List#{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
foreach (x <- withFilter(x -> x `Int32.modulo` 2 == 0, numbers)) {
println("${x}")
}
```

This prints only the even numbers: `2`, `4`, `6`, `8`, `10`.

### Mapping Elements

The `withMap` combinator applies a transformation to each element before it is
yielded:

```flix
use ForEach.withMap;
def main(): Unit \ IO =
let numbers = List#{1, 2, 3, 4, 5};
foreach (x <- withMap(x -> x * 10, numbers)) {
println("${x}")
}
```

This prints `10`, `20`, `30`, `40`, `50`.

### Zipping Two Collections

The `withZip` combinator zips two collections element-wise, producing pairs. The
iteration stops when the shorter collection is exhausted:

```flix
use ForEach.withZip;
def main(): Unit \ IO =
let names = List#{"Alice", "Bob", "Carol"};
let ages = List#{30, 25, 40};
foreach ((name, age) <- withZip(names, ages)) {
println("${name} is ${age} years old")
}
```

> **Note:** `withZip` requires both collections to implement the `Iterable`
> trait (not just `ForEach`).