lean4-htt/tests/lean/run/wfirred.lean
Joachim Breitner f9dc77673b
feat: dedicated fix operator for well-founded recursion on Nat (#7965)
This PR lets recursive functions defined by well-founded recursion use a
different `fix` function when the termination measure is of type `Nat`.
This fix-point operator use structural recursion on “fuel”, initialized
by the given measure, and is thus reasonable to reduce, e.g. in `by
decide` proofs.

Extra provisions are in place that the fixpoint operator only starts
reducing when the fuel is fully known, to prevent “accidential” defeqs
when the remaining fuel for the recursive calls match the initial fuel
for that recursive argument.

To opt-out, the idiom `termination_by (n,0)` can be used.

We still use `@[irreducible]` as the default for such recursive
definitions, to avoid unexpected `defeq` lemmas. Making these functions
`@[semireducible]` by default showed performance regressions in lean.
When the measure is of type `Nat`, the system will accept an explicit
`@[semireducible]` without the usual warning.

Fixes #5234. Fixes: #11181.
2025-12-01 12:51:55 +00:00

109 lines
1.7 KiB
Text

/-!
Tests that definitions by well-founded recursion (not on Nat) are irreducible.
-/
set_option pp.mvars false
def foo : Nat → Nat → Nat
| 0, m => m
| n+1, m => foo n (m + n)
termination_by n m => (n, m)
/--
error: Type mismatch
rfl
has type
?_ = ?_
but is expected to have type
foo 0 m = m
-/
#guard_msgs in
example : foo 0 m = m := rfl
/--
error: Type mismatch
rfl
has type
?_ = ?_
but is expected to have type
foo (n + 1) m = foo n (m + n)
-/
#guard_msgs in
example : foo (n+1) m = foo n (m + n) := rfl
-- also for closed terms
/--
error: Tactic `rfl` failed: The left-hand side
foo 0 0
is not definitionally equal to the right-hand side
0
⊢ foo 0 0 = 0
-/
#guard_msgs in
example : foo 0 0 = 0 := by rfl
section Unsealed
unseal foo
-- unsealing works, but does not have the desired effect
/--
error: Type mismatch
rfl
has type
?_ = ?_
but is expected to have type
foo 0 0 = 0
-/
#guard_msgs in
example : foo 0 0 = 0 := rfl
/--
error: Type mismatch
rfl
has type
?_ = ?_
but is expected to have type
foo (n + 1) m = foo n (n + m)
-/
#guard_msgs in
example : foo (n+1) m = foo n (n +m ):= rfl
end Unsealed
--should be sealed again here
/--
error: Type mismatch
rfl
has type
?_ = ?_
but is expected to have type
foo 0 m = m
-/
#guard_msgs in
example : foo 0 m = m := rfl
def bar : Nat → Nat → Nat
| 0, m => m
| n+1, m => bar n (m + n)
termination_by n m => (n, m)
-- Once unsealed, the full internals are visible. This allows one to prove, for example
-- an equality like the following
/--
error: Type mismatch
rfl
has type
?_ = ?_
but is expected to have type
foo = bar
-/
#guard_msgs in
example : foo = bar := rfl
unseal foo bar in
example : foo = bar := rfl