Closure factories and chained calls
The current implementation supports native owned-value closures and function factories, without translating to Python or evaluating dynamic source code.
A function that returns a function
agent ClosureDemo is Agent
public
ability run() -> List<Int> effects()
factory = (offset: Int) => (value: Int) => value + offset
add_two = factory(2)
add_ten = factory(10)
return [add_two(3), add_ten(3), factory(20)(1)]
The result is [5,13,21]. add_two and add_ten retain independent offset values rather than sharing a mutable capture slot. factory(20)(1) immediately calls the returned function.
Capture timing and mutable containers
Free local variables are captured by owned value when the closure is defined. Later changes to the original variable or container do not alter the captured snapshot. Each call receives another owned-value copy; changing a captured list affects only that call.
This is neither a Python-style shared mutable closure cell nor Agent instance state across requests.
Fn contracts and boundaries
Fn<P1,...,Pn,R> is a pure, positional function contract. The last type is the result. Fn<Int> takes no arguments and returns Int. Named arguments belong to the inferred full closure signature, not the erased Fn contract.
Creating a closure is pure. Calling it propagates all effects of its body. An effectful callback cannot masquerade as a pure Fn.
Closures cannot cross JSON, Host or remote Agent boundaries as public arguments or results, even when nested recursively. The example returns calculated integers, not executable closures to network callers.
Useful chains
factory(20)(1): create a function and call it immediately.agent("Worker").run().score: read a field from an ability's returned record. The account example uses this pattern.- Callables in records or lists: call after field or index access. Use indexing to disambiguate a field from a built-in method, such as
record["values"](). - Agent instance factory chains such as
factory.create(...).method()are not supported by the current version.
Run and modify the example
Save the complete program as closures.aal and run from the AAL repository:
cargo run --locked --bin aalc -- run closures.aal --agent ClosureDemo --ability run --args '{}' --state-dir /tmp/aal-closures --invocation closures-1
Confirm [5,13,21], then change factory(2) to factory(5) and run with a new invocation ID. The first result becomes 8 while the second remains 13. Changing one factory call does not change another closure's captured value.
Continue with the account example to use this pattern in a multi-package project.