This PR reorganizes the monad hierarchy for symbolic computation in Lean. ## Motivation We want a clean layering where: 1. A foundational monad (`SymM`) provides maximally shared terms and structural/syntactic `isDefEq` 2. `GrindM` builds on this foundation, adding E-graphs, congruence closure, and decision procedures 3. Symbolic execution / VCGen uses `GrindM` directly without introducing a third monad ## Changes The core symbolic computation layer still lives in `Lean.Meta.Sym`. This monad (`SymM`) provides: - Maximally shared terms with pointer-based equality - Structural/syntactic `isDefEq` and matching (no reduction, predictable cost) - Monotonic local contexts (no `revert` or `clear`), enabling O(1) metavariable validation - Efficient `intro`, `apply`, and `simp` implementations The name "Sym" reflects that this is infrastructure for symbolic computation: symbolic simulation, verification condition generation, and decision procedures. ### Updated hierarchy ``` Lean.Meta.Sym -- SymM: shared terms, syntactic isDefEq, intro, apply, simp Lean.Meta.Grind -- GrindM: E-graphs, congruence closure (extends SymM) ``` Symbolic execution is a usage pattern of `GrindM` operating on `Grind.Goal`, not a separate monad. This keeps the API surface minimal: users learn two monads, and VCGen is "how you use `GrindM`" (for users that want to use `grind`) rather than a third abstraction to understand.
33 lines
960 B
Text
33 lines
960 B
Text
import Lean.Meta.Sym
|
|
open Lean Meta Sym
|
|
open Internal
|
|
def checkMaxFVar (e : Expr) (x : Expr) : SymM Unit := do
|
|
let some fvarId ← getMaxFVar? e | unreachable!
|
|
assert! x.fvarId! == fvarId
|
|
|
|
def test1 : MetaM Unit := do
|
|
let nat := mkConst ``Nat
|
|
withLocalDeclD `x nat fun x => do
|
|
let m₁ ← mkFreshExprMVar nat
|
|
withLocalDeclD `y nat fun y => do
|
|
let m₂ ← mkFreshExprMVar nat
|
|
withLocalDeclD `z nat fun z => do
|
|
SymM.run do
|
|
let x ← shareCommon x
|
|
let y ← shareCommon y
|
|
let z ← shareCommon z
|
|
let m₁ ← shareCommon m₁
|
|
let m₂ ← shareCommon m₂
|
|
let f ← mkConstS `f
|
|
let e₁ ← mkAppS f x
|
|
checkMaxFVar e₁ x
|
|
let e₂ ← mkAppS e₁ m₁
|
|
checkMaxFVar e₂ x
|
|
let e₂ ← mkAppS e₁ m₂
|
|
checkMaxFVar e₂ y
|
|
let e₃ ← mkAppS e₂ (← mkProjS ``Prod 0 (← mkAppS f z))
|
|
checkMaxFVar e₃ z
|
|
let e₄ ← mkAppS f (← shareCommon (mkNatLit 3))
|
|
assert! (← getMaxFVar? e₄).isNone
|
|
|
|
#eval test1
|