Zulip Chat Archive
Stream: new members
Topic: How does Lean know that this terminates?
Kenny Lau (Sep 11 2025 at 10:11):
def foo (m n : Nat) : Int :=
if m < n then foo (m + 1) n else 100
#eval foo 2 5
Kenny Lau (Sep 11 2025 at 10:11):
this works and I don't know how
Robin Arnez (Sep 11 2025 at 10:20):
The termination measure is n - m here. This is the same kind of termination as in:
def foo (i : Nat) (as : Array Nat) : Int :=
if h : i < as.size then
foo (i + 1) as + as[i]
else
100
Kenny Lau (Sep 11 2025 at 10:20):
but how does 1. Lean know to use n-m and 2. Lean see it even though it's not a dependent if?
Kenny Lau (Sep 11 2025 at 10:21):
since it isn't a dependent if it shouldn't even make sense
Aaron Liu (Sep 11 2025 at 10:29):
in the preprocessing step nondependent ifs are converted into dependent ifs
Robin Arnez (Sep 11 2025 at 10:30):
It turns it into a dependent if in the recursion compiler. Also, the module that is responsible for this is Lean.Elab.PreDefinition.WF.GuessLex
Robin Arnez (Sep 11 2025 at 10:30):
Starting with basic measures (
sizeOf xᵢfor all parametersxᵢ), and complex measures (e.g.e₂ - e₁ife₁ < e₂is found in the context of a recursive call) it tries all combinations until it finds one where all proof obligations go through with the given tactic (decerasing_by), if given, or the defaultdecreasing_tactic.
Kenny Lau (Sep 11 2025 at 10:32):
ok on my end i did #print foo and found out the shenanigans involved
Kenny Lau (Sep 11 2025 at 10:32):
def foo (m n : Nat) : Int :=
if m < n then foo (m + 1) n else 100
#eval foo 2 5
#print foo
/-
@[irreducible] def foo : Nat → Nat → Int :=
fun m n => foo._unary n m
-/
#print foo._unary
/-
def foo._unary : Nat → Nat → Int :=
fun n => ⋯.fix fun m a => if h : m < n then a (m + 1) ⋯ else 100
-/
Kenny Lau (Sep 11 2025 at 10:32):
it's always interesting when the #print output isn't at all similar to what I wrote in the code
Last updated: Dec 20 2025 at 21:32 UTC