Coq提取中的证明泄漏?

时间:2018-08-14 15:11:18

标签: coq

为了了解通用递归Function的定义是如何工作的,以及它们如何符合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上使用了一些自定义引理,这些引理我没有粘贴到这里。它起作用了,我设法用它定义了欧几里得除法div a b,它递归地使用了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参数。我们看到此参数的唯一作用是在第S n-n步停止递归。摘录还提到不应assert 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_strong_induction_set的Coq定义写入lt k n,因此Coq知道将仅查询先前的P k。这使nat中的链条减少,被迫以少于S n个步骤终止。这样就可以对从n0开始的附加燃料参数S n进行结构性递归定义,这不会影响结果。因此,如果它只是终止证明的一部分,为什么提取过程不会将其删除?

1 个答案:

答案 0 :(得分:3)

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

要强制擦除,您需要使Coq确信该匹配在计算上无关紧要。您可以通过设置终止参数(即m的归纳法)来产生命题的证明,而不是类型为forall m k, lt k m -> P k的函数。幸运的是,标准库提供了使用Fix组合器的简便方法:

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_wf证明lt有充分的依据。提取此功能后,您将得到

let rec nat_strong_induction_set ind_step n =
  ind_step n (fun y _ -> nat_strong_induction_set ind_step y)

这正是您想要的。

(顺便说一句,请注意,您不需要有充分根据的递归来定义除法-例如检查Mathematical Components library中的除法定义。)