归纳型和nat的相互递归

时间:2018-05-22 23:44:06

标签: recursion coq termination

考虑这个例子:

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接受它?

2 个答案:

答案 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版本的作品相同。