Problem
After #278 (opaque LAMBDA/LET), /Unnest correctly leaves inner LAMBDA(...) bodies intact — but it no longer decomposes them at all. For formulas built around inner lambdas, the gnarliest nesting is exactly the part left as one blob.
Example
=ROUND(MIN(BYROW(HSTACK(...), LAMBDA(r, SUM(PAIROP(r, LAMBDA(a,b, SQRT(SUMSQ(PAIROP(XV(VSTACK(a,b), t[[City]:[Y-Coordinates]], {2,3}),,1)))*100),,1)))))+45,)
The distance calc SQRT(SUMSQ(PAIROP(XV(VSTACK(a,b), …)))) lives inside LAMBDA(a, b, …) and is the most opaque, most debug-worthy part — yet #278 leaves it inline because it references the bound params a/b.
Proposed solution (Option 3 — nested-LET-in-LAMBDA)
Decompose inside lambda bodies too, emitting a LET(...) inside the LAMBDA body to hold the steps that reference the lambda's parameters, so scope is preserved:
lambda1, LAMBDA(a, b, LET(
vstack1, VSTACK(a, b),
xv1, XV(vstack1, t[[City]:[Y-Coordinates]], {2,3}),
pairop1, PAIROP(xv1, , 1),
…,
body)),
This is the only option that exposes the inner calc as named, inspectable steps while keeping the formula valid.
Design notes / open questions for the spec
- Synthesiser must emit nested LETs and place each step in the correct (innermost-binding) scope.
- Scope analysis — a step belongs to the innermost lambda scope that binds any of its free variables; closed sub-expressions can still hoist to an outer scope (this subsumes the Option 2 "scope-aware hoisting" idea).
- Dialog must present steps grouped by scope (a renamed / un-included step belongs to a specific lambda's LET), and naming/uniqueness becomes per-scope.
- Preview + round-trip need to handle the nested-LET shape;
/Refactor and /LET to LAMBDA composition over a lambda-with-inner-LET should still work.
Needs a spec (0010) and Tim's approval before planning. Depends on #278.
Problem
After #278 (opaque LAMBDA/LET),
/Unnestcorrectly leaves innerLAMBDA(...)bodies intact — but it no longer decomposes them at all. For formulas built around inner lambdas, the gnarliest nesting is exactly the part left as one blob.Example
The distance calc
SQRT(SUMSQ(PAIROP(XV(VSTACK(a,b), …))))lives insideLAMBDA(a, b, …)and is the most opaque, most debug-worthy part — yet #278 leaves it inline because it references the bound paramsa/b.Proposed solution (Option 3 — nested-LET-in-LAMBDA)
Decompose inside lambda bodies too, emitting a
LET(...)inside the LAMBDA body to hold the steps that reference the lambda's parameters, so scope is preserved:This is the only option that exposes the inner calc as named, inspectable steps while keeping the formula valid.
Design notes / open questions for the spec
/Refactorand/LET to LAMBDAcomposition over a lambda-with-inner-LET should still work.Needs a spec (0010) and Tim's approval before planning. Depends on #278.