关注Arthur's suggestion后,我将Fixpoint
关系更改为共同Inductive
关系,“建立”游戏之间的不同比较而不是“向下钻取”。
但现在我收到一条全新的错误消息:
Error: Parameters should be syntactically the same for each inductive type.
我认为错误信息是说我需要所有这些互感定义的相同精确参数。
我意识到有一些简单的黑客来解决这个问题(未使用的虚拟变量,包含forall
内部所有内容的长函数类型),但我不明白为什么我应该这样做。
有人可以解释这种对互感类型的限制背后的逻辑吗?是否有更优雅的方式来写这个?这种限制是否也意味着相互之间的归纳调用必须使用相同的参数(在这种情况下,我不知道任何黑客可以保存大量的代码重复)?
(所有类型和术语的定义,例如compare_quest,game,g1side等,与我first question中的定义相同。
Inductive gameCompare (c : compare_quest) : game -> game -> Prop :=
| igc : forall g1 g2 : game,
innerGCompare (nextCompare c) (compareCombiner c) (g1side c) (g2side c) g1 g2 ->
gameCompare c g1 g2
with innerGCompare (next_c : compare_quest) (cbn : combiner) (g1s g2s : side)
: game -> game -> Prop :=
| compBoth : forall g1 g2 : game,
cbn (listGameCompare next_c cbn (g1s g1) g2)
(gameListCompare next_c cbn g1 (g2s g2)) ->
innerGCompare next_c cbn g1s g2s g1 g2
with listGameCompare (c : compare_quest) (cbn : combiner) : gamelist -> game -> Prop :=
| emptylgCompare : cbn_init cbn -> forall g2 : game, listGameCompare c cbn emptylist g2
| otlgCompare : forall (g1_cdr : gamelist) (g1_car g2 : game),
(cbn (listGameCompare c cbn g1_cdr g2) (gameCompare c g1_car g2)) ->
listGameCompare c cbn (listCons g1_car g1_cdr) g2
with gameListCompare (c : compare_quest) (cbn : combiner) : game -> gamelist -> Prop :=
| emptyglCompare : cbn_init cbn -> forall g1 : game, gameListCompare c cbn g1 emptylist
| otglCompare : forall (g1 g2_car : game) (g2_cdr : gamelist),
(cbn (gameListCompare c cbn g1 g2_cdr) (gameCompare c g1 g2_car)) ->
gameListCompare c cbn g1 (listCons g2_car g2_cdr).
在CGT中,通常有两个玩家(名为Left
和Right
)轮流玩游戏,让最后一步的玩家获胜。每个游戏(意味着游戏中的每个位置)都可以被视为一组Left
选项和一组Right
选项,写为{G_L | G_R}
。在比较两款游戏时,他们可以通过四种不同的方式进行比较:<
,>
,=
或||
。
如果A < B
严格优于B
A
,则Left
游戏为A > B
,无论谁先行。{如果A
优于B
Left
A = B
,则A + -B
。 A || B
如果这两个游戏是相同的(在某种意义上,游戏Left
的总和是零游戏,那么首先输掉的玩家就输了)。并且,A <= B
如果哪个游戏更适合A
,则取决于谁先行。
检查两场比赛之间比较的一种方法如下:
Left
如果所有<| B
的{{1}}个孩子都是A <|
且B
所有A <| B
的孩子都是。
A
如果<= B
有一个正确的孩子A <=
或B
任何>=
的左子女。
同样适用于>|
和A
。
那么,通过查看哪一对关系适用于两个游戏B
和A < B
,可以确定A<=B
(A<|B
和{{1} }),A=B
(A<=B
和A>=B
),A > B
(A>=B
和A>|B
)或A || B
({{ 1}}和A<|B
)。
答案 0 :(得分:2)
这个限制非常有趣,我之前从未遇到过。我没有看到为什么要拒绝这段代码的原因。我最好的选择是,当人们设计Coq的基础时,这种限制使得一些证据变得更容易,并且因为没有多少人对它感到烦恼,所以它只是保持这种状态。不过,我可能完全错了;我知道参数和参数(即箭头右侧的参数和参数)对某些事情的处理方式略有不同。例如,与参数相比,定义归纳类型时强加的Universe约束对参数的限制较少。
也许这应该转发给Coq Club邮件列表? :)
您无需将所有内容放在箭头右侧即可使其正常工作。您可以做的一件事是将除compare_quest
参数之外的所有内容放在右侧。当你使用你在构造函数中定义的相同类型的归纳时,你给出的参数不必与你在标题上给出的参数相同,所以没关系:
Inductive gameCompare (c : compare_quest) : game -> game -> Prop :=
| igc : forall g1 g2 : game,
innerGCompare (nextCompare c) (compareCombiner c) (g1side c) (g2side c) g1 g2 ->
gameCompare c g1 g2
with innerGCompare (c : compare_quest) : combiner -> side -> side ->
game -> game -> Prop :=
| compBoth : forall cbn g1s g2s (g1 g2 : game),
cbn (listGameCompare c cbn (g1s g1) g2)
(gameListCompare c cbn g1 (g2s g2)) ->
innerGCompare c cbn g1s g2s g1 g2
with listGameCompare (c : compare_quest) : combiner -> gamelist -> game -> Prop :=
| emptylgCompare : forall cbn, cbn_init cbn -> forall g2 : game, listGameCompare c cbn emptylist g2
| otlgCompare : forall cbn (g1_cdr : gamelist) (g1_car g2 : game),
(cbn (listGameCompare c cbn g1_cdr g2) (gameCompare c g1_car g2)) ->
listGameCompare c cbn (listCons g1_car g1_cdr) g2
with gameListCompare (c : compare_quest) : combiner -> game -> gamelist -> Prop :=
| emptyglCompare : forall cbn, cbn_init cbn -> forall g1 : game, gameListCompare c cbn g1 emptylist
| otglCompare : forall cbn (g1 g2_car : game) (g2_cdr : gamelist),
(cbn (gameListCompare c cbn g1 g2_cdr) (gameCompare c g1 g2_car)) ->
gameListCompare c cbn g1 (listCons g2_car g2_cdr).
不幸的是,尝试评估这会产生一个新错误:(
Error: Non strictly positive occurrence of "listGameCompare" in
"forall (cbn : Prop -> Prop -> Prop) (g1s g2s : game -> gamelist)
(g1 g2 : game),
cbn (listGameCompare c cbn (g1s g1) g2) (gameListCompare c cbn g1 (g2s g2)) ->
innerGCompare c cbn g1s g2s g1 g2".
这个错误在Coq中更为常见。它抱怨你将你定义的类型作为cbn
的参数传递,因为这可能导致该类型出现在箭头的 left (负面事件),这是已知会导致逻辑上的不一致。
我认为你可以通过在最后三种类型的构造函数中内联compareCombiner
来解决这个问题,这可能需要对代码进行一些重构。再说一遍,我很确定必须有更好的方法来定义它,但我不明白你想要做的很好,所以我的帮助在那里有点受限。
更新:我已经开始了一系列关于在Coq中正式化一些CGT的文章。你可以找到第一个here。