283 lines
6.2 KiB
Text
283 lines
6.2 KiB
Text
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
|