我多次遇到过这个问题:我在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
进行破坏,我会得到两个相同的目标。我想找到一种方法来实现其中一个目标。
答案 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。