coq-club AT inria.fr
Subject: The Coq mailing list
List archive
- From: Jason Gross <jasongross9 AT gmail.com>
- To: coq-club AT inria.fr
- Subject: Re: [Coq-Club] pattern match not reducing
- Date: Wed, 26 Oct 2016 13:43:35 +0000
- Authentication-results: mail2-smtp-roc.national.inria.fr; spf=None smtp.pra=jasongross9 AT gmail.com; spf=Pass smtp.mailfrom=jasongross9 AT gmail.com; spf=None smtp.helo=postmaster AT mail-qk0-f181.google.com
- Ironport-phdr: 9a23:WxDPChTc1RZ2Z16L0BQjo352y9psv+yvbD5Q0YIujvd0So/mwa67YxWN2/xhgRfzUJnB7Loc0qyN4vqmBz1Lv83J8ChbNscTB1ld0YRetjdjKfDGIHWzFOTtYS0+EZYKf35e1Fb/D3JoHt3jbUbZuHy44G1aMBz+MQ1oOra9QdaK3Izkn9y1rpbUekBDgCe3SbJ0NhS/6wvL5ecMho43CK8qzR2BjWFPYP8ekWFhPlWVkAz7/dzh1JFm+iVU/fkm8pgTAu3BY60kQOkAX3wdOGcv6ZizuA==
The shortish version (I'll let someone else fill in the details):
1. The guard condition changed from 8.4 to 8.5, to eliminate the inconsistency with propositional extensionality (in early enough versions of 8.4, you can prove [(forall P Q : Prop, (P <-> Q) -> P = Q) -> False], which is bad)
2. To get Coq v8.5 to accept {struct pt1}, pass [merge_partial_tuple pt1_tail] into your inner match statement, rather than passing in [pt1_tail] (that is, note that you apply [merge_partial_tuple] to [pt1_tail'] in both branches of the match inner, and do common subexpression elimination to bring the application out of the inner match)
3. Coq will only reduce applications of fixpoints that have a constructor in their structural position. Suppose it did otherwise, and consider the following function:
Fixpoint id (n : nat) : nat :=
match n with
| 0 => 0
| S n' => S (id n')
end.
What is the normal form of [fun n => id n]? If Coq can unfold (well, beta-reduce) fixpoints applied to variables, then this term would have an infinite normal form!
4. There is a way to fix your proof with the new definition. The most systematic way to do this is to write a lemma that lets you reduce your fixpoint a single step: prove that your fixpoint is equal to it's body by destructing pt2, and then rewrite with that lemma in the theorem you're trying to prove.
-Jason
Hi everybody,
I have a problem with updating a dependently typed function from
8.4 to 8.5 (see the source below). In 8.4, coq accepts the
definition of merge_partial_tuple with {struct pt1} and the proof
of the little lemma is very simple.
In 8.5, {struct pt1} is rejected, coq does not see anymore that
pt1_tail' and pt1_tail are identical.
First question: Is this an intended change?
However, in 8.5 the definition is accepted with {struct pt2}. For
this, I would say, coq has to infer that pt2 and pt2' are
identical, which does not seem to be a problem.
I don't care too much about the decreasing argument. My problem
is that with {struct pt2} the term
merge_partial_tuple (counted_nil _) something
is not convertible to (counted_nil _). (This behavior is the same
in 8.4 and 8.5.) I would be grateful if somebody could tell me
why coq does not use the obvious first case in the pattern match
to reduce the term. Indeed,
change (merge_partial_tuple (counted_nil (option nat)) pt) with
(counted_nil (option nat)).
fails with "Not convertible.", which I really don't understand.
Thanks in advance,
Hendrik
==================== 8.4 version ==============================================
Section Counted_list.
Variable A : Type.
Inductive counted_list : nat -> Type := (* lists of fixed length *)
| counted_nil : counted_list 0
| counted_cons : forall(n : nat),
A -> counted_list n -> counted_list (S n).
End Counted_list.
Definition partial_tuple(n : nat) : Type := counted_list (option nat) n.
(* this function should do
[Some 0; Some 1; None] [None, Some 2; None] => [Some 0; Some 1; None]
*)
Fixpoint merge_partial_tuple{l : nat}(pt1 pt2 : partial_tuple l)
{struct pt1} : partial_tuple l :=
match pt1 in counted_list _ l1
return partial_tuple l1 -> partial_tuple l1
with
| counted_nil => fun _ => counted_nil _
| counted_cons pl1 no1 pt1_tail => fun(pt2' : partial_tuple (S pl1)) =>
match pt2' in counted_list _ l2
return match l2 with
| 0 => nat (* impossible case *)
| S pl2 => partial_tuple pl2 -> partial_tuple (S pl2)
end
with
| counted_nil => 0 (* impossible case *)
| counted_cons _ no2 pt2_tail => fun pt1_tail' =>
match no1 with
| Some n1 => counted_cons _ _ (Some n1)
(merge_partial_tuple pt1_tail' pt2_tail)
| None => match no2 with
| Some n2 => counted_cons _ _ (Some n2)
(merge_partial_tuple pt1_tail' pt2_tail)
| None => counted_cons _ _ None
(merge_partial_tuple pt1_tail' pt2_tail)
end
end
end pt1_tail
end pt2.
Lemma merge_partial_tuple_nil :
forall(pt : partial_tuple 0),
merge_partial_tuple (counted_nil _) pt = (counted_nil _).
Proof.
intros pt.
simpl.
reflexivity.
Qed.
==================== end 8.4 version ===========================================
======================= 8.5 version of merge_partial_tuple =====================
Fixpoint merge_partial_tuple{l : nat}(pt1 pt2 : partial_tuple l)
{struct pt2} : partial_tuple l :=
match pt1 in counted_list _ l1
return partial_tuple l1 -> partial_tuple l1
with
| counted_nil _ => fun _ => counted_nil _
| counted_cons _ pl1 no1 pt1_tail => fun(pt2' : partial_tuple (S pl1)) =>
match pt2' in counted_list _ l2
return match l2 with
| 0 => nat (* impossible case *)
| S pl2 => partial_tuple pl2 -> partial_tuple (S pl2)
end
with
| counted_nil _ => 0 (* impossible case *)
| counted_cons _ _ no2 pt2_tail => fun pt1_tail' =>
match no1 with
| Some n1 => counted_cons _ _ (Some n1)
(merge_partial_tuple pt1_tail' pt2_tail)
| None => match no2 with
| Some n2 => counted_cons _ _ (Some n2)
(merge_partial_tuple pt1_tail' pt2_tail)
| None => counted_cons _ _ None
(merge_partial_tuple pt1_tail' pt2_tail)
end
end
end pt1_tail
end pt2.
======================= end ====================================================
- [Coq-Club] pattern match not reducing, Hendrik Tews, 10/26/2016
- Re: [Coq-Club] pattern match not reducing, Jason Gross, 10/26/2016
Archive powered by MHonArc 2.6.18.