In A Tutorial on[Co-]Inductive Types in Coq on p. 47, a recursive function is defined, where each recursive step uses a well-formedness proposition to show that the recursion terminates.
A function that is called with x makes a recursive call with x-y where y<>0, so it should terminate.
I am not able to enter it into Coq without getting an error. Coq is complaining that the recursion argument is not smaller in the call, while the tutorial claims that it is so.
What am I missing?
I rewrote the code slightly to make it shorter, but I also tried the verbatim definitions in the paper.
First we show that x-y is accessible from x.
Require Import Omega.
Definition minus_decrease:
forall x y, Acc lt x -> x<>0 -> y<>0 -> Acc lt (x-y).
intros x y H Hx Hy.
case H; intro Ha; apply Ha.
omega.
Qed.
Next, when trying to define the function, like this
Definition div_aux :=
fix div_aux (x y:nat) (H:Acc lt x) {struct H}: nat :=
match eq_nat_dec x 0 with
|left _ => 0
|right _ =>
match eq_nat_dec y 0 with
|left _ => 0
|right v => S (div_aux (x-y) y (minus_decrease x y H _ v))
end
end.
then Coq refuses, saying
Recursive call to div_aux has principal argument equal to
"minus_decrease x y H ?156 v" instead of a subterm of "H".
Notice how div_aux x ... calls itself recursively with div_aux (x-y) ..., and (minus_decrease ...) returns a term of type Acc lt (x-y)
How do I use Acc to show that this function actually terminates?
The error seems to be that I ended the definition with Qed. instead of Defined. The following works.
Require Import Omega.
Definition minus_decrease: forall x y, Acc lt x -> x<>0 -> y<>0 -> Acc lt (x-y).
intros x y H Hx Hy.
case H; intro Ha; apply Ha.
omega.
Defined.
Fixpoint div_aux (x y:nat) (H:Acc lt x) {struct H}: nat.
Proof.
refine (if eq_nat_dec x 0
then 0
else if eq_nat_dec y 0
then y
else S (div_aux (x-y) y _)).
apply (minus_decrease _ _ H _H _H0).
Qed.
Related
I’d like to define the following function using Program Fixpoint or Function in Coq:
Require Import Coq.Lists.List.
Import ListNotations.
Require Import Coq.Program.Wf.
Require Import Recdef.
Inductive Tree := Node : nat -> list Tree -> Tree.
Fixpoint height (t : Tree) : nat :=
match t with
| Node x ts => S (fold_right Nat.max 0 (map height ts))
end.
Program Fixpoint mapTree (f : nat -> nat) (t : Tree) {measure (height t)} : Tree :=
match t with
Node x ts => Node (f x) (map (fun t => mapTree f t) ts)
end.
Next Obligation.
Unfortunately, at this point I have a proof obligation height t < height (Node x ts) without knowing that t is a member of ts.
Similarly with Function instead of Program Fixpoint, only that Function detects the problem and aborts the definition:
Error:
the term fun t : Tree => mapTree f t can not contain a recursive call to mapTree
I would expect to get a proof obligation of In t ts → height t < height (Node x ts).
Is there a way of getting that that does not involve restructuring the function definition? (I know work-arounds that require inlining the definition of map here, for example – I’d like to avoid these.)
Isabelle
To justify that expectation, let me show what happens when I do the same in Isabelle, using the function command, which is (AFAIK) related to Coq’s Function command:
theory Tree imports Main begin
datatype Tree = Node nat "Tree list"
fun height where
"height (Node _ ts) = Suc (foldr max (map height ts) 0)"
function mapTree where
"mapTree f (Node x ts) = Node (f x) (map (λ t. mapTree f t) ts)"
by pat_completeness auto
termination
proof (relation "measure (λ(f,t). height t)")
show "wf (measure (λ(f, t). height t))" by auto
next
fix f :: "nat ⇒ nat" and x :: nat and ts :: "Tree list" and t
assume "t ∈ set ts"
thus "((f, t), (f, Node x ts)) ∈ measure (λ(f, t). height t)"
by (induction ts) auto
qed
In the termination proof, I get the assumption t ∈ set ts.
Note that Isabelle does not require a manual termination proof here, and the following definition works just fine:
fun mapTree where
"mapTree f (Node x ts) = Node (f x) (map (λ t. mapTree f t) ts)"
This works because the map function has a “congruence lemma” of the form
xs = ys ⟹ (⋀x. x ∈ set ys ⟹ f x = g x) ⟹ map f xs = map g ys
that the function command uses to find out that the termination proof only needs to consider t ∈ set ts..
If such a lemma is not available, e.g. because I define
definition "map' = map"
and use that in mapTree, I get the same unprovable proof obligation as in Coq. I can make it work again by declaring a congruence lemma for map', e.g. using
declare map_cong[folded map'_def,fundef_cong]
In this case, you actually do not need well-founded recursion in its full generality:
Require Import Coq.Lists.List.
Set Implicit Arguments.
Inductive tree := Node : nat -> list tree -> tree.
Fixpoint map_tree (f : nat -> nat) (t : tree) : tree :=
match t with
| Node x ts => Node (f x) (map (fun t => map_tree f t) ts)
end.
Coq is able to figure out by itself that recursive calls to map_tree are performed on strict subterms. However, proving anything about this function is difficult, as the induction principle generated for tree is not useful:
tree_ind :
forall P : tree -> Prop,
(forall (n : nat) (l : list tree), P (Node n l)) ->
forall t : tree, P t
This is essentially the same problem you described earlier. Luckily, we can fix the issue by proving our own induction principle with a proof term.
Require Import Coq.Lists.List.
Import ListNotations.
Unset Elimination Schemes.
Inductive tree := Node : nat -> list tree -> tree.
Set Elimination Schemes.
Fixpoint tree_ind
(P : tree -> Prop)
(IH : forall (n : nat) (ts : list tree),
fold_right (fun t => and (P t)) True ts ->
P (Node n ts))
(t : tree) : P t :=
match t with
| Node n ts =>
let fix loop ts :=
match ts return fold_right (fun t' => and (P t')) True ts with
| [] => I
| t' :: ts' => conj (tree_ind P IH t') (loop ts')
end in
IH n ts (loop ts)
end.
Fixpoint map_tree (f : nat -> nat) (t : tree) : tree :=
match t with
| Node x ts => Node (f x) (map (fun t => map_tree f t) ts)
end.
The Unset Elimination Schemes command prevents Coq from generating its default (and not useful) induction principle for tree. The occurrence of fold_right on the induction hypothesis simply expresses that the predicate P holds of every tree t' appearing in ts.
Here is a statement that you can prove using this induction principle:
Lemma map_tree_comp f g t :
map_tree f (map_tree g t) = map_tree (fun n => f (g n)) t.
Proof.
induction t as [n ts IH]; simpl; f_equal.
induction ts as [|t' ts' IHts]; try easy.
simpl in *.
destruct IH as [IHt' IHts'].
specialize (IHts IHts').
now rewrite IHt', <- IHts.
Qed.
You can now do this with Equations and get the right elimination principle automatically, using either structural nested recursion or well-founded recursion
In general, it might be advisable to avoid this problem. But if one really wants to obtain the proof obligation that Isabelle gives you, here is a way:
In Isabelle, we can give an external lemma that stats that map applies its arguments only to members of the given list. In Coq, we cannot do this in an external lemma, but we can do it in the type. So instead of the normal type of map
forall A B, (A -> B) -> list A -> list B
we want the type to say “f is only ever applied to elements of the list:
forall A B (xs : list A), (forall x : A, In x xs -> B) -> list B
(It requires reordering the argument so that the type of f can mention xs).
Writing this function is not trivial, and I found it easier to use a proof script:
Definition map {A B} (xs : list A) (f : forall (x:A), In x xs -> B) : list B.
Proof.
induction xs.
* exact [].
* refine (f a _ :: IHxs _).
- left. reflexivity.
- intros. eapply f. right. eassumption.
Defined.
But you can also write it “by hand”:
Fixpoint map {A B} (xs : list A) : forall (f : forall (x:A), In x xs -> B), list B :=
match xs with
| [] => fun _ => []
| x :: xs => fun f => f x (or_introl eq_refl) :: map xs (fun y h => f y (or_intror h))
end.
In either case, the result is nice: I can use this function in mapTree, i.e.
Program Fixpoint mapTree (f : nat -> nat) (t : Tree) {measure (height t)} : Tree :=
match t with
Node x ts => Node (f x) (map ts (fun t _ => mapTree f t))
end.
Next Obligation.
and I don’t have to do anything with the new argument to f, but it shows up in the the termination proof obligation, as In t ts → height t < height (Node x ts) as desired. So I can prove that and define mapTree:
simpl.
apply Lt.le_lt_n_Sm.
induction ts; inversion_clear H.
- subst. apply PeanoNat.Nat.le_max_l.
- rewrite IHts by assumption.
apply PeanoNat.Nat.le_max_r.
Qed.
It only works with Program Fixpoint, not with Function, unfortunately.
How do you make an anonymous recursive function (something simple for example factorial n?) I have heard it is possible but no idea how to make it work in OCaml.
let a =
fun x -> ....
I just don't know how to keep it going...
Here is a definition of factorial using only anonymous functions:
let fact =
(fun f -> (fun x a -> f (x x) a) (fun x a -> f (x x) a))
(fun f n -> if n < 2 then 1 else n * f (n - 1))
It requires the use of the -rectypes flag.
Here's a session showing that it works:
$ rlwrap ocaml -rectypes
OCaml version 4.03.0
let fact =
(fun f -> (fun x a -> f (x x) a) (fun x a -> f (x x) a))
(fun f n -> if n < 2 then 1 else n * f (n - 1));;
val fact : int -> int = <fun>
# fact 8;;
- : int = 40320
I cheated somewhat by looking up the Y Combinator here: Rosetta Code: Y Combinator
Update
Disclaimer: you would do better to read up on lambda calculus, fixed points, and the Y Combinator than to get your info from me. I'm not a theorist, just a humble practitioner.
Following the actual computation is almost impossible (but definitely worth doing I'm sure). But at a high level the ideas are like this.
The first line of the definition is the Y Combinator, which in general calculates the fixed point of a function. It so happens that a recursive function is the fixed point of a function from functions to functions.
So the first goal is to find the function whose fixed point is the factorial function. That's the second line of the definition. If you give it a function of type int -> int, it gives you back another function of type int -> int. And if you give it the factorial function, it gives you back the factorial function. This means that the factorial function is its fixed point.
So then when you apply the Y Combinator to this function, you do indeed get the factorial function.
Let me try to expand a bit on Jeffrey Scofield's answer. A non-anonymous recursive definition of the factorial function could be
let rec fact n =
if n < 2 then 1 else n * fact (n - 1)
The first problem you encounter when you try to define an anonymous recursive function is how to do the actual recursive call (fact (n - 1) in our case). For a call we need a name and we do not have a name for an anonymous function. The solution is to use a temporary name. With the temporary name f, the definition body is just
fun n -> if n < 2 then 1 else n * f (n - 1)
This term does not have a type, because the "temporary name" f is unbound. But we can turn it into a value that does have a type by bounding f as well. Let us call the result g:
let g = fun f n -> if n < 2 then 1 else n * f (n - 1)
g is not yet anonymous at the moment, but only because I want to refer to it again.
Observe that g has type (int -> int) -> (int -> int). What we want (the factorial function) will have type (int -> int). So g takes something of the type we want (a function type in this case) and produces something of the same type. The intuition is that g takes an approximation of the factorial function, namely a function f which works for all n up to some limit N and returns a better approximation, namely a function that works for all n up to N+1.
Finally we need something that turns g into an actual recursive definition.
Doing so is a very generic task. Recall that g improves the approximation quality. The final factorial function fact is one which cannot be further improved. So applying g to fact should be the same as just fact. (Actually that is only true from a value point of view. The actual computation inherent in g fact n for some n is different from that of just fact n. But the returned values are the same.) In other words, fact is a fixed point of g. So what we need is something that computes fixed points.
Luckily, there is a single function that does so: The Y combinator. From a value point of view, the Y combinator (let us use y in OCaml, as uppercase is reserved for constructors) is defined by the fact that y g = g (y g) for all g: given some function g, the combinator returns one of its fixed points.
Consequently,
y : (`a -> `a) -> `a
In our case the type variable is instantiated by (int -> int).
One possible way to define y would be
let y = fun g -> (fun x -> g (x x)) (fun x -> g (x x))
but this works only with lazy evaluation (as, I believe, Haskell has). As OCaml has eager evaluation, it produces a stack overflow when used. The reason is that OCaml tries to turn something like y g 8 into
g (y g) 8
g (g (y g)) 8
g (g (g (y g))) 8
...
without ever getting to call g.
The solution is to use deferred computation inside of y:
let y = fun g -> (fun x a -> g (x x) a) (fun x a -> g (x x) a)
One drawback is that y does not work for arbitrary types any more. It only works for function types.
y : ((`b -> `c) -> (`b -> `c)) -> (`b -> `c)
But you asked for recursive definitions of functions anyway, not for recursive definitions of other values. So, our definition of the factorial function is y g with y and g defined as above. Neither y nor g are anonymous yet, but that can be remedied easily:
(fun g -> (fun x a -> g (x x) a) (fun x a -> g (x x) a))
(fun f n -> if n < 2 then 1 else n * f (n - 1))
UPDATE:
Defining y only works with the -rectypes option. The reason is that we apply x to itself.
There is also an "intuitive" way to accomplish anonymous recursion without resorting to Y combinators.
It makes use of a let binding to store the value of a lambda that accepts itself as an argument, so that it can call itself with itself as the first parameter, like so:
let fact = (let fact0 = (fun self n -> if n < 2 then 1 else n * self self (n - 1)) in (fun n -> fact0 fact0 n));;
It's anonymous only to the extent that it is not defined with let rec.
I want to prove that computing the cumulative sum between a and b terminates.
I use an Acc lt x term to show that the recursion decreases, like this
Require Import Omega.
Lemma L1 : forall a b, a<b -> (b-(1+a)) < (b-a).
intros; omega. Qed.
Lemma term_lemma: forall a b, Acc lt (b-a) -> Acc lt (b-(1+a)).
intros; inversion H; clear H; constructor; intros; apply H0; omega.
Defined.
Fixpoint cumsum a b (H: Acc lt (b-a)) {struct H} : nat.
refine (
match lt_dec a b with
| left a_lt_b => a + cumsum (1+a) b _
| right a_ge_b => if beq_nat a b then a else 0
end
).
apply (term_lemma _ _ H).
Qed.
It clears all subgoals but it won't typecheck at the Qed statement. Coq complains:
Recursive definition of cumsum is ill-formed
Recursive call to cumsum has principal argument equal to
"term_lemma a b H" instead of a subterm of "H".
I guess I should somehow use L1 to show that the argument in the H term in the recursive call is actually smaller, but how do I do that?
Because you invert H before building something similar-ish back again by using constructor ; apply H0, you get a term_lemma with a pattern matching that's equivalent to what you'd want but confuses Coq's termination checker (You can inspect a term by using Print NAME.).
You don't need to do all of this inversion business if you remember that you already know that a < b thanks to your case analysis on lt_dec a b. By letting your lemma take an extra argument, you can now use the strict subterm of the Accessibility predicate to get your witness:
Require Import Omega.
Lemma term_lemma: forall a b, a < b -> Acc lt (b-a) -> Acc lt (b-(1+a)).
intros a b altb [H]; apply H; omega.
Defined.
Fixpoint cumsum a b (H: Acc lt (b-a)) {struct H} : nat.
refine (
match lt_dec a b with
| left a_lt_b => a + cumsum (1+a) b _
| right a_ge_b => if beq_nat a b then a else 0
end
).
apply (term_lemma _ _ a_lt_b H).
Defined.
From the manual FMapInterface.In is defined as:
Definition In (k:key)(m: t elt) : Prop := exists e:elt, MapsTo k e m.
So, I was expecting that unfolding a term In k m would yield exists e, MapsTo k e m.
However, in Coq 8.4pl4, given this:
______________________________________(1/1)
In (elt:=t) k m
performing an unfold yields
______________________________________(1/1)
Raw.In0 t (this m)
by issuing a Print M (where M is the module in question) I get
Module M
: Sig
.
.
.
End
:= (FMapAVL.Make ID)
My solution is to use lemmas find_mapsto_iff and in_find_iff (from FMapFacts), but that seems overly complicated. Why doesn't unfolding the definition work?
The instance of module FMapInterface (obtained from FMapAVL.Make) changes the definition of In, so this basic property is lost in the instance.
Instead, the result must be proved at the level of FMapInterface. The solution is to create an auxiliary module with these two properties.
Require Coq.FSets.FMapFacts.
Require Coq.FSets.FMapInterface.
Module MapUtil (Import M:FMapInterface.WS).
Module F := FMapFacts.Facts M.
Import F.
Lemma mapsto_to_in:
forall elt k e m,
MapsTo (elt:=elt) k e m ->
In k m.
Proof.
intros.
unfold In.
exists e.
assumption.
Qed.
Lemma in_to_mapsto : forall (elt:Type) m x,
In x m -> exists (e:elt), MapsTo x e m.
Proof.
intros.
unfold In in H.
assumption.
Qed.
End MapUtil.
Using the module above follows the same pattern of using Coq.FSets.FMapFacts. For example:
Require Import Coq.Structures.OrderedTypeEx. (* Imports: Nat_as_OT *)
Require Import Coq.FSets.FMapAVL. (* Imports: FMapAVL.Make *)
Module Map_Nat := FMapAVL.Make Nat_as_OT. (* Defines a map with nats as keys. *)
Module Map_Nat_Util := MapUtil Map_Nat. (* Defines an instance of module MapUtil. *)
Let's suppose that I have
type T
wellfounded relation R: T->T->Prop
function F1: T->T that makes argument "smaller"
condition C: T->Prop that describes "start values" of R
function F2: T->T that makes argument "bigger"
How can I make Fixpoint that looks similar to this:
Fixpoint Example (n:T):X :=
match {C n} + {~C n} with
left _ => ... |
right _ => Example (F1 n)
end.
And how I can make possible the following usage of tactic 'induction' (or similar):
Theorem ...
Proof.
...
induction n F.
(* And now I have two goals:
the first with assumption C n and goal P n,
the second with assumption P n and goal P (F2 n) *)
...
Qed.
I tried to do that with type nz: {n:nat | n<>O} (looking in the chapter 7.1 of Certified Programming with Dependent Types book) but got only this far:
Require Import Omega.
Definition nz: Set := {n:nat | n<>O}.
Theorem nz_t1 (n:nat): S n<>O. Proof. auto. Qed.
Definition nz_eq (n m:nz) := eq (projT1 n) (projT1 m).
Definition nz_one: nz := exist _ 1 (nz_t1 O).
Definition nz_lt (n m:nz) := lt (projT1 n) (projT1 m).
Definition nz_pred (n:nz): nz := exist _ (S (pred (pred (projT1 n)))) (nz_t1 _).
Theorem nz_Acc: forall (n:nz), Acc nz_lt n.
Proof.
intro. destruct n as [n pn], n as [|n]. omega.
induction n; split; intros; destruct y as [y py]; unfold nz_lt in *; simpl in *.
omega.
assert (y<S n\/y=S n). omega. destruct H0.
assert (S n<>O); auto.
assert (nz_lt (exist _ y py) (exist _ (S n) H1)). unfold nz_lt; simpl; assumption.
fold nz_lt in *. apply Acc_inv with (exist (fun n0:nat=>n0<>O) (S n) H1). apply IHn.
unfold nz_lt; simpl; assumption.
rewrite <- H0 in IHn. apply IHn.
Defined.
Theorem nz_lt_wf: well_founded nz_lt. Proof. exact nz_Acc. Qed.
Lemma pred_wf: forall (n m:nz), nz_lt nz_one n -> m = nz_pred n -> nz_lt m n.
Proof.
intros. unfold nz_lt, nz_pred in *. destruct n as [n pn], m as [m pm]. simpl in *.
destruct n, m; try omega. simpl in *. inversion H0. omega.
Defined.
I couldn't understand what happens further because it was too complicated for me.
P.S. As I see it - there isn't any good enough tutorial about general recursion and induction in Coq for beginners. At least I could find. :(
I'll try to write a more complete answer later, but Coq has a command called Function that makes it easier to write functions whose arguments decrease according to some well-ordering. Look for the command on the reference manual (http://coq.inria.fr/distrib/current/refman/Reference-Manual004.html#hevea_command48), specifically the "wf" variant.