问题
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 Stmtin yourStmttype, 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