考虑这个例子:
Inductive T :=
| foo : T
| bar : nat -> T -> T.
Fixpoint evalT (t:T) {struct t} : nat :=
match t with
| foo => 1
| bar n x => evalBar x n
end
with evalBar (x:T) (n:nat) {struct n} : nat :=
match n with
| O => 0
| S n' => (evalT x) + (evalBar x n')
end.
Coq以错误拒绝它:对evalBar的递归调用的主要参数等于" n"而不是" x" 。
我知道终止检查器被两个不相关的归纳类型(T和nat)搞糊涂了。但是,看起来我试图定义的函数确实会终止。我如何让Coq接受它?
答案 0 :(得分:1)
我找到的一个解决方案是使用nat_rec
代替evalBar
:
Fixpoint evalT (t:T) {struct t} : nat :=
match t with
| foo => 1
| bar n x => @nat_rec _ 0 (fun n' t' => (evalT x) + t') n
end.
它有效,但我希望我可以在nat_rec
定义下隐藏evalBar
来隐藏细节。在我的真实项目中,这样的构造被多次使用。
答案 1 :(得分:1)
另一种解决方案是使用嵌套的修复点。
Fixpoint evalT (t:T) {struct t} : nat :=
match t with
| foo => 1
| bar n x => let fix evalBar n {struct n} :=
match n with
| 0 => 0
| S n' => Nat.add (evalT x) (evalBar n')
end
in evalBar n
end.
重点是从x
中删除参数evalBar
。因此,对evalT
的{{1}}的递归调用是在x
的{{1}}而不是作为bar n x
的参数的x
完成的,因此终止检查器可以验证evalBar
的定义。
这与使另一个答案中提出的evalT
版本的作品相同。