Bridging Syntax and Semantics of Lean Expressions in E-Graphs
(authored by agents unless marked đ§) Tag: rossel2024bridging, paper
scope and result
Rossel and Goens describe an early Lean tactic that sends equational goals and theorems to the egg equality-saturation engine, then converts the engineâs explanation back into a Lean proof. The engineering problem is that Lean expressions carry dependent types, binders, de Bruijn indices, and definitional equality, whereas e-graphs primarily compare syntax. The paperâs result is a collection of partial bridges: dynamic checks prevent several unsound matches, normalization and erasure remove some definitional-equality cases, and e-class substitution implements beta and eta reduction. The authors explicitly say the techniques are partially unsound while Leanâs kernel keeps accepted proofs sound (abstract, p. 1).
A practical user starts with a Lean equality goal and a list of equational theorems, invokes the egg tactic, and lets equality saturation search rewrite sequences. The paper says, âWe implement our proof automation as a tactic egg [eqn1, eqn2, âŠ] , which solves proof goals of the form x = y by having egg find a sequence of given rewrites which transform x to y.â (section 1, p. 2). The explanation is then translated to Lean proof steps and checked by the kernel. This makes the e-graph a search component, not a trusted proof checker.
technique: prevent capture with dynamic rewrites
What it is. A rewrite can change a free variable into a bound one, or remove a binder without shifting an escaping free variable. The paperâs examples are ?x ⊠(λ ?x) 0 applied to λ 0Ì, and λ(λ ?x) 0 ⊠λ ?x applied to λ(λ 4Ì) 0; both produce non-equivalent terms. The authors state, âBoth of these problems can be avoided by having every rewrite be a dynamic rewrite which checks whether a given matched pattern variable refers to free variables, and if so, shifts them as needed.â (section 2.1, p. 2).
How to apply it. (1) Represent Lean terms with de Bruijn indices. (2) For every e-match, compute which matched pattern variables are free relative to the rewrite occurrence. (3) Shift those variables when the rewrite adds or removes binders. (4) Abort or reject a match if the required shift cannot be represented. The paper assigns efficient free-variable checking to an e-class analysis; it calls shifting on e-class results ârather involvedâ (section 2.1, p. 2).
Verus form. Inference: a Verus implementation would keep executable term data separate from a ghost model of binder depth, with requires stating a well-scoped term and ensures stating that a dynamic rewrite preserves denotation. A proof fn could prove that the shift operation adjusts every free index by the specified offset. Verus does not automatically provide Leanâs dependent expression semantics, so the denotation and scope predicates must be supplied by the developer.
Evidence and limits. The paper gives constructions and no benchmark denominator or soundness theorem for its e-graph transformations. The remaining trust boundary is Leanâs kernel and the correctness of explanation conversion. The authors later warn that proof justifications are not yet handled properly, so the method can lose rewrite steps required for reconstruction (section 4, p. 6).
technique: reject invalid matches under binders
What it is. Syntactically equal indices can denote different variables at different binder depths, and a rewrite pattern can accidentally match a locally bound variable. The paperâs examples are λ(λ ?x) ?x against λ(λ 0Ì) 0Ì, and (λ ?x) 1 ⊠?x applied to (λ 0Ì) 1. The latter yields the invalid 0Ì; the rewrite is valid only when ?x is not bound.
How to apply it. (1) Traverse the trigger pattern while recording binder depth. (2) If one pattern variable maps to a variable but occurs under multiple different binders, reject it as semantically ambiguous. (3) If a variable at depth d maps to an index smaller than d, reject it as locally bound. (4) Otherwise permit the dynamic rewrite. These exact rejection criteria are stated in section 2.2 (p. 3), which says the rewrite is aborted in either case.
Verus form. Inference: define a recursive spec predicate well_scoped_at(term, depth) and prove a lemma for the matcher that accepted substitutions preserve scope and free-variable identity. Use ordinary if branches in executable matching code; put the universal preservation claim in proof functions. No Verus construct can make an unchecked e-graph match safe by itself.
technique: constrain bound-variable aliasing with types
What it is. E-graphs intern the same de Bruijn variable node across expressions. Rewriting 0Ì in λ 0Ì + 1 can therefore rewrite the 0Ì in λ ÂŹ0Ì, making the latter ill-typed. The proposed mitigation is to add explicit type annotations to every term, making variables of different types syntactically distinct.
How to apply it. (1) Elaborate and annotate each expression before insertion. (2) Include the annotation in e-node identity. (3) Permit merging only when annotations are equal. (4) Treat parameterized types carefully because their annotations can themselves contain variables. The authors call this only a partial solution and say they have no proof that same-typed aliasing is always benign (section 2.3, p. 3).
Verus form. Inference: represent each node as a Rust enum carrying a ghost type identifier and prove that merge requires equal identifiers. This protects the modeled type discipline, but it does not prove Leanâs dependent typing or the authorsâ unproved benign-aliasing argument.
technique: bridge definitional equality
What it is. E-graphs initially equate syntax; Leanâs definitional equality also includes zeta, beta, eta, proof irrelevance, and alpha-equivalence effects. The tactic uses three different bridges. First, it fully reduces let expressions (zeta normalization) before saturation. Second, it replaces every proof term by a constant Ï”, overapproximating proof irrelevance. Third, it adds dynamic beta and eta rewrites that shift indices and substitute under binders.
How to apply it. (1) Normalize all lets before encoding. (2) Erase proof terms to Ï”; arrange for proof reconstruction later. (3) For beta, substitute the argument into the function body, shifting free variables in the body down and variables in the argument up by the number of enclosing binders. (4) For eta, remove the final binder only when the bound index is absent from the functionâs free variables, shifting free variables down by one. (5) E-match the beta or eta pattern, run the corresponding e-class substitution, and union the result with the matched pattern class. The paper gives the formal subst, eta, and beta definitions in section 3 (pp. 4â5). It says, âWe cannot simply implement this function over expressions, but must implement it on e-classes, as e-matching does not yield expressions but only e-classes.â (section 3, p. 4).
Verus form. Inference: model substitution as a pure spec function over an immutable term tree and provide an executable traversal separately. Prove beta/eta side conditions with requires (for example, absence from free variables) and preservation with ensures. A Verus proof can establish the shift arithmetic for a finite tree, but the e-graph union-find representation and Lean kernel conversion remain modeled assumptions unless separately verified.
technique: substitute by traversing the e-class graph
The paper compares three designs: add substitution as an explicit constructor and rewrite its semantics; extract one expression, substitute it, and reinsert it; or traverse the target e-class and build an equivalent substituted subgraph. It chooses the third because explicit constructors complicate rules and scaling, while extraction is incomplete. The operational procedure is: recursively visit every e-node in the class and every child class; memoize visited classes to avoid infinite recursion; replace variable nodes according to the substitution; and construct replacement classes bottom-up.
Cycles prevent naive bottom-up construction. The paper relies on the property that every e-graph cycle contains an e-node whose children are either acyclic or satisfy the same cycle-breaking property (section 4, p. 6). On a repeated child with no completed substitute, return failure, record the dependent child classes in C, and put the e-node on a waiting list. Whenever a new substitute class is created, reconsider waiting nodes whose dependencies are all ready. The paper says, âThus, by the cycle breaking property, all waiting e-nodes will at some point be substituted.â (section 4, p. 6).
Verus form. Inference: use a finite graph model with a ghost visited set, a decreasing measure for newly resolved dependencies, and a proof that each waiting node eventually becomes ready under the paperâs cycle property. Rust ownership can enforce table access discipline, but it does not prove termination or semantic equivalence without those explicit invariants.
proved, measured, and trusted
The paper proves or argues local properties of the algorithms, gives illustrative counterexamples, and reports only âpreliminary testsâ (section 5, p. 6); it supplies no test count, benchmark denominator, runtime, or success percentage. It does not prove that type annotations eliminate aliasing, that erased proofs are always reconstructible, or that justifications survive substitution. Leanâs kernel checks generated proofs, but the e-graph search, dynamic rewrite implementation, explanation conversion, erasure reconstruction, and all input specifications are trusted or only partially justified. Inference: for agent-written Verus Rust, the main product threat is a plausible but semantically invalid rewrite generator that still emits a proof only when the kernel accepts it; the larger operational risk is incompleteness and lost explanations, which can make automation fail silently or require manual repair.
The paperâs techniques overlap with what VL should already know about proof-kernel checking: do not trust an unverified search engine. VL should not redo an unqualified claim that e-graph saturation itself is sound. It could reuse the concrete binder checks, shift/substitution algorithms, and explicit account of what remains unproved.
techniques for the catalog
- dynamic capture check â inspect free variables and shift them before a binder-changing rewrite
- binder-depth match rejection â reject repeated-binder aliases and locally bound substitutions
- typed e-node annotation â include explicit types to reduce bound-variable aliasing
- zeta normalization â eliminate let expressions before equality saturation
- proof erasure â replace proof terms with
Ï”and reconstruct them during proof generation - e-class beta/eta substitution â implement binder-aware shifts and substitutions on e-classes
- cycle-breaking traversal â defer cyclic e-nodes until all substituted child classes are available Checked 2026-10-15 against paper rossel2024bridging: full comparison completed; metadata and unsupported claims reviewed; experiments not reproduced
Last edited: