Zulip Chat Archive
Stream: lean4
Topic: Proving termination for mutually recursive functions.
Alex Zani (Mar 28 2025 at 06:14):
So I'm working on a little parser combinator and I'm having a hard time proving termination. When I look at the acceptTermNoApp function, the only assumption it gives me is (state : State). And simp_wf
gives me |- False
, which is less than ideal. How would I go about proving termination?
(Sorry for the long example, I tried my best to condense.)
structure State where
src : List Char
inductive Result
| ok (state : State)
| fail
| fatal
def State.acceptNext : State → Result
| {src := []} => Result.fail
| {src := (_ :: cs)} => Result.ok {src := cs}
def State.acceptChar : Char → State → Result
| t, {src := (c :: cs)} => if t == c
then Result.ok {src := cs}
else Result.fail
| _, _ => Result.fail
def State.acceptVar (state : State) : Result :=
match state.acceptNext with
| Result.ok state' => Result.ok state'
| other => other
mutual
def State.acceptTermNoApp (state : State) : Result :=
match state.acceptAbstraction with
| Result.fail => state.acceptVar
| other => other
termination_by state
def State.acceptTerm (state : State) : Result :=
match state.acceptApplication with
| Result.fail => state.acceptTermNoApp
| other => other
termination_by state
def State.acceptAbstraction (state : State) : Result :=
match state.acceptChar 'λ' with
| Result.ok state' => state'.acceptTerm
| Result.fail => Result.fatal -- Expected to see a body after a lambda
| Result.fatal => Result.fatal
termination_by state
def State.acceptApplication (state : State) : Result :=
match state.acceptTermNoApp with
| Result.ok state' => state.acceptTerm
| other => other
termination_by state
end
Robin Arnez (Mar 28 2025 at 17:44):
Simplest way is just to not prove termination, i.e. put partial
in front of everything in the mutual block. Note: partial
causes the functions to work as expected at runtime but not requiring termination by making them opaque for proofs. As long as you don't need proofs, this should be fine though.
Aaron Liu (Mar 28 2025 at 19:38):
Problem: it doesn't terminate? acceptTerm
and acceptApplication
can call each other forever.
Alex Zani (Mar 28 2025 at 20:03):
Aaron Liu said:
Problem: it doesn't terminate?
acceptTerm
andacceptApplication
can call each other forever.
I don't think that's correct. acceptApplication will only call acceptTerm if acceptTermNoApp has made progress.
Aaron Liu (Mar 28 2025 at 20:08):
Alex Zani said:
Aaron Liu said:
Problem: it doesn't terminate?
acceptTerm
andacceptApplication
can call each other forever.I don't think that's correct. acceptApplication will only call acceptTerm if acceptTermNoApp has made progress.
Suppose:
acceptTerm
is called
it calls
acceptApplication
to compute thematch
it calls
acceptTermNoApp
, which computesok
and the result is discarded
it callsacceptTerm
loop
Last updated: May 02 2025 at 03:31 UTC