plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
5308f5f
— Peter John
2026-10-26T14:38:28+05:30
docs(plans): T8 = for x := form(...) iteration forms + inline user forms
docs/plans/2026-10-26-zig-generics-and-numbers.md
CHANGED
|
@@ -171,17 +171,40 @@ Tests:
|
|
|
171
171
|
|
|
172
172
|
Update the README's Error handling section, plum-examples/error_propagation.plum (to `T ! [..]` with auto-wrap) and safe_navigation.plum (to `T?`). Migrate std signatures to the sugar where it reads better.
|
|
173
173
|
|
|
174
|
-
##
|
|
175
|
-
|
|
176
|
-
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
-
|
|
174
|
+
## Task T8: `for` forms and inline user forms. This replaces the old "near-free closures" idea, which the user dropped over the risk of code bloat. Not run yet.
|
|
175
|
+
|
|
176
|
+
The user decided: Pyret-style iteration forms written with Plum's existing `for x := …` syntax, including custom forms written by users. Code size stays equal to hand-written loops.
|
|
177
|
+
|
|
178
|
+
1. **Syntax.** `for <binders> := <source>[, <clause>]*` followed by an indented body.
|
|
179
|
+
- Binders: one name, or several comma-separated (`acc, u`, `i, u`, `a, b`).
|
|
180
|
+
- Sources:
|
|
181
|
+
- `range n`, which is unchanged;
|
|
182
|
+
- a bare iterable (`for u := units`), meaning anything with `len()` and `get(i)`;
|
|
183
|
+
- a form call (`filter(units)`, `fold(0.0, units)`, `zip(xs, ys)`).
|
|
184
|
+
- Clauses: `if cond` skips the element, and `name := expr` binds a value for the later clauses and the body. Binders are in scope in the clauses.
|
|
185
|
+
- `for` is an expression when its form returns a value (`alive := for u := filter(units)`), with the body's last expression as the block result. When the form returns Unit it is a statement.
|
|
186
|
+
2. **Inline forms.** `inline fun f[..](params…, body: block(A, B) -> R) -> Out = …`.
|
|
187
|
+
- The last parameter must be a `block`. Its parameter count equals the binder count, and its return type is the type of the body's last expression (Unit for statement bodies).
|
|
188
|
+
- Calling `for a, b := f(args)` expands `f`'s body at the call site, with every `body(x, y)` replaced by the user's body, binders bound to `x, y`, and clauses applied in front.
|
|
189
|
+
- Rules:
|
|
190
|
+
- a `block` value can't escape: it can't be stored, returned or captured, and can't be passed anywhere except another inline form's block parameter, which is the composition case;
|
|
191
|
+
- inline fns can't be recursive (rejected);
|
|
192
|
+
- `break` and `continue` in the user body target the innermost loop the form uses to call `body` (documented per form), and `return` returns from the enclosing non-inline fn;
|
|
193
|
+
- the use-site chain errors apply as with generics.
|
|
194
|
+
3. **Std forms, written in Plum in `plum-std/Iter.plum`:** `filter` (→ List[T]), `map` (→ List[U]), `find` (→ `T?`), `fold(init, xs)` (binders `acc, x`), `any`, `all`, `count`, `indexed` (binders `i, x`), `zip` (binders `a, b`), `each`. None of them is special-cased in the compiler.
|
|
195
|
+
4. **Resolution.** In `for x := f(args)`: if `f` is an inline fn with a final block param, it is expanded. Otherwise the expression must be iterable (`len`/`get`). Otherwise the error is `'f' is not a for-form or iterable`.
|
|
196
|
+
5. **The closure methods stay** (`xs.map(|x| …)`), for passing behaviour around as values.
|
|
180
197
|
|
|
181
198
|
Tests:
|
|
182
|
-
- `
|
|
199
|
+
- `filter_form_no_closure`: the wasm for `for u := filter(units)` has no closure struct.new and no call_indirect;
|
|
183
|
-
- `
|
|
200
|
+
- `map_with_clauses_fused` (one loop, no intermediate List);
|
|
201
|
+
- `fold_two_binders`;
|
|
184
|
-
- `
|
|
202
|
+
- `find_returns_nullable`;
|
|
203
|
+
- `user_form_sumBy` and `user_form_neighbours_grid` (two binders, statement body);
|
|
204
|
+
- `block_escape_rejected` (storing, returning or capturing a block);
|
|
185
|
-
- `
|
|
205
|
+
- `inline_recursion_rejected`;
|
|
186
|
-
|
|
206
|
+
- `break_continue_return_semantics`;
|
|
207
|
+
- `plain_iterable_for`;
|
|
208
|
+
- `not_a_form_error`.
|
|
209
|
+
|
|
187
|
-
Bench:
|
|
210
|
+
Bench: a loop over 10k units doing filter, then map, then fold. Compare the closure-method chain against the fused `for` form, and record the wasm size difference.
|