如何使Coq评估特定的重新索引(或 - 为什么在这种情况下拒绝?)

时间:2014-12-08 09:35:48

标签: recursion coq

当我试图证明一个关于递归函数的定理时(见下文),我最终得到了一个可简化的表达式

(fix picksome L H := match A with .... end) L1 H1 = RHS

我想扩展match表达式,但Coq拒绝。做simpl只是将右侧扩展为难以理解的混乱。为什么Coq无法用simpl; reflexivity完成证明,如何指示Coq精确扩展redex,并完成证明?

该函数是一个递归函数pick,它取list nat并取第一个nat调用a,从列表中删除以下a项,并在剩余的清单上进行递归。即

pick [2;3;4;0;1;3])=[2; 0; 1]

我试图证明的定理是,在仅包含零的列表中,函数“不执行任何操作”。以下是导致问题的发展:

Require Import Arith.
Require Import List.
Import ListNotations.

Fixpoint drop {T} n (l:list T) :=
  match n,l with
    | S n', cons _ l' => drop n' l'
    | O, _ => l
    | _, _ => nil
  end.

第一个引理:

Lemma drop_lemma_le : forall {T} n (l:list T), length (drop n l) <= (length l).
Proof.
  intros; generalize n; induction l; intros; destruct n0; try reflexivity;
  apply le_S; apply IHl.
Defined.

第二个引理:

Lemma picksome_term: forall l l' (a :nat),
       l = a::l' -> Acc lt (length l) ->  Acc lt (length (drop a l')).
Proof.
  intros; apply H0; rewrite H; simpl; apply le_lt_n_Sm; apply drop_lemma_le.
Defined.

更多定义:

Fixpoint picksome (l:list nat) (H : Acc lt (length l)) {struct H}: list nat :=
  match l as m return l=m -> _ with
    | nil       => fun _  => nil
    | cons a l' => fun Hl =>
                     cons a (picksome (drop a l')
                                      (picksome_term _ _ _ Hl H))
  end
    (eq_refl _).

Definition pick (l:list nat) : list nat := picksome l (lt_wf (length l)).

Inductive zerolist : list nat -> Prop :=
| znil : zerolist nil
| hzlist : forall l, zerolist l -> zerolist (O::l).

现在,如果我们有引理H

,我们可以证明我们的定理
Theorem pickzero': (forall k, pick (0::k) = 0::pick k) ->
                forall l, zerolist l -> pick l = l.
Proof.
  intros H l H0; induction H0; [ | rewrite H; rewrite IHzerolist]; reflexivity.
Qed.

(* but trying to prove the lemma *)
Lemma pickzero_lemma : forall k, pick (0::k) = 0::pick k.
  induction k; try reflexivity.
  unfold pick at 1.
  unfold picksome.

这是目标和背景:

a : nat
k : list nat
IHk : pick (0 :: k) = 0 :: pick k
============================
 (fix picksome (l : list nat) (H : Acc lt (length l)) {struct H} :
    list nat :=
    match l as m return (l = m -> list nat) with
    | [] => fun _ : l = [] => []
    | a0 :: l' =>
        fun Hl : l = a0 :: l' =>
        a0 :: picksome (drop a0 l') (picksome_term l l' a0 Hl H)
    end eq_refl) (0 :: a :: k) (lt_wf (length (0 :: a :: k))) =
 0 :: pick (a :: k)

2 个答案:

答案 0 :(得分:3)

关于fixpoint的Coq减少规则非常简单:当且仅当修复点应用于&#34;构建的&#34;时,才能展开修复点的一步。术语。例如,length (1 :: nil)会减少,但在上下文中l = 1 :: nillength l不会减少。您必须使用构造的术语l明确替换1 :: nil才能使缩减能够追加。

在您的目标中,picksomeH上的结构递归定义,即可访问性证明。如果你尝试simpl,实际上会发生缩减,并且当这个参数不再被构造时会停止&#34;#34;。在您的特定情况下,在simpl之后您最终得到(fix picksome ...) (drop a1 l'0) (nat_ind <big term>)证明,并且Coq不能再减少picksome

编辑:为了完成你的证明,我首先尝试证明:

Lemma picksome_unfold : 
  forall (hd:nat) (tl:list nat) (H:Acc lt (length (hd::tl))), picksome (hd::tl) H = 
    cons hd (picksome (drop hd tl) (picksome_term (hd::tl) tl hd (eq_refl (hd::tl)) H)).

(如果你破坏H,这很容易)。但是,为了完成pickzero_lemma引理,我需要证明可访问性证明的相等性,这可能需要证明不相关。我不确定,抱歉。

答案 1 :(得分:2)

@Vinz解释了为什么Coq没有使用fix减少beta-redex的原因。以下是CDPT的相关摘录:

  

一个候选规则会说我们尽可能应用递归定义。然而,这显然会导致无终止的减少序列,因为该函数可能看起来完全应用于其自己的定义中,并且我们将天真地简化&#34;这样的申请立即。相反,当递归参数的顶级结构已知时,Coq仅对递归函数应用beta规则。

我只想补充说,引理可以在不假设其他公理的情况下得到证明 - 简单的推广就足够了。

让我们首先为列表定义新的归纳原则:

Definition lt_list {A} (xs ys : list A) := length xs < length ys.

Definition lt_list_wf {A : Type} : well_founded (@lt_list A) :=
  well_founded_ltof (list A) (@length A).

Lemma lt_list_wf_ind {A} (P : list A -> Prop) :
  (forall ys, (forall xs, length xs < length ys -> P xs) -> P ys) ->
  forall l, P l.
Proof. intros ? l; elim (lt_list_wf l); auto with arith. Qed.

基本上,lt_list_wf_ind归纳原则表明,如果我们可以证明P的谓词ys适用于P,假设P适用于所有较小的列表长度,然后我们为所有列表picksome

现在,让我们来证明一个表达与Lemma picksome_helper l : forall acc acc', picksome l acc = picksome l acc'. Proof. induction l as [l IH] using lt_list_wf_ind; intros acc acc'. destruct l; destruct acc, acc'; [trivial |]. simpl. f_equal. apply IH. simpl; rewrite Nat.lt_succ_r. apply drop_lemma_le. Qed. 的可访问性参数无关的证明:

Acc

使用pick_zero的证明无关的本地版本,我们现在可以证明Lemma pick_zero k : pick (0::k) = 0::pick k. Proof. unfold pick. destruct (lt_wf (length (0 :: k))). simpl (picksome (0 :: k) _). f_equal. apply picksome_helper. Qed. 引理:

<output>
            <mime:multipartRelated>
                <mime:part>
                    <soap:body parts="" use="literal" />
                </mime:part>
                <mime:part>
                    <mime:content part="parameters" type="text/xml" />
                </mime:part>
            </mime:multipartRelated>
        </output>