Skip to content

fix: lambdas capture their defining environment#883

Open
mwaddip wants to merge 1 commit into
ergoplatform:developfrom
mwaddip:fix/lambda-env-capture
Open

fix: lambdas capture their defining environment#883
mwaddip wants to merge 1 commit into
ergoplatform:developfrom
mwaddip:fix/lambda-env-capture

Conversation

@mwaddip

@mwaddip mwaddip commented Jun 6, 2026

Copy link
Copy Markdown

The JVM's FuncValue.eval returns a closure over its defining env (values.scala); each application evaluates the body in that captured env plus the argument binding. sigma-rust's Value::Lambda carried only args + body, and every invocation site (Apply, the Coll/Option HOF evals) bound arguments into the CALLER's env with a save/restore dance — wrong for lambdas that escape: the inner lambda of add = (a: Int) => (b: Int) => a + b lost a when the outer Apply returned, so the curried add(3)(1) errored where the JVM evaluates 4.

Lambda now captures its defining bindings and a shared LambdaInvoker evaluates bodies in the captured env — uniformly, since an escaped lambda fed to a HOF hits the same root cause.

Surfaced by SANTA's v6 HOF vectors (add(3)(1) → Int 4).

The JVM's FuncValue.eval returns a closure over the env it was created in
(values.scala): each application evaluates the body in that captured env
extended with the argument binding. sigma-rust's Value::Lambda carried
only args + body, and every invocation site (Apply and the HOF evals)
bound arguments into the CALLER's env with a save/restore dance — correct
for lambdas applied where they were created, wrong for lambdas that
escape: the inner lambda of add = (a: Int) => (b: Int) => a + b lost a
the moment the outer Apply returned, so the curried add(3)(1) errored
where the JVM evaluates 4.

Lambda gains the captured bindings (snapshotted by FuncValue::eval), and
a shared LambdaInvoker materializes the captured env once per lambda
value and binds the argument slot per call — replacing the save/restore
dance in Apply, Coll.{map,filter,fold,exists,forAll,flatMap} and
Option.{map,filter}. The capture must hold uniformly: an escaped lambda
fed to a HOF (val f = mk(3); coll.map(f)) hits the same root cause.

Surfaced by SANTA's v6 HOF vectors (HOF_currying_Apply_of_Apply,
blessed Int 4).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant