lean4-htt/tests/lean/run/reserved.lean
Joachim Breitner d975e4302e
feat: fine-grained equational lemmas for non-recursive functions (#4154)
This is part of #3983.

Fine-grained equational lemmas are useful even for non-recursive
functions, so this adds them.

The new option `eqns.nonrecursive` can be set to `false` to have the old
behavior.

### Breaking channge

This is a breaking change: Previously, `rw [Option.map]` would rewrite
`Option.map f o` to `match o with … `. Now this rewrite will fail
because the equational lemmas require constructors here (like they do
for, say, `List.map`).

Remedies:

 * Split on `o` before rewriting.
* Use `rw [Option.map.eq_def]`, which rewrites any (saturated)
application of `Option.map`
* Use `set_option eqns.nonrecursive false` when *defining* the function
in question.

### Interaction with simp

The `simp` tactic so far had a special provision for non-recursive
functions so that `simp [f]` will try to use the equational lemmas, but
will also unfold `f` else, so less breakage here (but maybe performance
improvements with functions with many cases when applied to a
constructor, as the simplifier will no longer unfold to a large
`match`-statement and then collapse it right away).

For projection functions and functions marked `[reducible]`, `simp [f]`
won’t use the equational theorems, and will only use its internal
unfolding machinery.

### Implementation notes

It uses the same `mkEqnTypes` function as for recursive functions, so we
are close to a consistency here. There is still the wrinkle that for
recursive functions we don't split matches without an interesting
recursive call inside. Unifying that is future work.
2024-08-22 13:26:58 +00:00

136 lines
2.7 KiB
Text

-- `g.eq_def` is not reserved yet
theorem g.eq_def : 1 + x = x + 1 := Nat.add_comm ..
/--
error: failed to declare `g` because `g.eq_def` has already been declared
-/
#guard_msgs (error) in
def g (x : Nat) := x + 1
def f (x : Nat) := x + 1
/--
error: 'f.eq_def' is a reserved name
-/
#guard_msgs (error) in
theorem f.eq_def : f x = x + 1 := rfl
/--
error: 'f.eq_1' is a reserved name
-/
#guard_msgs (error) in
theorem f.eq_1 : f x = x + 1 := rfl
def f.eq_2_ := 10 -- Should be ok
/-- info: f.eq_1 (x : Nat) : f x = x + 1 -/
#guard_msgs in
#check f.eq_1
/-- error: unknown identifier 'f.eq_2' -/
#guard_msgs (error) in
#check f.eq_2
/-- info: f.eq_def (x : Nat) : f x = x + 1 -/
#guard_msgs in
#check f.eq_def
def nonrecfun : Bool → Nat
| false => 0
| true => 0
/--
info: nonrecfun.eq_def :
∀ (x : Bool),
nonrecfun x =
match x with
| false => 0
| true => 0
-/
#guard_msgs in
#check nonrecfun.eq_def
/-- info: nonrecfun.eq_1 : nonrecfun false = 0 -/
#guard_msgs in
#check nonrecfun.eq_1
/-- info: nonrecfun.eq_2 : nonrecfun true = 0 -/
#guard_msgs in
#check nonrecfun.eq_2
def fact : Nat → Nat
| 0 => 1
| n+1 => (n+1) * fact n
/--
info: fact.eq_def :
∀ (x : Nat),
fact x =
match x with
| 0 => 1
| n.succ => (n + 1) * fact n
-/
#guard_msgs in
#check fact.eq_def
/-- info: fact.eq_1 : fact 0 = 1 -/
#guard_msgs in
#check fact.eq_1
/-- info: fact.eq_2 (n : Nat) : fact n.succ = (n + 1) * fact n -/
#guard_msgs in
#check fact.eq_2
/-- error: unknown identifier 'fact.eq_3' -/
#guard_msgs (error) in
#check fact.eq_3
def fact' : Nat → Nat
| 0 => 1
| n+1 => (n+1) * fact' n
example : fact' 0 + fact' 0 = 2 := by
simp [fact'.eq_1]
example : fact' 0 + fact' 1 = 2 := by
rw [fact'.eq_1]
guard_target =ₛ 1 + fact' 1 = 2
rw [fact'.eq_2]
guard_target =ₛ 1 + (0+1) * fact' 0 = 2
rw [fact'.eq_1]
example : fact' 0 + fact' 1 = 2 := by
rw [fact'.eq_def, fact'.eq_def]; simp
guard_target =ₛ 1 + fact' 0 = 2
rw [fact'.eq_def]
guard_target =
(1 + fact.match_1 (fun _ => Nat) 0 (fun _ => 1) fun n => (n + 1) * fact' n) = 2
simp
theorem bla : 0 = 0 := rfl
def bla.def := 1 -- should work since `bla` is a theorem
def bla.eq_1 := 2 -- should work since `bla` is a theorem
def find (as : Array Int) (i : Nat) (v : Int) : Nat :=
if _ : i < as.size then
if as[i] = v then
i
else
find as (i+1) v
else
i
/--
info: find.eq_def (as : Array Int) (i : Nat) (v : Int) :
find as i v = if x : i < as.size then if as[i] = v then i else find as (i + 1) v else i
-/
#guard_msgs in
#check find.eq_def
/--
info: find.eq_1 (as : Array Int) (i : Nat) (v : Int) :
find as i v = if x : i < as.size then if as[i] = v then i else find as (i + 1) v else i
-/
#guard_msgs in
#check find.eq_1