Coq提取过程中的证据泄漏?

Coq提取过程中的证据泄漏?,coq,Coq,为了理解一般的递归函数定义是如何工作的,以及它们是如何符合Coq的结构递归约束的,我尝试在Peano自然数上重新实现它。我想定义递归的nat->nat函数,这些函数可以使用任何先前的值,而不仅仅是先前的值。以下是我所做的: Definition nat_strong_induction_set (* erased at extraction, type specification *) (P : nat -> Set)

为了理解一般的递归
函数
定义是如何工作的,以及它们是如何符合Coq的结构递归约束的,我尝试在Peano自然数上重新实现它。我想定义递归的
nat->nat
函数,这些函数可以使用任何先前的值,而不仅仅是先前的值。以下是我所做的:

  Definition nat_strong_induction_set
             (* erased at extraction, type specification *)
             (P : nat -> Set)
             (* The strong induction step. To build the P n it can, but does not have to, 
                recursively query the construction of any previous P k's. *)
             (ind_step : forall n : nat, (forall k : nat, (lt k n -> P k)) -> P n)
             (n : nat)
    : P n.
  Proof.
    (* Force the hypothesis of ind_step as a standard induction hypothesis *)
    assert (forall m k : nat, lt k m -> P k) as partial_build.
    { induction m.
      - intros k H0. destruct k; inversion H0.
      - intros k H0. apply ind_step. intros k0 H1. apply IHm. apply (lt_transitive k0 k).
        assumption. apply le_lt_equiv. assumption. }
    apply (partial_build (S n) n). apply succ_lt.
  Defined.
我在NAT上使用了一些自定义引理,我没有粘贴在这里。它起作用了,我用它定义了欧几里得除法
divab
,它递归地使用
div(a-b)b
。提取几乎是我所期望的:

let nat_strong_induction_set ind_step n =
  let m = S n in
  let rec f n0 k =
    match n0 with
    | O -> assert false (* absurd case *)
    | S n1 -> ind_step k (fun k0 _ -> f n1 k0)
  in f m n
除了
n0
参数之外。我们看到这个参数的唯一作用是在
sn
-n步停止递归。提取还提到不应发生此
断言false
。那么为什么要提取呢?这似乎更好

let nat_strong_induction_set ind_step n =
  let rec f k = ind_step k (fun k0 _ -> f k0)
  in f n

它看起来像是Coq的结构递归约束的一个小故障,以确保所有递归的终止。
nat\u strong\u inclution\u set
的Coq定义写入
lt k n
,因此Coq只知道将查询以前的
pk
。这使得NAT中的链逐渐减少,被迫以小于
sn
的步数终止。这允许从
sn
开始对附加燃油参数
n0
进行结构递归定义,不会影响结果。因此,如果它只是终止证明的一部分,为什么不通过提取来删除它呢?

您的匹配不会被删除,因为您的定义混合了两件事:需要匹配的终止参数和不需要匹配的计算相关递归调用

要强制擦除,您需要说服Coq匹配在计算上是无关的。您可以通过使终止参数(即,
m
上的归纳)生成命题的证明,而不是所有mk,lt k m->pk
类型的函数。幸运的是,使用
Fix
combinator,标准库提供了一种简单的方法:

Require Import Coq.Arith.Wf_nat.

Definition nat_strong_induction_set
             (P : nat -> Set)
             (ind_step : forall n : nat, (forall k : nat, (lt k n -> P k)) -> P n)
             (n : nat)
    : P n :=
  Fix lt_wf P ind_step n.
在这里,
lt\u wf
证明了
lt
是有根据的。当你提取这个函数时,你会得到

let rec nat_strong_induction_set ind_step n =
  ind_step n (fun y _ -> nat_strong_induction_set ind_step y)
这正是你想要的


(顺便说一句,请注意,定义除法不需要有良好基础的递归——例如,检查如何在中定义除法。)

该库对良好基础关系的定义非常好。这么简单。。。然而,我已经三天没能自己编写代码了。这给了我另一个关于归纳性质的问题,我不明白数学元件库中除法的定义是如何结构递归的。这是相同的算法,它迭代地从分子中减去分母。是否涉及到一些SSReflect黑魔法?@V.Semeria Coq的终止检查器比你想象的更聪明。它能够检测到,如果
m-n=sm'
,那么
m'
m
的一个子项,因为减法()的定义返回它的第一个参数,而不是基于基本情况的0!(无可否认,这是一种黑客行为,但在这种情况下它确实派上了用场。)