This adds support for mutual structural recursive functions. For now this is opt-in: The functions must have a `termination_by structural …` annotation (new since #4542) for this to work: ```lean mutual inductive A | self : A → A | other : B → A | empty inductive B | self : B → B | other : A → B | empty end mutual def A.size : A → Nat | .self a => a.size + 1 | .other b => b.size + 1 | .empty => 0 termination_by structural x => x def B.size : B → Nat | .self b => b.size + 1 | .other a => a.size + 1 | .empty => 0 termination_by structural x => x end ``` The recursive functions don’t have to be in a one-to-one relation to a set of mutually recursive inductive data types. It is possible to ignore some of the types: ```lean def A.self_size : A → Nat | .self a => a.self_size + 1 | .other _ => 0 | .empty => 0 termination_by structural x => x ``` or have more than one function per argument type: ```lean def isEven : Nat → Prop | 0 => True | n+1 => ¬ isOdd n termination_by structural x => x def isOdd : Nat → Prop | 0 => False | n+1 => ¬ isEven n termination_by structural x => x ``` This does not include * Support for nested inductive data types or nested recursion * Inferring mutual structural recursion in the absence of `termination_by`. * Functional induction principles for these. * Mutually recursive functions that live in different universes. This may be possible, maybe after beefing up the `.below` and `.brecOn` functions; we can look into this some other time, maybe when there are concrete use cases. --------- Co-authored-by: Richard Kiss <him@richardkiss.com> Co-authored-by: Tobias Grosser <tobias@grosser.es>
23 lines
2.2 KiB
Text
23 lines
2.2 KiB
Text
termination_by.lean:9:2-9:18: error: unused `termination_by`, function is not recursive
|
|
termination_by.lean:12:2-12:21: error: unused `decreasing_by`, function is not recursive
|
|
termination_by.lean:15:2-16:21: error: unused termination hints, function is not recursive
|
|
termination_by.lean:19:2-19:18: error: unused `termination_by`, function is partial
|
|
termination_by.lean:22:2-22:21: error: unused `decreasing_by`, function is partial
|
|
termination_by.lean:25:2-26:21: error: unused termination hints, function is partial
|
|
termination_by.lean:29:0-29:16: error: unused `termination_by`, function is unsafe
|
|
termination_by.lean:32:2-32:21: error: unused `decreasing_by`, function is unsafe
|
|
termination_by.lean:35:2-36:21: error: unused termination hints, function is unsafe
|
|
termination_by.lean:40:4-40:20: error: unused `termination_by`, function is not recursive
|
|
termination_by.lean:44:4-44:20: error: unused `termination_by`, function is not recursive
|
|
termination_by.lean:54:2-54:18: error: unused `termination_by`, function is not recursive
|
|
termination_by.lean:62:2-62:23: error: Incomplete set of `termination_by` annotations:
|
|
This function is mutually with isOdd, which does not have a `termination_by` clause.
|
|
The present clause is ignored.
|
|
Try this: termination_by x1 => x1
|
|
termination_by.lean:79:2-79:27: error: Incomplete set of `termination_by` annotations:
|
|
This function is mutually with Test.f, Test.h and Test.i, which do not have a `termination_by` clause.
|
|
The present clause is ignored.
|
|
termination_by.lean:101:2-101:27: error: Invalid `termination_by`; this function is mutually recursive with Test2.f, which is marked as `termination_by structural` so this one also needs to be marked `structural`.
|
|
termination_by.lean:120:2-120:38: error: Invalid `termination_by`; this function is mutually recursive with Test3.f, which is not marked as `structural` so this one cannot be `structural` either.
|
|
termination_by.lean:144:2-144:38: error: Invalid `termination_by`; this function is mutually recursive with Test4.f, which is not marked as `structural` so this one cannot be `structural` either.
|
|
termination_by.lean:159:2-159:21: error: Invalid `decreasing_by`; this function is marked as structurally recursive, so no explicit termination proof is needed.
|