import Lean
import Mathlib.Tactic
open Lean Meta Elab Command Tactic
Inspired by
elab "proofs "n:n: TSyntax `numnum :num: Parser.Parsertactic => dotactic: Parser.CategorywithMainContext do letwithMainContext: {α : Type} → TacticM α → TacticM αmvarId ::mvarId: MVarIdmvarIds ←mvarIds: List MVarIdgetUnsolvedGoals |getUnsolvedGoals: TacticM (List MVarId)throwNoGoalsToBeSolvedthrowNoGoalsToBeSolved: {α : Type} → TacticM αsetGoals $setGoals: List MVarId → TacticM UnitList.replicate (List.replicate: {α : Type} → ℕ → α → List αn.n: TSyntax `numraw.raw: {ks : SyntaxNodeKinds} → TSyntax ks → SyntaxtoNat)toNat: Syntax → ℕmvarId ++mvarId: MVarIdmvarIds elab (name :=mvarIds: List MVarIdproof) "proof"proof: ParserDescr_n:(_n: Option (TSyntax `num)num)?num: Parser.Parser_desc:_desc: Option (TSyntax Name.anonymous)interpolatedStr(interpolatedStr: Parser.Parser → Parser.Parserterm)? ":"term: Parser.Categoryt:t: TSyntax `Lean.Parser.Tactic.tacticSeqtacticSeq :tacticSeq: Parser.Parsertactic => dotactic: Parser.CategorywithMainContext do letwithMainContext: {α : Type} → TacticM α → TacticM αmvarId ::mvarId: MVarIdmvarIds ←mvarIds: List MVarIdgetUnsolvedGoals |getUnsolvedGoals: TacticM (List MVarId)throwNoGoalsToBeSolved -- focus on the first goalthrowNoGoalsToBeSolved: {α : Type} → TacticM αsetGoals [setGoals: List MVarId → TacticM UnitmvarId] -- save the non-proven state for recover after the proof letmvarId: MVarIdb ←b: Tactic.SavedStatesaveState -- run the proof letsaveState: {s : outParam Type} → {m : Type → Type} → [self : MonadBacktrack s m] → m sa ←a: UnitevalTacticevalTactic: Syntax → TacticM Unitt -- detect sorry in proof if lett: TSyntax `Lean.Parser.Tactic.tacticSeqsomesome: {α : Type ?u.1053} → α → Option αproof :=proof: Expr(←(← getMCtx): MetavarContextgetMCtxgetMCtx: {m : Type → Type} → [self : MonadMCtx m] → m MetavarContext).(← getMCtx): MetavarContexteAssignment.eAssignment: MetavarContext → PersistentHashMap MVarId Exprfind?find?: {α β : Type} → {x : BEq α} → {x_1 : Hashable α} → PersistentHashMap α β → α → Option βmvarId then ifmvarId: MVarIdproof.proof: ExprisSorry thenisSorry: Expr → BoollogWarninglogWarning: {m : Type → Type} → [inst : Monad m] → [inst : MonadLog m] → [inst : AddMessageContext m] → [inst : MonadOptions m] → MessageData → m UnitlogWarning "proof uses 'sorry'": TacticM Unit"proof uses 'sorry'" -- detect unsolved goals let"proof uses 'sorry'": Stringgs ←gs: List MVarIdgetUnsolvedGoals if !getUnsolvedGoals: TacticM (List MVarId)gs.gs: List MVarIdisEmpty thenisEmpty: {α : Type} → List α → BoolTerm.reportUnsolvedGoalsTerm.reportUnsolvedGoals: List MVarId → MetaM UnitTerm.reportUnsolvedGoals gs: TacticM Unitgs -- if it's not the last alternative proof, restore the non-proven state and restore the remaining goals -- otherwise the remaining goal will be proven automatically if !gs: List MVarIdmvarIds.mvarIds: List MVarIdisEmpty then letisEmpty: {α : Type} → List α → Boolmsgs ←msgs: MessageLogCore.getMessageLogCore.getMessageLog: CoreM MessageLogb.b: Tactic.SavedStaterestorerestore: Tactic.SavedState → optParam Bool false → TacticM UnitsetGoalssetGoals: List MVarId → TacticM UnitmvarIdsmvarIds: List MVarIdCore.setMessageLogCore.setMessageLog: MessageLog → CoreM UnitCore.setMessageLog msgs: TacticM Unitmsgs -- else use the last proof as the proof -- TODO this doesn't guarantee that the whole theorem is proven if any of the proofs are valid -- it also doesn't guarantee that the whole theorem is proven only if all of the proofs are validmsgs: MessageLogpurepure: {f : Type → Type} → [self : Pure f] → {α : Type} → α → f αa elab (name :=a: UnitQED) "QED" :QED: ParserDescrtactic => do lettactic: Parser.Categorygs ←gs: List MVarIdgetUnsolvedGoals ifgetUnsolvedGoals: TacticM (List MVarId)gs.gs: List MVarIdisEmpty thenisEmpty: {α : Type} → List α → BoollogInfologInfo: {m : Type → Type} → [inst : Monad m] → [inst : MonadLog m] → [inst : AddMessageContext m] → [inst : MonadOptions m] → MessageData → m Unit" 🎉 Goals accomplished" else" 🎉 Goals accomplished": StringlogErrorlogError: {m : Type → Type} → [inst : Monad m] → [inst : MonadLog m] → [inst : AddMessageContext m] → [inst : MonadOptions m] → MessageData → m Unit"☝️ Unresolved goals" elab (name :="☝️ Unresolved goals": StringWIP) "WIP" :WIP: ParserDescrtactic => do lettactic: Parser.Categorygs ←gs: List MVarIdgetUnsolvedGoals ifgetUnsolvedGoals: TacticM (List MVarId)gs.gs: List MVarIdisEmpty thenisEmpty: {α : Type} → List α → BoollogErrorlogError: {m : Type → Type} → [inst : Monad m] → [inst : MonadLog m] → [inst : AddMessageContext m] → [inst : MonadOptions m] → MessageData → m Unit" 🎉 Goals accomplished, mark it with QED" else" 🎉 Goals accomplished, mark it with QED": StringlogWarninglogWarning: {m : Type → Type} → [inst : Monad m] → [inst : MonadLog m] → [inst : AddMessageContext m] → [inst : MonadOptions m] → MessageData → m Unit"☝️ Unresolved goals""☝️ Unresolved goals": Stringexample (example: ∀ (a b c : ℕ), a + b * c = c * b + aaa: ℕbb: ℕc :c: ℕℕ) :ℕ: Typea +a: ℕb *b: ℕc =c: ℕc *c: ℕb +b: ℕa :=a: ℕGoals accomplished! 🐙a, b, c: ℕa + b * c = c * b + aa, b, c: ℕa + b * c = c * b + aa, b, c: ℕa + b * c = c * b + aa, b, c: ℕa + b * c = c * b + aa, b, c: ℕa + b * c = c * b + aa, b, c: ℕb * c + a = c * b + aa, b, c: ℕb * c = c * ba, b, c: ℕc * b = c * bGoals accomplished! 🐙a, b, c: ℕa + b * c = c * b + a-- to see the colorful effect, comment out #guard_msgs inGoals accomplished! 🐙
error: unsolved goals ⊢ 2 + 1 = 3
in theoremex :ex: 1 + 2 = 31 +1: ℕ2 =2: ℕ3 :=3: ℕGoals accomplished! 🐙1 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 3Goals accomplished! 🐙1 + 2 = 31 + 2 = 31 + 2 = 31 + 2 = 3Goals accomplished! 🐙1 + 2 = 31 + 2 = 31 + 2 = 3Goals accomplished! 🐙1 + 2 = 31 + 2 = 31 + 2 = 32 + 1 = 32 + 1 = 31 + 2 = 31 + 2 = 3Goals accomplished! 🐙Goals accomplished! 🐙Goals accomplished! 🐙example :example: 1 + 1 = 21 +1: ℕ1 =1: ℕ2 :=2: ℕGoals accomplished! 🐙1 + 1 = 21 + 1 = 21 + 1 = 21 + 1 = 2Goals accomplished! 🐙1 + 1 = 2Goals accomplished! 🐙Goals accomplished! 🐙