消除Coq中案例分析生成的冗余子目标

时间:2017-07-23 12:18:13

标签: coq

用简单的定义

Inductive B := bb.
Inductive C := cc.

Inductive A :=
 | mkA1 : B -> A
 | mkA2 : C -> A.

Definition id (a: A) : A :=
 match a with 
  | mkA1 b => mkA1 b 
  | mkA2 c => mkA2 c
end.

我尝试通过案例分析(破坏)来做证明,例如:

Theorem Foo :
  forall  a1 a2 : A , a1 <> a2 -> id a1 <> id a2.
Proof.
 destruct a1; destruct a2.
 Abort.

不出所料,目前的证明状态包含两个相等的子目标:

b: B
c: C
______________________________________(2/4)
mkA1 b <> mkA2 c -> id (mkA1 b) <> id (mkA2 c)
______________________________________(3/4)
mkA2 c <> mkA1 b -> id (mkA2 c) <> id (mkA1 b)

在我看来,在进行结构案例分析时,经常会出现重复的子目标。是否有一些常见的方法来删除这些重复?

我所做的是按下第二个子目标看起来像第三个:

Focus 2; 
intro; apply not_eq_sym in H; apply not_eq_sym; revert H;
Unfocus.

虽然我仍无法让Coq删​​除重复项。现在我可以为我的第二个子目标证明一个引理,并在我的第三个子目标中重复使用它。但我想知道一些替代方案。

1 个答案:

答案 0 :(得分:2)

以下是一些重复使用子目标的策略自动化。请注意,目标不仅必须完全匹配,而且上下文的顺序也必须匹配。在进行案例分析之前,还需要运行初始化策略。这是Coq&gt; = 8.5的代码。

Inductive B := bb.
Inductive C := cc.

Inductive A :=
| mkA1 : B -> A
| mkA2 : C -> A.

Definition id (a: A) : A :=
  match a with
  | mkA1 b => mkA1 b
  | mkA2 c => mkA2 c
  end.

Record duplicate_prod (A B : Type) := duplicate_conj { duplicate_fst : A ; duplicate_snd : B }.
Definition HERE := True.

Ltac start_remove_duplicates H :=
  simple refine (let H___duplicates := @duplicate_conj _ _ I _ in _);
  [ shelve | | ]; cycle 1.
Ltac find_dup H G :=
  lazymatch type of H with
  | duplicate_prod G _ => constr:(@duplicate_fst _ _ H)
  | duplicate_prod _ _ => find_dup (@duplicate_snd _ _ H) G
  end.
Ltac find_end H :=
  lazymatch type of H with
  | duplicate_prod _ _ => find_end (@duplicate_snd _ _ H)
  | _ => H
  end.
Ltac revert_until H :=
  repeat lazymatch goal with
         | [ H' : _ |- _ ]
           => first [ constr_eq H H'; fail 1
                    | revert H' ]
         end.
Ltac remove_duplicates :=
  [ > lazymatch goal with
      | [ |- duplicate_prod _ _ ] => idtac
      | [ H : duplicate_prod _ _ |- _ ]
        => generalize (I : HERE);
           revert_until H;
           let G := match goal with |- ?G => G end in
           lazymatch type of H with
           | context[duplicate_prod G]
             => let lem := find_dup H G in exact lem
           | _ => let lem := find_end H in
                  refine (@duplicate_fst _ _ lem); clear H; (* clear to work around a bug in Coq *)
                  shelve
           end
      end.. ].
Ltac finish_duplicates :=
  [ > lazymatch goal with
      | [ H : duplicate_prod _ _ |- _ ] => clear H
      end..
  | repeat match goal with
           | [ |- duplicate_prod _ ?e ]
             => split;
                [ repeat lazymatch goal with
                         | [ |- HERE -> _ ] => fail
                         | _ => intro
                         end;
                  intros _
                | try (is_evar e; exact I) ]
           end ].


Theorem Foo :
  forall  a1 a2 : A , a1 <> a2 -> id a1 <> id a2.
Proof.
  start_remove_duplicates.
  destruct a1; destruct a2.
  2:intro; apply not_eq_sym in H; apply not_eq_sym; revert c b H; intros c b.
  all:remove_duplicates.
  all:finish_duplicates.

这个想法是你首先要创造一个能够解决独特目标的问题。然后你做案例分析。然后你完成目标,并用evar的新投影解决它们,或者,如果你发现已经找到了你正在寻找的目标的解决方案,你可以使用该解决方案。最后,您将evar分成多个(重复数据删除)目标。还有一些额外的样板可以恢复在创建evar时不存在的假设(需要为良好类型的术语安排变量作用域),记住最初来自上下文的内容,并在最后将这些内容重新引入上下文