Inline lambda bodies into comprehensions; emit set comprehensions#2
Merged
Conversation
List combinators now inline a simple lambda body directly into the
comprehension instead of emitting a helper def and calling it:
xs.map (fun x => x + 1) -> [x + 1 for x in xs]
This covers map/filter/filterMap/bind/any/all/find?/findSome?. A named or
caller-supplied function argument still falls back to [f(x) for x in xs], and
a lambda whose body is not a simple expression (e.g. if/else) falls back to a
real def rather than a call to an undefined name.
List.eraseDups / .toFinset / .toSet now emit Python set comprehensions, fusing
an upstream map/filter comprehension into a single set comp and dropping the
now-dead intermediate line:
(xs.filter (·>5)).eraseDups -> {x for x in xs if 5 < x}
Implementation: emitLocalFun defers a single-parameter lambda whose body renders
as one expression (recorded in deferredLambdas, no def emitted), rolling back
state on failure; comprehension combinators splice the body in via fnCompParts;
a deferred lambda used as a value is re-materialized as (lambda p: e). The
renderer is conservative -- unknown constructs return none so the def path runs.
Verified no regression against the corpus (F821/F811 counts unchanged from
baseline). Adds Comprehensions.lean + Comprehensions_test.py (semantic and
structural assertions) and a GitHub Actions CI workflow running both regression
suites.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Improves the fidelity of Python comprehensions generated from Lean list operations.
xs.map (fun x => x + 1)produces[x + 1 for x in xs]instead of a helperdef+[_f(x) for x in xs]. Coversmap,filter,filterMap,bind(flatMap),any,all,find?,findSome?.List.eraseDups/.toFinset/.toSetemit{x for x in xs}instead oflist(dict.fromkeys(...)), and fuse an upstreammap/filter:(xs.filter (·>5)).eraseDups→{x for x in xs if 5 < x}, with the dead intermediate line removed.Behavior that is deliberately preserved
xs.map f,xs.map Nat.succ) still emits correctly —Nat.succinlines ton + 1, an unknownfstays[f(x) for x in xs].if/else) falls back to a realdef— never a call to an undefined name.(lambda p: e).How it works
In LCNF a
maplambda lowers to a localdefthe combinator references by name.emitLocalFunnow tries to render a single-parameter lambda's body as one Python expression (renderExprCode/renderLetValueExpr); on success it defers the lambda (records(param, body), emits nodef), rolling back all state on failure. Comprehension combinators splice the body in viafnCompParts. The renderer is conservative — it returnsnonefor anything not in a known-safe set (constructors,OfNat,bne, nestedcases/fun), so those lambdas fall back to a correctdef.See
CLAUDE.md→ "Lambda Inlining Architecture" for details.Testing
Comprehensions.lean+Comprehensions_test.py: asserts both semantics (correct output) and structure (inlining actually happens, complex bodies fall back to adef, dedup produces a set comprehension, no staledict.fromkeys).ruffover the fullCorpus/CorpusTestCombined.leanoutput)..github/workflows/ci.yml) builds the library and runs both the comprehension and Bool-branch/min-max regression suites on every push and PR.