合并匹配Coq中的重复个案

时间:2016-05-29 21:03:52

标签: coq coq-tactic

我多次遇到过这个问题:我在Coq中有一个证明状态,包括相等两边的匹配。

有没有一种标准方法可以将多个匹配重写为一个?

例如

match expression_evaling_to_Z with
    Zarith.Z0 => something
    Zartih.Pos _ => something_else
    Zarith.Neg _ => something_else
end = yet_another_thing.

如果我在expresion_evaling_to_Z进行破坏,我会得到两个相同的目标。我想找到一种方法来实现其中一个目标。

3 个答案:

答案 0 :(得分:3)

标准解决方案是使用类型系列定义数据类型的“视图”,该类型系列将在销毁时引入正确的条件和案例。对于您的特定情况,您可以这样做:

Require Import Coq.ZArith.ZArith.

Inductive zero_view_spec : Z -> Type :=
| Z_zero  :                      zero_view_spec Z0
| Z_zeroN : forall z, z <> Z0 -> zero_view_spec z.

Lemma zero_viewP z : zero_view_spec z.
Proof. now destruct z; [constructor|constructor 2|constructor 2]. Qed.

Lemma U z : match z with
              Z0              => 0
            | Zpos _ | Zneg _ => 1
            end = 0.
Proof.
destruct (zero_viewP z).
Abort.

这是一些常见的习惯用法,例如math-comp,它为实例化类型族的z参数提供特殊支持。

答案 1 :(得分:2)

您可以更简洁地编写match表达式:

match expression_evaling_to_Z with
  | Z0 => something
  | Zpos _ | Zneg _ => something_else
end = yet_another_thing.

但是在使用destruct时,这将为您提供3个子目标。

在这种特殊情况下,我们可能会使用您实际需要区分零和非零情况的事实,它看起来像Z.abs_nat : Z -> nat函数的作业。

Require Import Coq.ZArith.BinIntDef.

match Z.abs_nat (expression_evaling_to_Z) with
  | O => something
  | S _ => something_else
end = yet_another_thing.

这将只为您提供两个子类,但您需要在Z.abs_nat (expression_evaling_to_Z)上进行销毁或引入一个新变量。如果您选择第一个变体,那么您可能需要destruct (...) eqn:Heq.将等式放入上下文中。

基本上,这种方法是寻找一种新的数据类型(或定义一种),以及一种适合从旧类型映射到新类型的函数。

答案 2 :(得分:0)

如果您不介意打字,可以使用replace将LHS替换为目标的LHS,这使得解决起来很简单,然后您只需要证明重写确实没问题

Open Scope Z.
Lemma L a b :
  match a + b with
      Z0     => a + b
    | Zpos _ => b + a
    | Zneg _ => b + a
  end = a + b.
  replace (b+a) with (a+b). (* 1. replace the RHS with something trivially true *)
  destruct (a+b); auto.     (* 2. solve the branches in one fell swoop *)
  apply Z.add_comm.         (* 3. solve only once what is required for the two brances *)
Qed.

也许您可以使用一些Ltac-fu或其他引理来手动输入RHS。