@shd101wyy/yo 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: yo-async-effects
3
+ description: Write Yo async code and algebraic effect handlers. Use this when working with IO, Future, JoinHandle, using/given, io.async, io.await, io.spawn, return, and escape.
4
+ argument-hint: "[async task, effect, or API]"
5
+ ---
6
+
7
+ # Yo Async and Effects
8
+
9
+ Use this skill for single-threaded async workflows and algebraic-effect-based APIs in Yo.
10
+
11
+ If a repository wraps these primitives, keep the same semantics and verify whether the wrapper changes naming only or behavior too.
12
+
13
+ ## When to use this skill
14
+
15
+ Use this skill when you need to:
16
+
17
+ - write functions with `using(io : IO)`
18
+ - return or consume `Future(...)` values
19
+ - run tasks with `io.async`, `io.await`, or `io.spawn`
20
+ - define or handle effects via `using(...)` and `given(...)`
21
+ - reason about `return` versus `escape` in handlers
22
+
23
+ ## Workflow
24
+
25
+ 1. Decide whether the task needs sequential async, concurrent async on one thread, or true parallelism.
26
+ 2. Add the necessary `using(...)` parameters to function signatures and call sites.
27
+ 3. Use the [async and effects recipes](./async-effects-recipes.md) for working patterns.
28
+ 4. Re-check handler semantics before finalizing:
29
+ - `return value` resumes the continuation
30
+ - `escape expr` discards it
31
+
32
+ ## High-signal rules
33
+
34
+ - `io.async(fn)` creates a lazy future; it does not start until awaited or spawned.
35
+ - `io.await(future)` runs or waits for the future and returns its result.
36
+ - `io.spawn(future)` starts it without waiting and returns `JoinHandle(T)`.
37
+ - `handle.await(using(io))` returns `Option(T)`; `.None` means the task aborted via `escape`.
38
+ - Future types include their effects: `Future(ResultType, IO, Effect...)`.
39
+ - Effects are matched by type, not variable name.
40
+ - `using(name : Type)` declares an implicit effect parameter; `given(name) := Type(...)` installs the handler.
41
+ - `return value` inside a handler resumes the continuation; `escape expr` discards it.
42
+ - `Exception` — non-resumable; handler calls `escape` to exit. `ResumableException(T)` — handler calls `return` to resume.
43
+ - Effect handlers are standalone, not closures; pass state explicitly.
44
+ - Yo async is single-threaded concurrency, not multithreaded parallelism.
45
+
46
+ ## Resource
47
+
48
+ - [Yo async and effects recipes](./async-effects-recipes.md)
@@ -0,0 +1,262 @@
1
+ # Yo Async and Effects Recipes
2
+
3
+ These patterns cover normal Yo async code and algebraic effects.
4
+
5
+ ## Pick the right execution model
6
+
7
+ | Need | Pattern |
8
+ | -------------------------- | --------------------------------------------------------- |
9
+ | Sequential async work | `result := io.await(task)` |
10
+ | Start work and wait later | `handle := io.spawn(task)` then `handle.await(using(io))` |
11
+ | Yield to other ready tasks | `io.await(yield())` |
12
+ | True multithreading | Use thread or parallelism APIs, not `io.async` alone |
13
+
14
+ ## Minimal async function
15
+
16
+ ```rust
17
+ { yield } :: import "std/async";
18
+
19
+ pause_then_answer :: (fn(using(io : IO)) -> Impl(Future(i32, IO)))(
20
+ io.async((using(io : IO)) => {
21
+ io.await(yield());
22
+ i32(42)
23
+ })
24
+ );
25
+ ```
26
+
27
+ - `io.async(...)` is lazy
28
+ - If a function uses `using(io : IO)` and returns a future, include `IO` in the `Future(...)` type
29
+
30
+ ## Sequential await
31
+
32
+ ```rust
33
+ { yield } :: import "std/async";
34
+
35
+ main :: (fn(using(io : IO)) -> unit)({
36
+ task := io.async((using(io : IO)) => {
37
+ io.await(yield());
38
+ i32(1)
39
+ });
40
+
41
+ result := io.await(task);
42
+ assert((result == i32(1)), "unexpected result");
43
+ });
44
+
45
+ export main;
46
+ ```
47
+
48
+ ## Concurrent tasks on the same thread
49
+
50
+ ```rust
51
+ { yield } :: import "std/async";
52
+
53
+ main :: (fn(using(io : IO)) -> unit)({
54
+ task1 := io.async((using(io : IO)) => {
55
+ io.await(yield());
56
+ i32(1)
57
+ });
58
+ task2 := io.async((using(io : IO)) => {
59
+ io.await(yield());
60
+ i32(2)
61
+ });
62
+
63
+ handle1 := io.spawn(task1);
64
+ handle2 := io.spawn(task2);
65
+
66
+ result1 := handle1.await(using(io));
67
+ result2 := handle2.await(using(io));
68
+ });
69
+
70
+ export main;
71
+ ```
72
+
73
+ - `io.spawn(...)` begins execution without waiting
74
+ - `handle.await(using(io))` returns `Option(T)` because a spawned task can abort via `escape`
75
+
76
+ ## Propagating and handling effects
77
+
78
+ ```rust
79
+ open import "std/fmt";
80
+ open import "std/string";
81
+
82
+ Raise :: (fn(msg : String) -> i32);
83
+
84
+ safe_divide :: (fn(x : i32, y : i32, using(raise : Raise)) -> i32)(
85
+ cond(
86
+ (y == i32(0)) => raise(`divide by zero`),
87
+ true => (x / y)
88
+ )
89
+ );
90
+
91
+ resume_example :: (fn() -> i32)({
92
+ (given(raise) : Raise) = (fn(msg : String) -> i32)({
93
+ println(msg);
94
+ return i32(0);
95
+ });
96
+
97
+ safe_divide(i32(8), i32(0))
98
+ });
99
+
100
+ escape_example :: (fn() -> i32)({
101
+ (given(raise) : Raise) = (fn(msg : String) -> i32)({
102
+ println(msg);
103
+ escape i32(-1);
104
+ });
105
+
106
+ safe_divide(i32(8), i32(0))
107
+ });
108
+ ```
109
+
110
+ | Handler action | Meaning |
111
+ | -------------- | -------------------------------------------- |
112
+ | `return value` | Resume the continuation with `value` |
113
+ | `escape expr` | Exit the function that installed the handler |
114
+
115
+ ## Futures with multiple effects
116
+
117
+ ```rust
118
+ { yield } :: import "std/async";
119
+
120
+ work :: (fn(using(io : IO, raise : Raise)) -> Impl(Future(i32, IO, Raise)))(
121
+ io.async((using(io : IO, raise : Raise)) => {
122
+ io.await(yield());
123
+ safe_divide(i32(10), i32(2), using(raise))
124
+ })
125
+ );
126
+ ```
127
+
128
+ - Every effect used by the future should appear in the `Future(...)` type
129
+ - Effects propagate through `using(...)` just like other contextual parameters
130
+
131
+ ## Common pitfalls
132
+
133
+ - `io.async(...)` does not run immediately
134
+ - `escape` inside async aborts the future instead of completing it normally
135
+ - `io.await(...)` on an aborted future can panic; `JoinHandle.await(...)` converts abort into `.None`
136
+ - Handler functions cannot capture outer variables like closures; pass required state explicitly
137
+
138
+ ## Exception (non-resumable)
139
+
140
+ `Exception` is a built-in module effect for non-resumable error handling. When the handler calls `escape`, the continuation is discarded:
141
+
142
+ ```rust
143
+ open import "std/error";
144
+ open import "std/fmt";
145
+
146
+ DivError :: enum(DivByZero);
147
+ impl(DivError, ToString(to_string : ((self) -> `division by zero`)));
148
+ impl(DivError, Error());
149
+
150
+ safe_divide :: (fn(x : i32, y : i32, using(exn : Exception)) -> i32)(
151
+ cond(
152
+ (y == i32(0)) => exn.throw(dyn(DivError.DivByZero)),
153
+ true => (x / y)
154
+ )
155
+ );
156
+
157
+ main :: (fn() -> unit)({
158
+ given(exn) := Exception(
159
+ throw : ((err) -> {
160
+ println(`Error: ${err}`);
161
+ escape ();
162
+ })
163
+ );
164
+
165
+ result := safe_divide(i32(10), i32(2));
166
+ println(`result: ${result}`);
167
+
168
+ safe_divide(i32(10), i32(0));
169
+ });
170
+
171
+ export main;
172
+ ```
173
+
174
+ - `Exception` has a single field `throw : (fn(error : AnyError) -> T)`
175
+ - `exn.throw(dyn(error))` calls the handler with a type-erased error
176
+ - Handler uses `escape` to discard the continuation and exit the enclosing function
177
+ - Code after the escaped call is never reached
178
+
179
+ ## ResumableException
180
+
181
+ `ResumableException(ResumeType)` is a module effect for resumable error handling. The handler uses `return` to resume with a recovery value:
182
+
183
+ ```rust
184
+ open import "std/error";
185
+ open import "std/fmt";
186
+
187
+ safe_divide :: (fn(x : i32, y : i32, using(exn : ResumableException(i32))) -> i32)(
188
+ cond(
189
+ (y == i32(0)) => exn.throw(dyn(`division by zero`)),
190
+ true => (x / y)
191
+ )
192
+ );
193
+
194
+ main :: (fn() -> unit)({
195
+ given(exn) := ResumableException(i32)(
196
+ throw : ((err) -> {
197
+ println(`Recovering from: ${err}`);
198
+ return i32(0);
199
+ })
200
+ );
201
+
202
+ result := safe_divide(i32(10), i32(0));
203
+ assert((result == i32(0)), "recovered with 0");
204
+ });
205
+
206
+ export main;
207
+ ```
208
+
209
+ - Handler uses `return value` to resume the continuation with the recovery value
210
+ - The call site receives the returned value and continues normally
211
+
212
+ ## Module effects vs function-type effects
213
+
214
+ Effects in Yo can be plain function types or module types:
215
+
216
+ ```rust
217
+ Raise :: (fn(msg : String) -> i32);
218
+
219
+ Logger :: module(
220
+ log : (fn(level : i32, msg : String) -> unit)
221
+ );
222
+ ```
223
+
224
+ Both kinds use `using(...)` / `given(...)` with the same semantics — they compile to evidence passing (function pointers as implicit C parameters). Module effects group related operations under a single name.
225
+
226
+ ## Async with effects
227
+
228
+ When an async future uses effects, include them in the `Future` type:
229
+
230
+ ```rust
231
+ work :: (fn(using(io : IO, exn : Exception)) -> Impl(Future(i32, IO, Exception)))(
232
+ io.async((using(io : IO, exn : Exception)) => {
233
+ io.await(yield());
234
+ safe_divide(i32(10), i32(2), using(exn))
235
+ })
236
+ );
237
+ ```
238
+
239
+ To spawn a task with effects, pass them explicitly via `using`:
240
+
241
+ ```rust
242
+ handle := io.spawn(task, using(io, exn));
243
+ result := handle.await(using(io));
244
+ match(result,
245
+ .Some(value) => println(`got: ${value}`),
246
+ .None => println("task aborted via escape")
247
+ );
248
+ ```
249
+
250
+ ## Effect row variables (advanced)
251
+
252
+ Functions can be polymorphic over their effects using spread parameters:
253
+
254
+ ```rust
255
+ wrapper :: (fn(forall(...(E)), x : i32, using(...(E))) -> i32)(
256
+ safe_divide(x, i32(2))
257
+ );
258
+ ```
259
+
260
+ - `forall(...(E))` introduces an effect row variable
261
+ - `using(...(E))` forwards whatever effects the caller provides
262
+ - See [ALGEBRAIC_EFFECTS.md](https://github.com/shd101wyy/Yo/blob/develop/docs/en-US/ALGEBRAIC_EFFECTS.md) for the full design
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: yo-core-patterns
3
+ description: Write everyday Yo application and library code. Use this when choosing Yo types, imports, strings, Option/Result, collections, traits, boxes, pointers, and standard-library modules.
4
+ argument-hint: "[feature, data type, or module]"
5
+ ---
6
+
7
+ # Yo Core Patterns
8
+
9
+ Use this skill for normal Yo program structure and standard-library usage rather than compiler internals.
10
+
11
+ If a repository defines local wrappers or conventions, follow them after these baseline patterns.
12
+
13
+ ## When to use this skill
14
+
15
+ Use this skill when you need to:
16
+
17
+ - pick between built-in types and standard-library types
18
+ - choose import paths for common Yo modules
19
+ - model optional values or recoverable errors
20
+ - write collection-heavy, string-heavy, or trait-based code
21
+ - handle boxes, pointers, and platform-specific branches
22
+
23
+ ## Workflow
24
+
25
+ 1. Identify whether the task is about data modeling, strings, containers, errors, or imports.
26
+ 2. Choose the smallest built-in or standard-library type that fits the job.
27
+ 3. Use the [core patterns cheatsheet](./core-patterns-cheatsheet.md) for imports, strings, `Option`/`Result`, traits, and collections.
28
+ 4. Prefer standard modules before inventing custom helpers.
29
+
30
+ ## High-signal rules
31
+
32
+ - `"` creates `str` in runtime code; template strings create `String`. In `comptime` functions, `"hello"` is `comptime_string` (distinct from `str`).
33
+ - Prefer template strings for constant `String` values.
34
+ - Prefer `print`/`println` from `std/fmt` over `printf`.
35
+ - `Option(T)` and `Result(T, E)` are the default nullable/error carriers.
36
+ - Use `rune` for Unicode code points, not `Char`.
37
+ - Model nullable pointers with `Option(*(T))` or `?*(T)`.
38
+ - Use `struct` for value types, `newtype` for single-field wrappers, `object` for reference-counted types.
39
+ - Use `forall` + `where` for generic impls; use `_` placeholder for partial application of comptime functions.
40
+ - Use `derive(Type, Eq, Hash, Clone, Ord, ToString)` to auto-generate common trait impls.
41
+ - Custom error types implement `ToString` + `Error`; wrap with `dyn(...)` into `AnyError`.
42
+ - Use `(params) => expr` for closures; `Impl(Fn(...) -> T)` for the closure type.
43
+ - Use `for collection.iter(), (item) => { ... }` for iteration.
44
+ - Indexed modules import cleanly as `std/url`, `std/regex`, `std/http`, `std/log`, and `std/glob`; multi-module families use explicit submodules.
45
+
46
+ ## Resource
47
+
48
+ - [Yo core patterns cheatsheet](./core-patterns-cheatsheet.md)
@@ -0,0 +1,318 @@
1
+ # Yo Core Patterns Cheatsheet
2
+
3
+ These patterns are aimed at everyday Yo application and library code.
4
+
5
+ ## Strings and output
6
+
7
+ ```rust
8
+ open import "std/fmt";
9
+ open import "std/string";
10
+
11
+ (name : str) = "yo";
12
+ greeting := `Hello ${name}`;
13
+
14
+ println(greeting);
15
+ println("plain str is also fine");
16
+ ```
17
+
18
+ - `"hello"` is a `str` literal in normal runtime code
19
+ - `` `hello ${name}` `` creates a `String`
20
+ - Prefer template strings for constant `String` values instead of `String.from("...")`
21
+ - Prefer `print`/`println` when a type implements `ToString`
22
+
23
+ ### String type disambiguation
24
+
25
+ | Type | When you see it | Key behavior |
26
+ | ----------------- | -------------------------------------------- | -------------------------------------- |
27
+ | `str` | `"hello"` in runtime contexts | Slice of bytes, no ownership |
28
+ | `String` | Template strings `` `hello` `` | Owned UTF-8, reference-counted |
29
+ | `comptime_string` | `"hello"` inside `comptime` functions/macros | Compile-time only, distinct from `str` |
30
+
31
+ Key rules:
32
+
33
+ - In **runtime** code, `"hello"` is always `str`. Mixing literal and variable branches in `cond`/`match` works fine.
34
+ - In **comptime** functions (return type `comptime(...)`), `"hello"` is `comptime_string`. It does NOT auto-convert to `str`. Use `str.from_raw_parts(*(u8)("..."), usize(N))` if a comptime function needs to return `str`.
35
+ - For `String` constants, prefer `` `hello` `` over `String.from("hello")`.
36
+
37
+ ## Import patterns
38
+
39
+ ```rust
40
+ { LocalType } :: import "./local_type.yo";
41
+ open import "std/string";
42
+ { ArrayList } :: import "std/collections/array_list";
43
+ { HashMap } :: import "std/collections/hash_map";
44
+ { Url } :: import "std/url";
45
+ { Regex } :: import "std/regex";
46
+ { fetch, HttpRequest } :: import "std/http";
47
+ ```
48
+
49
+ | Need | Import pattern |
50
+ | ------------------------------ | ------------------------------------------------------------------------------------ |
51
+ | Local module in same directory | `./file.yo` |
52
+ | Module with a clean index | `std/url`, `std/regex`, `std/http`, `std/log`, `std/glob` |
53
+ | Collections | `std/collections/array_list`, `std/collections/hash_map`, `std/collections/hash_set` |
54
+ | File system | `std/fs/file`, `std/fs/dir`, `std/path` |
55
+ | Networking | `std/net/tcp`, `std/net/udp`, `std/net/dns` |
56
+
57
+ Do not import `std/prelude`; it is already available.
58
+
59
+ ## Option and Result
60
+
61
+ ```rust
62
+ open import "std/string";
63
+
64
+ (value : Option(i32)) = .Some(i32(21));
65
+ doubled := value.map((x) => (x * i32(2)));
66
+ fallback := value.unwrap_or_else(() => i32(0));
67
+
68
+ (parsed : Result(i32, String)) = .Ok(i32(42));
69
+ text := match(parsed,
70
+ .Ok(n) => `value=${n}`,
71
+ .Err(err) => err
72
+ );
73
+ ```
74
+
75
+ - Use `Option(T)` when absence is expected and ordinary
76
+ - Use `Result(T, E)` when the caller should handle failure
77
+ - Prefer combinators for straight-line transforms: `map`, `and_then`, `map_err`, `or_else`
78
+ - Switch to `match(...)` when branches need different logic or side effects
79
+
80
+ ## Collections
81
+
82
+ ```rust
83
+ { ArrayList } :: import "std/collections/array_list";
84
+ { HashMap } :: import "std/collections/hash_map";
85
+ open import "std/string";
86
+
87
+ numbers := ArrayList(i32).new();
88
+ numbers.push(i32(1));
89
+ numbers.push(i32(2));
90
+
91
+ counts := HashMap(String, i32).new();
92
+ counts.set(`yo`, i32(1));
93
+ ```
94
+
95
+ | Type | Use when |
96
+ | ---------------- | ---------------------------------------- |
97
+ | `ArrayList(T)` | Ordered growable sequence |
98
+ | `HashMap(K, V)` | Key/value lookup with `Eq` + `Hash` keys |
99
+ | `HashSet(T)` | Membership tests and deduplication |
100
+ | `BTreeMap(K, V)` | Ordered map with `Ord` keys |
101
+ | `Deque(T)` | Push/pop on both ends |
102
+ | `String` | Owned UTF-8 text |
103
+
104
+ ## Traits and associated types
105
+
106
+ ```rust
107
+ Iterator :: trait(
108
+ Item : Type,
109
+ next : (fn(self : *(Self)) -> Option(Self.Item))
110
+ );
111
+ ```
112
+
113
+ - Traits use labeled fields directly inside `trait(...)`
114
+ - Associated types are fields like `Item : Type` or `Output : Type`
115
+ - Wrap `fn` types in parentheses inside traits and type annotations
116
+
117
+ ## Boxes, pointers, and nullability
118
+
119
+ ```rust
120
+ counter := box(i32(0));
121
+ counter.* = (counter.* + i32(1));
122
+
123
+ (ptr : Option(*(u8))) = .None;
124
+ ```
125
+
126
+ - Use `Box(T)` or `box(value)` for owned heap allocation
127
+ - Use `*(T)` for raw pointers
128
+ - Model nullable pointers as `Option(*(T))` or `?*(T)`, not sentinel integers
129
+
130
+ ## Unicode and platform checks
131
+
132
+ ```rust
133
+ { Platform, platform } :: import "std/process";
134
+
135
+ separator := cond(
136
+ (platform == Platform.Windows) => `\\`,
137
+ true => `/`
138
+ );
139
+ ```
140
+
141
+ - Use `rune` for Unicode code points
142
+ - Branch on `platform` and `Platform` for OS-specific behavior
143
+
144
+ ## Type categories
145
+
146
+ ```rust
147
+ Point :: struct(x : i32, y : i32);
148
+
149
+ FilePermission :: newtype(mode : u32);
150
+
151
+ TcpStream :: object(fd : i32, buffer : ArrayList(u8));
152
+ ```
153
+
154
+ | Keyword | Semantics |
155
+ | -------------- | --------------------------------------- |
156
+ | `struct(...)` | Value type, copied on assignment |
157
+ | `newtype(...)` | Single-field value wrapper |
158
+ | `object(...)` | Reference-counted, shared on assignment |
159
+
160
+ - Use `newtype(...)` when the type has exactly one field
161
+ - Use `object(...)` for types that need shared ownership
162
+
163
+ ## Impl blocks and generics
164
+
165
+ ```rust
166
+ impl(Point,
167
+ distance : (fn(self : Self, other : Point) -> f64)({
168
+ dx := f64((self.x - other.x));
169
+ dy := f64((self.y - other.y));
170
+ sqrt(((dx * dx) + (dy * dy)))
171
+ })
172
+ );
173
+
174
+ impl(forall(T), where(T <: ToString), Box(T),
175
+ show : (fn(self : Self) -> unit)(
176
+ println(self.*)
177
+ )
178
+ );
179
+ ```
180
+
181
+ - Use `Self` inside impl method signatures
182
+ - `forall(T)` + `where(T <: Trait)` for generic impls
183
+ - Trait impls: `impl(MyType, MyTrait(args), : trait_field_bindings...)`
184
+
185
+ ## Partial application
186
+
187
+ ```rust
188
+ IntResult :: Result(_, i32);
189
+ (r : IntResult(bool)) = .Ok(true);
190
+
191
+ add :: (fn(comptime(x) : i32, comptime(y) : i32) -> comptime(i32))((x + y));
192
+ add1 :: add(i32(1), _);
193
+ ```
194
+
195
+ - Use `_` placeholder in comptime function calls to partially apply
196
+ - Works with type constructors: `Result(_, i32)` makes a one-argument type function
197
+ - Only valid for functions with `comptime` return types
198
+
199
+ ## Dynamic dispatch
200
+
201
+ ```rust
202
+ (value : Dyn(ToString)) = dyn(i32(42));
203
+ println(value);
204
+ ```
205
+
206
+ - `Dyn(Trait)` is a type-erased trait object
207
+ - `dyn(expr)` wraps a concrete value into the trait object
208
+ - `Impl(Trait)` is the static dispatch counterpart
209
+
210
+ ## Derive traits
211
+
212
+ ```rust
213
+ Point :: struct(x : i32, y : i32);
214
+ derive(Point, Eq, Hash, Clone, Ord, ToString);
215
+
216
+ p1 := Point(1, 2);
217
+ p2 := p1.clone();
218
+ assert((p1 == p2), "equal after clone");
219
+ println(p1.to_string());
220
+ ```
221
+
222
+ - Built-in derivable traits: `Eq`, `Hash`, `Clone`, `Ord`, `ToString`
223
+ - Works for both structs and enums
224
+ - Custom derives can be registered with `derive_rule`; see [DERIVE_TRAITS.md](https://github.com/shd101wyy/Yo/blob/develop/docs/en-US/DERIVE_TRAITS.md)
225
+
226
+ ## Error handling
227
+
228
+ ```rust
229
+ open import "std/error";
230
+
231
+ DivError :: enum(DivByZero);
232
+ impl(DivError, ToString(to_string : ((self) -> `division by zero`)));
233
+ impl(DivError, Error());
234
+
235
+ safe_div :: (fn(a : i32, b : i32) -> Result(i32, DivError))(
236
+ cond(
237
+ (b == i32(0)) => .Err(.DivByZero),
238
+ true => .Ok((a / b))
239
+ )
240
+ );
241
+ ```
242
+
243
+ - Custom error types implement both `ToString` and `Error` traits
244
+ - `AnyError` is `Dyn(Error)` — wraps any error: `(err : AnyError) = dyn(MyError.Foo)`
245
+ - Use `downcast(err, MyError)` to recover the concrete type from `AnyError`
246
+ - For exception-style control flow, see [yo-async-effects](../yo-async-effects/SKILL.md)
247
+
248
+ ## Closures as values
249
+
250
+ ```rust
251
+ (inc : Impl(Fn(x : i32) -> i32)) = ((x) => (x + i32(1)));
252
+ result := inc(i32(5));
253
+
254
+ transform :: (fn(values : ArrayList(i32), f : Impl(Fn(x : i32) -> i32)) -> unit)({
255
+ for values.iter(), (ptr) => {
256
+ ptr.* = f(ptr.*);
257
+ };
258
+ });
259
+ ```
260
+
261
+ - `(params) => expr` creates a closure
262
+ - `Impl(Fn(params) -> ReturnType)` is the closure type
263
+ - Closures capture: value types by copy, object types by reference
264
+ - Each closure has a unique type
265
+
266
+ ## Iterator and for loop
267
+
268
+ ```rust
269
+ { ArrayList } :: import "std/collections/array_list";
270
+
271
+ list := ArrayList(i32).new();
272
+ list.push(i32(1));
273
+ list.push(i32(2));
274
+
275
+ for list.iter(), (ptr) => {
276
+ println(ptr.*);
277
+ };
278
+
279
+ for list.into_iter(), (value) => {
280
+ println(value);
281
+ };
282
+ ```
283
+
284
+ | Method | Yields | Semantics |
285
+ | -------------- | ------ | ----------------------------------- |
286
+ | `.iter()` | `*(T)` | Borrow via pointer; yields pointers |
287
+ | `.into_iter()` | `T` | Takes ownership; yields values |
288
+
289
+ - Implement `Iterator` trait to make custom types iterable
290
+ - Implement `IntoIterator` trait for collection-style iteration
291
+
292
+ ## Module-level mutable variables
293
+
294
+ ```rust
295
+ counter := i32(0);
296
+
297
+ inc :: (fn() -> unit)({
298
+ counter = (counter + i32(1));
299
+ });
300
+ ```
301
+
302
+ - Top-level `:=` creates a C `static` file-scope variable
303
+ - Cannot be exported; only compile-time values can be exported
304
+ - Not allowed inside `impl` blocks; use `::` for constants there
305
+
306
+ ## Anonymous modules
307
+
308
+ ```rust
309
+ my_module :: impl {
310
+ helper :: (fn(x : i32) -> i32)((x + i32(1)));
311
+ export helper;
312
+ };
313
+
314
+ result := my_module.helper(i32(5));
315
+ ```
316
+
317
+ - `impl { ... }` creates a module namespace
318
+ - Only `::` (compile-time) bindings are allowed inside