import Lean open Lean Meta Sym.Simp cbv_simproc_decl myDeclProc (Nat.succ _) := fun _ => do return .rfl cbv_simproc myPostProc (Nat.add _ _) := fun _ => do return .rfl cbv_simproc ↓ myPreProc (Nat.mul _ _) := fun _ => do return .rfl cbv_simproc cbv_eval myEvalProc (Nat.sub _ _) := fun _ => do return .rfl cbv_simproc ↑ myExplicitPostProc (Nat.mod _ _) := fun _ => do return .rfl cbv_simproc_decl myLateProc (Nat.div _ _) := fun _ => do return .rfl attribute [cbv_simproc cbv_eval] myLateProc opaque myFun : Nat → Nat -- Pre simproc sees unreduced arguments section local cbv_simproc ↓ preTest (myFun _) := fun e => do let .app _f arg := e | return .rfl logInfo m!"pre saw: {arg}" return .rfl /-- info: pre saw: 1 + 2 --- info: pre saw: 3 -/ #guard_msgs in example : myFun (1 + 2) = myFun 3 := by cbv end -- Eval simproc sees reduced arguments (fires before handleApp) section local cbv_simproc cbv_eval evalTest (myFun _) := fun e => do let .app _f arg := e | return .rfl logInfo m!"eval saw: {arg}" return .rfl /-- info: eval saw: 3 --- info: eval saw: 3 --- info: eval saw: 4 --- error: unsolved goals ⊢ myFun 3 = myFun 4 -/ #guard_msgs in example : myFun (1 + 2) = myFun 4 := by cbv end -- Post simproc sees reduced arguments (fires after handleApp) section local cbv_simproc ↑ postTest (myFun _) := fun e => do let .app _f arg := e | return .rfl logInfo m!"post saw: {arg}" return .rfl /-- info: post saw: 3 --- info: post saw: 3 --- info: post saw: 4 --- error: unsolved goals ⊢ myFun 3 = myFun 4 -/ #guard_msgs in example : myFun (1 + 2) = myFun 4 := by cbv end section cbv_simproc ↓ stringToList (String.toList _) := fun e => do let_expr String.toList s := e | return .rfl let some str := getStringValue? s | return .rfl let result ← Sym.share <| toExpr str.toList let typeExpr := mkApp (mkConst ``List [Lean.Level.zero]) (mkConst ``Char) return .step result (mkApp2 (mkConst ``Eq.refl [1]) typeExpr result) (done := true) theorem simprocTest : "a".toList = ['a'] := by cbv /-- info: theorem simprocTest : "a".toList = ['a'] := of_eq_true (Eq.trans (congrFun' (congrArg Eq (Eq.refl ['a'])) ['a']) (eq_self ['a'])) -/ #guard_msgs in #print simprocTest end -- Erase attribute test cbv_simproc_decl erasableProc (Nat.gcd _ _) := fun _ => return .rfl (done := true) theorem erasableProcTest : Nat.gcd 1 2 = 1 := by cbv /-- info: theorem erasableProcTest : Nat.gcd 1 2 = 1 := of_eq_true (Eq.trans (congrFun' (congrArg Eq (Eq.refl 1)) 1) (eq_self 1)) -/ #guard_msgs in #print erasableProcTest /-- error: `erasableProc` does not have a [cbv_simproc] attribute -/ #guard_msgs in attribute [-cbvSimprocAttr] erasableProc attribute [cbv_simproc] erasableProc attribute [-cbvSimprocAttr] erasableProc -- Pattern with @ section local cbv_simproc ↓ testAt (@Nat.succ _) := fun e => do let_expr Nat.succ arg := e | return .rfl logInfo m!"@ saw: {arg}" return .rfl /-- info: @ saw: 1 + 2 -/ #guard_msgs in example : Nat.succ (1 + 2) = 4 := by cbv end -- Pattern with explicit type args via @ section local cbv_simproc ↓ testExplicitList (@List.cons Nat _ _) := fun _ => do logInfo m!"explicit list cons" return .rfl /-- info: explicit list cons --- info: explicit list cons --- info: explicit list cons -/ #guard_msgs in example : ([1, 2, 3] : List Nat) = [1, 2, 3] := by cbv end -- Implicit args are auto-filled: `List.cons _ _` works the same as `@List.cons Nat _ _` section local cbv_simproc ↓ testImplicitList (List.cons _ _) := fun _ => do logInfo m!"implicit list cons" return .rfl /-- info: implicit list cons --- info: implicit list cons --- info: implicit list cons -/ #guard_msgs in example : ([1, 2, 3] : List Nat) = [1, 2, 3] := by cbv end -- Typeclass-heavy pattern section local cbv_simproc ↓ testHAdd (HAdd.hAdd _ _) := fun _ => do logInfo m!"HAdd matched" return .rfl /-- info: HAdd matched -/ #guard_msgs in example : (1 : Nat) + 2 = 3 := by cbv end -- Nested pattern section local cbv_simproc ↓ testNested (Nat.succ (Nat.succ _)) := fun _ => do logInfo m!"nested succ" return .rfl /-- info: nested succ --- info: nested succ -/ #guard_msgs in example : Nat.succ (Nat.succ 0) = 2 := by cbv end -- Explicit type args on Prod.mk section local cbv_simproc ↓ testProd (@Prod.mk Nat Nat _ _) := fun _ => do logInfo m!"prod matched" return .rfl /-- info: prod matched --- info: prod matched -/ #guard_msgs in example : (1 + 2, 3) = (3, 3) := by cbv end -- Scoped simproc: active when namespace is open, inactive when closed namespace ScopedTest scoped cbv_simproc ↓ scopedProc (myFun _) := fun e => do let .app _f arg := e | return .rfl logInfo m!"scoped saw: {arg}" return .rfl /-- info: scoped saw: 0 -/ #guard_msgs in example : myFun 0 = myFun 0 := by cbv end ScopedTest -- Outside the namespace, the simproc should not fire example : myFun 0 = myFun 0 := by cbv -- Re-opening the namespace reactivates the simproc open ScopedTest in /-- info: scoped saw: 0 -/ #guard_msgs in example : myFun 0 = myFun 0 := by cbv -- Over-applied pattern: simproc registered for `myBinFun _` fires on `myBinFun x y` opaque myBinFun : Nat → Nat → Nat section local cbv_simproc ↓ overAppliedProc (myBinFun _) := fun e => do logInfo m!"over-applied saw: {e}" return .rfl /-- info: over-applied saw: myBinFun (1 + 2) --- info: over-applied saw: myBinFun 3 -/ #guard_msgs in example : myBinFun (1 + 2) 4 = myBinFun 3 4 := by cbv end -- Multiple simprocs matching the same head: first non-rfl result wins section local cbv_simproc ↓ multiFirst (myFun _) := fun _ => do logInfo m!"first fired" return .rfl (done := true) local cbv_simproc ↓ multiSecond (myFun _) := fun _ => do logInfo m!"second fired" return .rfl /-- info: first fired -/ #guard_msgs in example : myFun 0 = myFun 0 := by cbv end -- Multiple simprocs: first returns .rfl (skip), second succeeds with .step section @[irreducible] def myConst : Nat := 42 local cbv_simproc ↓ skipFirst (myConst) := fun _e => do logInfo m!"first skipped" return .rfl local cbv_simproc ↓ succeedSecond (myConst) := fun _e => do logInfo m!"second succeeded" let result := toExpr (42 : Nat) return .step result (mkConst ``myConst.eq_def) (done := true) /-- info: first skipped --- info: second succeeded -/ #guard_msgs in example : myConst = 42 := by cbv end