我对Coq中的类型检查定义有疑问。我遇到一种情况,我有两个类型为t1和t2的项,从定义中我知道t1和t2相等(t1 = t2)。但是,我不能将这两个术语一起使用,因为类型检查器认为类型不相等。我试图找出一个对情况进行建模的最小示例(是的,我知道这是一个愚蠢的属性,但我只想让它进行类型检查;)):
Require Import Coq.Lists.List.
Lemma myLemma :
forall t1 t2 : Type,
forall (l1 : list t1) (l2 : list t2),
t1 = t2 ->
l1 = l2.
假设我不能直接写(l2 : list t1)
,因为我是从另一个定义中获得的。
我尝试使用Program
是因为我希望我可以以某种方式推迟任务以证明类型匹配,但这没有帮助(得到相同的类型检查错误)。
如果上面的示例不足以使问题明确,那么以下是我的实际问题摘录:
Definition taclet_sound_new (t : taclet) :=
forall K st seSt, let S := (sig K) in
[(K, st)] |= (pathC seSt) ->
(forall K', let S' := (sig K') in
S' = (newSig t S) ->
exists (seSt' : (@sestatesc (newSig t S))),
List.In seSt' (apply t S seSt) ->
[(K', st)] |= (conv S' (pathC seSt'))).
系统抱怨The term "pathC seSt'" has type "@pathCond (newSig t S)" while it is expected to have type "@pathCond S'".
;但是,从前提S' = (newSig t S)
开始,我希望可以通过某种方式检查该定义类型。
(注:conv
是一个琐碎的定义,我只是为了改善Coq的输出而添加-Definition conv (S : signature) (pc : (@pathCond S)) : list (@formulas S) := pc.
-如果没有,它说The term "pathC seSt'" has type "pathCond" while it is expected to have type "list formulas".
掩盖了实际问题。)
出于完整性考虑:记录taclet
定义为
Record taclet : Type := {
defined (prog : P) : Prop;
newSig (S1 : signature) : signature ;
apply : forall (S1 : signature),
(@sestatesc S1) -> list (@sestatesc (newSig S1)) ;
}.
这里有newSig
个词。因此,替代定义
Definition taclet_sound_new (t : taclet) :=
forall K st seSt, let S := (sig K) in
[(K, st)] |= (pathC seSt) ->
(forall K', let S' := (sig K') in
exists (seSt' : (@sestatesc S')),
S' = (newSig t S) ->
List.In seSt' (apply t S seSt) ->
[(K', st)] |= (pathC seSt')).
也不会键入check,出现类似错误The term "apply t S seSt" has type "list (sestatesc P (newSig t S))" while it is expected to have type "list (sestatesc P S')".
,同样应从前提中清除该错误。
如果有人可以帮助我,我将非常高兴。 Coq的类型检查机制有时有点不方便...;)
谢谢!
/ edit(2018-09-27):尽管我在下面给自己一个答案,可以安抚类型检查器,但是在尝试解决一些定理时,我仍然遇到很多问题和谓词逻辑领域的定义。例如,由于类型检查,我完全无法定义令人满意的保守性定理版本(如果公式在结构中有效,那么在所有扩展中也都有效),并且添加一个疯狂的约束(扩展名具有相同的签名,因此它并不是真正的扩展名),并添加(有效的)演员表,我无法证明!
这次,我想我举一个完整的例子。我隔离了该问题,并将其作为 GitHub Gist (https://gist.github.com/rindPHI/9c55346965418bd5db26bfa8404aa7fe)放在一个文件“ firstorder.v”中。文档中有注释,解释了我为自己发现的挑战。如果有人找到了其中一个或两个“主要挑战”的答案,我将非常< em< 很高兴了解他们(并在此接受这个答案)。再次感谢!我希望对这些问题的解决方案不仅对我有帮助,而且对因相关问题而变得绝望的其他人也有帮助;)
答案 0 :(得分:0)
多亏了Anton的评论,我设法以某种方式解决了这个问题。 This answer回答了Anton提出的第一个问题,使我开始考虑编写一个cast
函数(我也尝试使用另一种替代方法JMeq,但这无济于事-也许我不太了解它)。我以为可以共享解决方案,以防有人帮忙。
首先,我编写了以下cast
函数,并通过两个包装器使用了该包装器(由于它们通常并不有趣,因此我不会发布它们:
Definition simple_cast {T1 T2 : Type} (H : T1 = T2) (x : T1) : T2 :=
eq_rect T1 (fun T3 : Type => T3) x T2 H.
(备注:我没有直接提出 eq_rect
术语,因为我对专业用户还不够;但是,可以在Coq中,我发现这很有趣: Definition simple_cast {T1 T2 : Type} (H : T1 = T2) (x : T1) : T2. rewrite -> H in x. assumption. Defined.
如果您这样做 Print simple_cast
,您会得到一个可以简化一点并直接简化的术语将其发布到定义中以使其更明确。构建这种方式的术语要容易得多,因为您可以使用简单的策略。
接下来,我想出了以下定义,这使我避免了包装程序:
Definition cast {T : Type} {T1 T2 : T} (H : T1 = T2) (f : T -> Type) (x : f T1) :=
eq_rect T1 (fun T3 : T => f T3) x T2 H.
关于简单列表示例,以下代码类型检查:
Lemma myLemma :
forall t1 t2 : Type,
forall (l1 : list t1) (l2 : list t2),
forall (H : t2 = t1),
l1 = cast H (list) l2.
我的实际代码段也进行检查:
Definition taclet_sound_new (t : taclet) :=
forall K st seSt, let S := (sig K) in
[(K, st)] |= (pathC seSt) ->
(forall K', let S' := (sig K') in
forall (H : (newSig t S) = S'),
exists (seSt' : (@sestatesc (newSig t S))),
List.In seSt' (apply t S seSt) ->
[(K', st)] |= (cast H (@pathCond) (pathC seSt'))).
最后,我可以在Coq中强制转换表达式(只要有确凿的证据证明强制转换可以-我可以接受)!
/ edit:我现在找到了用于此类强制转换的库:Heq library。这样,myLemma
就像
Lemma myLemma :
forall t1 t2 : Type,
forall (l1 : list t1) (l2 : list t2),
forall (H : t2 = t1),
l1 = << list # H >> l2.
因此您不必编写自己的强制转换函数。
不幸的是,我无法真正消除证明中的演员表(无论我使用自己的演员表还是Heq的演员表);看来您需要成为一位真正有经验的依赖类型黑客。或我的引理错了,但是我不认为。对于那些真的想进入主题的人们,Adam Chlipala出色的CPDT book中有一章关于平等。就我而言,我个人将只是“ admit
”一些证明来简化这些表达并以此为基础。至少它会进行检查...