88public import Lean.Meta.Tactic.Simp.Types
99public import Lean.Meta.Tactic.Grind.AlphaShareCommon
1010public import Lean.Meta.Tactic.Grind.Attr
11+ public import Lean.Meta.Tactic.Grind.CheckResult
1112public import Init.Data.Queue
1213import Lean.Meta.Tactic.Grind.ExprPtr
1314import Lean.HeadIndex
@@ -1493,6 +1494,38 @@ def withoutModifyingState (x : GoalM α) : GoalM α := do
14931494@[extern "lean_grind_canon"] -- Forward definition
14941495opaque canon (e : Expr) : GoalM Expr
14951496
1497+ /-!
1498+ `Action` is the *control interface* for `grind`’s search steps. It is defined in
1499+ Continuation-Passing Style (CPS).
1500+ See `Grind/Action.lean` for additional details.
1501+ -/
1502+
1503+ abbrev TGrind := TSyntax `grind
1504+
1505+ /-- Result type for a `grind` Action -/
1506+ inductive ActionResult where
1507+ | /--
1508+ The goal has been closed, and you can use `seq` to close the goal efficiently.
1509+ -/
1510+ closed (seq : List TGrind)
1511+ | /--
1512+ The action could not make further progress.
1513+ `gs` are subgoals that could not be closed. They are used for producing error messages.
1514+ -/
1515+ stuck (gs : List Goal)
1516+
1517+ abbrev ActionCont : Type :=
1518+ Goal → GrindM ActionResult
1519+
1520+ abbrev Action : Type :=
1521+ Goal → (kna : ActionCont) → (kp : ActionCont) → GrindM ActionResult
1522+
1523+ @[expose] def Action.notApplicable : Action := fun goal kna _ =>
1524+ kna goal
1525+
1526+ instance : Inhabited Action where
1527+ default := Action.notApplicable
1528+
14961529/-!
14971530Solver Extensions
14981531-/
@@ -1508,9 +1541,9 @@ structure SolverExtension (σ : Type) where private mk ::
15081541 newEq : Expr → Expr → GoalM Unit
15091542 newDiseq : Expr → Expr → GoalM Unit
15101543 mbtc : GoalM Bool
1511- check : GoalM Bool
1544+ action : Action
1545+ check : GoalM Bool -- **TODO** : Consider deleting `check` in the future.
15121546 checkInv : GoalM Unit
1513- mkTactic? : CoreM (Option (TSyntax `grind))
15141547 deriving Inhabited
15151548
15161549private builtin_initialize solverExtensionsRef : IO.Ref (Array (SolverExtension SolverExtensionState)) ← IO.mkRef #[]
@@ -1530,10 +1563,10 @@ def registerSolverExtension {σ : Type} (mkInitial : IO σ) : IO (SolverExtensio
15301563 internalize := fun _ _ => return ()
15311564 newEq := fun _ _ => return ()
15321565 newDiseq := fun _ _ => return ()
1566+ action := Action.notApplicable
15331567 check := fun _ _ => return false
15341568 checkInv := fun _ _ => return ()
15351569 mbtc := fun _ _ => return false
1536- mkTactic? := return none
15371570 }
15381571 solverExtensionsRef.modify fun exts => exts.push (unsafe unsafeCast ext)
15391572 return ext
@@ -1548,16 +1581,16 @@ def SolverExtension.setMethods (ext : SolverExtension σ)
15481581 (newEq : Expr → Expr → GoalM Unit := fun _ _ => return ())
15491582 (newDiseq : Expr → Expr → GoalM Unit := fun _ _ => return ())
15501583 (mbtc : GoalM Bool := return false )
1584+ (action : Action := Action.notApplicable)
15511585 (check : GoalM Bool := return false )
15521586 (checkInv : GoalM Unit := return ())
1553- (mkTactic? : CoreM (Option (TSyntax `grind)) := return none)
15541587 : IO Unit := do
15551588 unless (← initializing) do
15561589 throw (IO.userError "failed to register `grind` solver, extensions can only be registered during initialization" )
15571590 unless ext.id < (← solverExtensionsRef.get).size do
15581591 throw (IO.userError "failed to register `grind` solver methods, invalid solver id" )
15591592 solverExtensionsRef.modify fun exts => exts.modify ext.id fun s => { s with
1560- internalize, newEq, newDiseq, mbtc, check, checkInv, mkTactic?
1593+ internalize, newEq, newDiseq, mbtc, action, check, checkInv
15611594 }
15621595
15631596/-- Returns initial state for registered solvers. -/
@@ -1621,6 +1654,31 @@ def Solvers.mbtc : GoalM Bool := do
16211654 result := true
16221655 return result
16231656
1657+ /--
1658+ Sequential conjunction: executes both `x` and `y`.
1659+
1660+ - Runs `x` and always runs `y` afterward, regardless of whether `x` made progress.
1661+ - It is not applicable only if both `x` and `y` are not applicable.
1662+ -/
1663+ def Action.andAlso (x y : Action) : Action := fun goal kna kp => do
1664+ x goal (fun goal => y goal kna kp) (fun goal => y goal kp kp)
1665+
1666+ /-
1667+ Creates an action that tries all solver extensions. It uses the `Action.andAlso`
1668+ to combine them.
1669+ -/
1670+ def Solvers.mkAction : IO Action := do
1671+ let exts ← solverExtensionsRef.get
1672+ let rec go (i : Nat) (acc : Action) : Action :=
1673+ if h : i < exts.size then
1674+ go (i+1 ) (acc.andAlso exts[i].action)
1675+ else
1676+ acc
1677+ if h : 0 < exts.size then
1678+ return go 1 exts[0 ].action
1679+ else
1680+ return Action.notApplicable
1681+
16241682/--
16251683Given a new disequality `lhs ≠ rhs`, propagates it to relevant theories.
16261684-/
0 commit comments