在Coq中定义参数化不动点
我试图在Coq中定义一个不动点,其中一个函数定义通过一个参数引用另一个函数定义,但我得到了一些令人困惑的错误 我已将此定义最小化:在Coq中定义参数化不动点,coq,Coq,我试图在Coq中定义一个不动点,其中一个函数定义通过一个参数引用另一个函数定义,但我得到了一些令人困惑的错误 我已将此定义最小化: Require Import Coq.Init.Notations. Require Import Coq.Init.Datatypes. Inductive Wrapper (T : Type) := | Wrap : T -> Wrapper T . Inductive Unwrapper := | Empty : Unwrapper |
Require Import Coq.Init.Notations.
Require Import Coq.Init.Datatypes.
Inductive Wrapper (T : Type) :=
| Wrap : T -> Wrapper T
.
Inductive Unwrapper :=
| Empty : Unwrapper
| Unwrap : Wrapper Unwrapper -> Unwrapper
.
Fixpoint Unwrapper_size (u : Unwrapper) {struct u} : nat :=
match u with
| Empty => O
| Unwrap w => Wrapper_size w
end
with Wrapper_size (w : Wrapper Unwrapper) {struct w} : nat :=
match w with
| Wrap _ t => Unwrapper_size t
end.
导致此错误的原因:
Recursive definition of Wrapper_size is ill-formed.
In environment
Unwrapper_size : Unwrapper -> nat
Wrapper_size : Wrapper Unwrapper -> nat
w : Wrapper Unwrapper
t : Unwrapper
Recursive call to Unwrapper_size has principal argument equal to
"t" instead of a subterm of "w".
Recursive definition is:
"fun w : Wrapper Unwrapper =>
match w with
| Wrap _ t => Unwrapper_size t
end".
这里,
t
显然是w
的一个子项-w
是我们匹配得到的t
,但Coq不接受它。这里的错误是什么,我该如何避免呢?假设您在其他参数上也使用了包装器。然后需要打破相互递归,使函数与数据类型“并行”。所以你想写Wrapper\u size:Wrapper T->(T->nat)->nat
然后您可以在Unwrapper\u size
中使用Wrapper\u size Unwrapper\u size
:Coq应该在终止检查中进行足够的内联,以识别这是安全的
在本例中,手动内联也很容易:Unwrapper\u size
将在Unwrap(Wrap\t)
上匹配,并在t
上递归。您的代码非常可疑:唯一的基本情况返回0,并且在nat上没有操作。因此,如果它终止,它只返回0。这可能不是你想要的。是的,我已经最小化了定义,以便更清楚地阅读。我的实际用例不那么空洞,但它只是给问题增加了更多的噪音。(您可以想象实际增加递归调用的结果以生成一个更有用的函数。)正如有人在IRC上所说,“尝试将包装器和展开器定义为相互归纳的”,给出归纳包装器:=Wrap:unwrapper->wrapper with unwrapper
:Coq的“子项”概念假设递归遵循数据类型的结构。我想这对最初的一个没有帮助,但最好有一个例子,说明这不起作用。我有另一个想法…如果你也包装其他东西,那么你需要打破相互递归,使函数与数据类型“并行”。所以写Wrapper\u size:Wrapper T->(T->nat)->nat.
然后我会尝试在Unwrapper\u size
中使用Wrapper\u size Unwrapper\u size
:Coq可能会在终止检查中进行足够的内联,以识别这是安全的。(在本例中,手动内联也很容易:Unwrapper_size`将在Unwrap(wrap t)
上匹配,并在t
上递归)。如果所有其他操作都失败,则总是有充分的归纳,但这很烦人,我会尝试避免它。