考虑以下发展:
Require Import Relation RelationClasses.
Set Implicit Arguments.
CoInductive stream (A : Type) : Type :=
| scons : A -> stream A -> stream A.
CoInductive stream_le (A : Type) {eqA R : relation A}
`{PO : PartialOrder A eqA R} :
stream A -> stream A -> Prop :=
| le_step : forall h1 h2 t1 t2, R h1 h2 ->
(eqA h1 h2 -> stream_le t1 t2) ->
stream_le (scons h1 t1) (scons h2 t2).
如果我有一个假设stream_le (scons h1 t1) (scons h2 t2)
,destruct
策略将其转换为一对假设R h1 h2
和eqA h1 h2 -> stream_le t1 t2
是合理的。但事实并非如此,因为destruct
在做任何非平凡的事情时都会丢失信息。相反,新条款h0
,h3
,t0
,t3
会被引入上下文,而不会回想它们分别等于h1
,{{ 1}},h2
,t1
。
我想知道是否有一种快速简便的方法来做这种"智能t2
"。这就是我现在所拥有的:
destruct
答案 0 :(得分:5)
事实上,inversion
基本上可以做你想要的,但亚瑟指出它有点不稳定,主要是由于不同的同步步骤。
在幕后,inversion
只调用destruct
的版本,但首先要记住一些平等。正如你已经发现的那样,Coq中的模式匹配将会忘记"构造函数的参数,除非这些是变量,否则,destruct范围下的所有变量都将被实例化。
这是什么意思?这意味着,为了正确破坏归纳I : Idx -> Prop
,您希望获得表单的目标:I x -> Q x
,以便破坏I x
也会优化x
在Q
。因此,归纳I term
和目标Q (f term)
的标准转换是将其重写为I x -> x = term -> Q (f x)
。然后,破坏I x
将使x
实例化为正确的索引。
考虑到这一点,使用Coq 8.7的case:
策略手动实现反演可能是一个很好的练习;
From Coq Require Import ssreflect.
Theorem stream_le_destruct A eqA R `{PO : PartialOrder A eqA R} (h1 h2 : A) (t1 t2 : stream A) :
stream_le (scons h1 t1) (scons h2 t2) ->
R h1 h2 /\ (eqA h1 h2 -> stream_le t1 t2).
Proof.
move E1: (scons h1 t1) => sc1; move E2: (scons h2 t2) => sc2 H.
by case: sc1 sc2 / H E1 E2 => h1' h2' t1' t2' hr ih [? ?] [? ?]; subst.
Qed.
您可以阅读手册了解更多详情,但基本上在第一行,我们创造了我们需要的平等;然后,在第二个中,我们可以破坏术语并获得解决目标的适当实例。 case:
策略的一个很好的效果是,与破坏相反,它会试图阻止我们在没有首先将其依赖性纳入范围的情况下破坏一个术语。
答案 1 :(得分:3)
致电destruct
不会直接为您提供所需内容。您需要改为使用inversion
。
Theorem stream_le_destruct : forall h1 h2 t1 t2,
stream_le (scons h1 t1) (scons h2 t2) ->
h1 <= h2 /\ (h1 = h2 -> stream_le t1 t2).
Proof.
intros.
inversion H; subst; clear H.
split; assumption.
Qed.
不幸的是,inversion
策略非常糟糕,因为它往往会产生许多虚假的平等假设,因此难以一致地命名它们。一个(有点重量级,不可否认)替代方案是仅使用inversion
来证明类似于你所做的引理,并在证明中应用此引理而不是调用inversion
。