我们将使用有限集的标准定义:
Inductive fin : nat -> Set :=
| F1 : forall {n : nat}, fin (S n)
| FS : forall {n : nat}, fin n -> fin (S n).
让我们假设我们有一些P : forall {m : nat} (x y : fin m) : Set
(重要的是 的两个参数P
属于同一类型)。出于演示目的,设 P 为:
Definition P {m : nat} (x y : fin m) := {x = y} + {x <> y}.
现在,我们想编写一个比较两个数字的自定义函数:
Fixpoint feq_dec {m : nat} (x y : fin m) : P x y.
这个想法很简单:我们匹配x
and y
,对于x = F1
,y = F1
我们平凡地返回相等,对于x = FS x'
,y = FS y'
我们递归地调用过程x'
和y'
,对于其他情况,我们可以平凡地返回不等式。
将这个想法直接翻译成 Coq 显然失败了:
refine (
match x, y return P x y with
| F1 _, F1 _ => _
| FS _ x', F1 _ => _
| F1 _, FS _ y' => _
| FS _ x', FS _ y' => _
end
).
(*
* The term "y0" has type "fin n0" while it is expected to have type "fin n".
*)
在比赛期间x
,y
我们丢失了类型信息,因此我们无法将它们应用于P
. 传递类型相等证明的标准技巧在这里没有帮助:
refine (
match x in fin mx, y in fin my return mx = my -> P x y with
| F1 _, F1 _ => _
| FS _ x', F1 _ => _
| F1 _, FS _ y' => _
| FS _ x', FS _ y' => _
end eq_refl
).
(*
* The term "y0" has type "fin my" while it is expected to have type "fin mx".
*)
那么,也许我们可以使用该相等性证明来强制转换x
具有与 ? 相同的类型
y
?
Definition fcast {m1 m2 : nat} (Heq : m1 = m2) (x : fin m1) : fin m2.
Proof.
rewrite <- Heq.
apply x.
Defined.
我们还需要能够在以后摆脱演员阵容。但是,我注意到这
fcast eq_refl x = x
还不够,因为我们需要让它与任意等价证明一起工作。我找到了一个叫做 UIP 的东西,它可以满足我的需要。
Require Import Coq.Program.Program.
Lemma fcast_void {m : nat} : forall (x : fin m) (H : m = m),
fcast H x = x.
Proof.
intros.
rewrite -> (UIP nat m m H eq_refl).
trivial.
Defined.
现在我们准备完成整个定义:
refine (
match x in fin mx, y in fin my
return forall (Hmx : m = mx) (Hmy : mx = my), P (fcast Hmy x) y with
| F1 _, F1 _ => fun Hmx Hmy => _
| FS _ x', F1 _ => fun Hmx Hmy => _
| F1 _, FS _ y' => fun Hmx Hmy => _
| FS _ x', FS _ y' => fun Hmx Hmy => _
end eq_refl eq_refl
); inversion Hmy; subst; rewrite fcast_void.
- left. reflexivity.
- right. intro Contra. inversion Contra.
- right. intro Contra. inversion Contra.
- destruct (feq_dec _ x' y') as [Heq | Hneq].
+ left. apply f_equal. apply Heq.
+ right. intro Contra. dependent destruction Contra. apply Hneq. reflexivity.
Defined.
它通过了!但是,它不会评估任何有用的价值。例如,以下产生一个具有五个嵌套匹配项而不是一个简单值(in_right
或in_left
)的术语。我怀疑问题出在我使用的 UIP 公理上。
Compute (@feq_dec 5 (FS F1) (FS F1)).
所以最后,我想出的定义几乎没有用。我也尝试过使用convoy 模式进行嵌套匹配,而不是同时匹配两个值,但我遇到了同样的障碍:一旦我对第二个值进行匹配,就P
不再适用于它。我可以用其他方式吗?