module public axiom P : Nat → Prop public axiom P.intro : P n public inductive AckFuel : (n m : Nat) → Type where | step1 : AckFuel 0 m | step2 : AckFuel n 1 → AckFuel (n + 1) 0 | step3 : (∀ m', P m' → AckFuel n m') → AckFuel (n + 1) m → AckFuel (n+1) (m + 1) namespace Test1 /-- info: Try this: [apply] termination_by structural x _ x => x -/ #guard_msgs in public def ackermann_fuel : (n m : Nat) → (fuel : AckFuel n m) → Nat | 0, m, .step1 => m+1 | n + 1, 0, .step2 f => ackermann_fuel n 1 f | n + 1, m + 1, .step3 f1 f2 => ackermann_fuel n (ackermann_fuel (n + 1) m f2) (f1 _ (by exact P.intro)) termination_by? end Test1 namespace Test2 /-- info: Try this: [apply] termination_by structural x _ x => x -/ #guard_msgs in public def ackermann_fuel : (n m : Nat) → (fuel : AckFuel n m) → Nat | 0, m, .step1 => m+1 | n + 1, 0, .step2 f => ackermann_fuel n 1 f | n + 1, m + 1, .step3 f1 f2 => ackermann_fuel n (ackermann_fuel (n + 1) m f2) (f1 _ (by as_aux_lemma => exact P.intro)) termination_by? end Test2 namespace Test3 /-- info: Try this: [apply] termination_by structural x _ x => x -/ #guard_msgs in @[expose] public def ackermann_fuel : (n m : Nat) → (fuel : AckFuel n m) → Nat | 0, m, .step1 => m+1 | n + 1, 0, .step2 f => ackermann_fuel n 1 f | n + 1, m + 1, .step3 f1 f2 => ackermann_fuel n (ackermann_fuel (n + 1) m f2) (f1 _ (by exact P.intro)) termination_by? end Test3 namespace Test4 -- This checks that when unfolding abstracted proofs, we do not unfold function calls -- that were actually there, like the one to `Function.cons` below /-- error: failed to infer structural recursion: Cannot use parameter #3: unexpected occurrence of recursive application ackermann_fuel -/ #guard_msgs in public def ackermann_fuel : (n m : Nat) → (fuel : AckFuel n m) → Nat | 0, m, .step1 => m+1 | n + 1, 0, .step2 f => ackermann_fuel n 1 f | n + 1, m + 1, .step3 f1 f2 => Function.const _ ( ackermann_fuel n (ackermann_fuel (n + 1) m f2) (f1 _ (by exact P.intro)) ) ackermann_fuel termination_by structural _ _ fuel => fuel end Test4