lean4-htt/tests/lean/run/sym_instantiate.lean
Leonardo de Moura 175661b6c3
refactor: reorganize SymM and GrindM monad hierarchy (#11909)
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.
2026-01-06 01:12:07 +00:00

67 lines
1.6 KiB
Text

import Lean.Meta.Sym
set_option sym.debug true
open Lean Meta Sym
open Internal
def tst1 : SymM Unit := do
let f ← mkConstS `f
let e ← mkAppS (← mkAppS (← mkAppS f (← mkBVarS 0)) (← mkBVarS 1)) (← shareCommon (mkNatLit 1))
let a ← mkConstS `a
let b ← mkConstS `b
let r ← instantiateRevS e #[a, b]
assert! r == e.instantiateRev #[a, b]
logInfo r
let r ← instantiateS e #[a, b]
assert! r == e.instantiate #[a, b]
logInfo r
let e ← mkLambdaS `x .default (← mkConstS ``Nat) e
let r ← instantiateRevS e #[a, b]
assert! r == e.instantiateRev #[a, b]
logInfo r
let r ← instantiateS e #[a, b]
assert! r == e.instantiate #[a, b]
logInfo r
/--
info: f b a 1
---
info: f a b 1
---
info: fun x => f x b 1
---
info: fun x => f x a 1
-/
#guard_msgs in
#eval SymM.run tst1
def tst2 : SymM Unit := do
let f ← mkConstS `f
withLocalDeclD `w (← mkConstS ``Nat) fun w => do
let w ← shareCommon w
let e ← mkAppS (← mkAppS (← mkAppS f (← mkBVarS 0)) (← mkBVarS 1)) w
withLocalDeclD `x (← mkConstS ``Nat) fun x => do
withLocalDeclD `y (← mkConstS ``Nat) fun y => do
let x ← shareCommon x
let y ← shareCommon y
logInfo e
let r ← instantiateRevS e #[x, y]
logInfo r
assert! isSameExpr (← abstractFVars r #[x, y]) e
logInfo (← abstractFVars r #[x, y])
logInfo (← abstractFVarsRange r 1 #[x, y])
logInfo (← mkLambdaFVarsS #[x, y] e)
set_option pp.funBinderTypes true in
/--
info: f #0 #1 w
---
info: f y x w
---
info: f #0 #1 w
---
info: f #0 x w
---
info: fun (x y : Nat) => f y x w
-/
#guard_msgs in
#eval SymM.run tst2