This PR adds the ability to define possibly non-terminating functions
and still be able to reason about them equationally, as long as they are
tail-recursive or monadic.
Typical uses of this feature are
```lean4
def ack : (n m : Nat) → Option Nat
| 0, y => some (y+1)
| x+1, 0 => ack x 1
| x+1, y+1 => do ack x (← ack (x+1) y)
partial_fixpiont
def whileSome (f : α → Option α) (x : α) : α :=
match f x with
| none => x
| some x' => whileSome f x'
partial_fixpiont
def computeLfp {α : Type u} [DecidableEq α] (f : α → α) (x : α) : α :=
let next := f x
if x ≠ next then
computeLfp f next
else
x
partial_fixpiont
noncomputable def geom : Distr Nat := do
let head ← coin
if head then
return 0
else
let n ← geom
return (n + 1)
partial_fixpiont
```
This PR contains
* The necessary fragment of domain theory, up to (a variant of)
Knaster–Tarski theorem (merged as
https://github.com/leanprover/lean4/pull/6477)
* A tactic to solve monotonicity goals compositionally (a bit like
mathlib’s `fun_prop`) (merged as
https://github.com/leanprover/lean4/pull/6506)
* An attribute to extend that tactic (merged as
https://github.com/leanprover/lean4/pull/6506)
* A “derecursifier” that uses that machinery to define recursive
function, including support for dependent functions and mutual
recursion.
* Fixed-point induction principles (technical, tedious to use)
* For `Option`-valued functions: Partial correctness induction theorems
that hide all the domain theory
This is heavily inspired by [Isabelle’s `partial_function`
command](https://isabelle.in.tum.de/doc/codegen.pdf).
23 lines
2.3 KiB
Text
23 lines
2.3 KiB
Text
termination_by.lean:9:2-9:18: warning: unused `termination_by`, function is not recursive
|
|
termination_by.lean:12:2-12:21: warning: unused `decreasing_by`, function is not recursive
|
|
termination_by.lean:15:2-16:21: warning: unused termination hints, function is not recursive
|
|
termination_by.lean:19:2-19:18: warning: unused `termination_by`, function is partial
|
|
termination_by.lean:22:2-22:21: warning: unused `decreasing_by`, function is partial
|
|
termination_by.lean:25:2-26:21: warning: unused termination hints, function is partial
|
|
termination_by.lean:29:0-29:16: warning: unused `termination_by`, function is unsafe
|
|
termination_by.lean:32:2-32:21: warning: unused `decreasing_by`, function is unsafe
|
|
termination_by.lean:35:2-36:21: warning: unused termination hints, function is unsafe
|
|
termination_by.lean:40:4-40:20: warning: unused `termination_by`, function is not recursive
|
|
termination_by.lean:44:4-44:20: warning: unused `termination_by`, function is not recursive
|
|
termination_by.lean:54:2-54:18: warning: 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 recursive 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 recursive 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.
|