我正在尝试在Coq中定义一个固定点,其中一个函数定义通过一个参数引用另一个,但是我遇到了一些令人困惑的错误。
我已经将定义最小化了:
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不接受。这是什么错误,我该如何解决?
答案 0 :(得分:3)
假设您还对其他参数使用了Wrapper
。然后,您需要中断相互递归并使函数与数据类型“平行”。所以你想写Wrapper_size: Wrapper T -> (T -> nat) -> nat
。
然后您可以在Wrapper_size Unwrapper_size
中使用Unwrapper_size
:Coq应该在终止检查中做足够的内联,以确认这是安全的。
在此示例中,手动进行内联也很容易:Unwrapper_size
将在Unwrap (Wrap _ t)
上匹配并在t
上递归。