Zulip Chat Archive
Stream: new members
Topic: Termination of mutual recursive definition
bruno cuconato (Sep 29 2022 at 23:53):
Hi, I've been toying with an implementation in Lean 4 (commit ded7216a12cb) of primitive recursive functions, following this Agda version. When implementing the evaluator (whose termination Agda seems to be able to prove), Lean says structural recursion does not handle mutually recursive functions
, and that I should use termination_by
to show it terminates.
inductive PRF : Nat → Type where
| zero : PRF 0
| succ : PRF 1
| proj : {n : Nat} → Fin n → PRF n -- projection
| comp : {m k : Nat} → PRF m → (Fin m → PRF k) → PRF k -- composition
| primrec : {n : Nat} → PRF n → PRF (n + 2) → PRF (n + 1) -- primitive recursion
def evaluate (f : PRF a) (arg : Fin a → Nat) : Nat :=
match f with
| PRF.zero => 0
| PRF.succ => arg 0 + 1
| PRF.proj i => arg i
| PRF.comp g hs => evaluate g (λ i => evaluate (hs i) arg)
| PRF.primrec g h =>
let rec primrec : Nat → Nat
| 0 =>
evaluate
g
(λ {val := i, isLt := i_lt_n} =>
arg {val := i + 1, isLt := Nat.succ_le_succ i_lt_n})
| n + 1 =>
evaluate
h
(λ fini =>
match fini with
| {val := 0, isLt := _} => primrec n
| {val := 1, isLt := _} => n
| {val := i + 2, isLt} => arg {val := i + 1, isLt := Nat.pred_le_pred isLt})
primrec (arg 0)
- Are there any plans for Lean 4 to support the automatic termination check of mutually recursive function by structural recursion?
- How do I prove this terminates? I have tried looking for examples using
termination_by
ordecreasing_by
on Lean std library, but nothing seems very enlightening to me…
Mario Carneiro (Sep 30 2022 at 00:53):
The easiest way is to make the inner function not mutually recursive with the outer one, by extracting evaluate g
and evaluate h
out of the inner function:
def evaluate (f : PRF a) (arg : Fin a → Nat) : Nat :=
match f with
| PRF.zero => 0
| PRF.succ => arg 0 + 1
| PRF.proj i => arg i
| PRF.comp g hs => evaluate g fun i => evaluate (hs i) arg
| PRF.primrec g h =>
let IHg := evaluate g
let IHh := evaluate h
let rec primrec : Nat → Nat
| 0 => IHg fun ⟨i, i_lt_n⟩ => arg ⟨i + 1, Nat.succ_le_succ i_lt_n⟩
| n + 1 => IHh fun
| ⟨0, _⟩ => primrec n
| ⟨1, _⟩ => n
| ⟨i + 2, isLt⟩ => arg ⟨i + 1, Nat.pred_le_pred isLt⟩
primrec (arg 0)
bruno cuconato (Sep 30 2022 at 01:16):
That was simpler than I thought I'd be, thank you @Mario Carneiro !
Last updated: Dec 20 2023 at 11:08 UTC