给出一个从属记录类型:
Record FinPath : Type := mkPath { fp_head : S i;
fp_tail : FinPathTail fp_head
}.
和两个Path
类型的对象相等,我想推断它们的头和尾是相等的。问题是我很快就得到了这种形式的东西:
fpH : {| path_head := fp_head fp; path_tail := fpt_to_pt (fp_tail fp) |} =
{| path_head := fp_head fp'; path_tail := fpt_to_pt (fp_tail fp') |}
使用注入策略,我可以推断出fp_head fp = fp_head fp'
以及这个术语:
existT (fun path_head : S i => PathTail path_head) (fp_head fp)
(fpt_to_pt (fp_tail fp)) =
existT (fun path_head : S i => PathTail path_head) (fp_head fp')
(fpt_to_pt (fp_tail fp'))
假设S i
的可判定性,我通常会想使用inj_pair2_eq_dec
,但这在这种情况下不适用,因为fp_head fp
和fp_head fp'
并不是语法上的相同。我也无法用相同的方式重写它们,因为用fp_head fp' = fp_head fp
进行重写会导致右侧的打字错误。
如何从这里继续? inj_pair2_eq_dec
是否有一个更聪明的版本,以某种方式使用(非语法)基等式而不是要求sigma类型的基数相等?
编辑:稍微思考一下,我意识到要求尾巴相等是没有意义的(因为尾巴的类型不同)。但是有可能基于eq_rect
证明他们之间某种形式的莱布尼兹平等吗?
答案 0 :(得分:3)
像这样的问题是为什么许多人更喜欢在Coq中避免依赖类型的原因。对于Coq sigma类型{x : T & S x}
,我将回答您的问题,该类型可以推广到其他从属记录。
我们可以通过强制转换函数来表达该对依赖组件应该满足的相等性:
Definition cast {T} (S : T -> Type) {a b : T} (p : a = b) : S a -> S b :=
match p with eq_refl => fun a => a end.
Definition eq_sig T (S : T -> Type) (a b : T) x y
(p : existT S a x = existT S b y) :
{q : a = b & cast S q x = y} :=
match p in _ = z return {q : a = projT1 z & cast S q x = projT2 z} with
| eq_refl => existT _ eq_refl eq_refl
end.
cast
函数允许我们使用等式p : a = b
从S a
转换为S b
。我通过证明术语定义的eq_sig
引理说,给定两个依赖对p
和existT S a x
之间的等式existT S b y
,我可以产生另一个依赖对包含:
等式q : a = b
和
证明x
和y
在投射后等于 。
使用类似的定义,我们可以提供一个证明原理,用于“归纳”相关对之间的相等性证明:
Definition eq_sig_elim T (S : T -> Type) (a b : T) x y
(p : existT S a x = existT S b y) :
forall (R : forall c, S c -> Prop), R a x -> R b y :=
match p in _ = z return forall (R : forall c, S c -> Prop), R a x -> R _ (projT2 z) with
| eq_refl => fun R H => H
end.
引理的形状与eq_sig
相似,但这一次它表示在存在这样的相等性的情况下,我们可以证明任意依赖谓词{{1} }提供了R b y
的证明。
使用这种依赖原则可能很尴尬。面临的挑战是找到一个R a x
来表达自己的目标:在上面的结果类型中,R
的第二个参数的类型相对于第一个参数是参数性的。在许多感兴趣的情况下,第二项的第一成分R
不是变量,而是具有特定的形状,这可能会阻止直接概括。