问题
How can I prove termination for size_prgm
? I tried, but can't come up with a well founded relation to pass to Fix
.
Inductive Stmt : Set :=
| assign: Stmt
| if': (list Stmt) -> (list Stmt) -> Stmt.
Fixpoint size_prgm (p: list Stmt) : nat :=
match p with
| nil => 0
| s::t => size_prgm t +
match s with
| assign => 1
| if' b0 b1 => S (size_prgm b0 + size_prgm b1)
end
end.
回答1:
The termination oracle is quite better than what it used to be. Defining a function sum_with
using fold_left
and feeding it the recursive call to size_prgm
works perfectly well.
Require Import List.
Inductive Stmt : Set :=
| assign: Stmt
| if': (list Stmt) -> (list Stmt) -> Stmt.
Definition sum_with {A : Type} (f : A -> nat) (xs : list A) : nat :=
fold_left (fun n a => n + f a) xs 0.
Fixpoint size_prgm (p: Stmt) : nat :=
match p with
| assign => 1
| if' b0 b1 => sum_with size_prgm b1 + sum_with size_prgm b0
end.
回答2:
Short answer, since I don't have much time right now (I'll try to get back to you later): this is a really usual (and silly) problem that every Coq user has to experience one day.
If I recall correctly, there is two "general" solutions to this problem and lots of very specific ones. For the two former:
- build a inner fixpoint: I don't really remember how to do this properly.
use a mutual recursive type: The issue with your code is that you use
list Stmt
in yourStmt
type, and Coq is not able to compute the induction principle you have in mind. But you could use a time likeInductive Stmt : Set := | assign : Stmt | if': list_Stmt -> list_Stmt -> Stmt with list_Stmt : Set := | Nil_Stmt : list_Stmt | Cons_Stmt : Stmt -> list_Stmt -> list_Stmt.
Now write your function over this type and a bijection between this type and your original Stmt
type.
You can try to browse the Coq-Club mailing list, this kind of topic is a recurring one.
Hope it helps a bit, V
来源:https://stackoverflow.com/questions/19507311/proving-termination-in-coq