证明涉及在COQ中展开两个递归函数

时间:2017-04-17 13:08:42

标签: coq proof coq-tactic

我开始学习Coq,并试图证明一些看似相当简单的事情:如果一个列表包含x,那么该列表中x的实例数将是> 0

我已经定义了包含和计数函数,如下所示:

Fixpoint contains (n: nat) (l: list nat) : Prop :=
  match l with
  | nil => False
  | h :: t => if beq_nat h n then True else contains n t
  end.

Fixpoint count (n acc: nat) (l: list nat) : nat :=
  match l with
  | nil => acc
  | h :: t => if beq_nat h n then count n (acc + 1) t else count n acc t
  end.

我试图证明:

Lemma contains_count_ge1 : forall (n: nat) (l: list nat), contains n l -> (count n 0 l > 0).

我理解证明将涉及展开count和contains的定义,但是我想说"列表不能为nil,因为contains是真的,所以必须有一个元素{{在x {1}} {}} {}} {}}} {}} {}} {}} {} {}} {} {}}任何指导都将不胜感激。

2 个答案:

答案 0 :(得分:6)

在他的回答中,ejgallego已经为你的问题提供了很好的解决方案。我仍然想提出一个他遗漏的重要观点:在Coq中,你必须始终从第一原则论证,并且对你的证明非常迂腐和准确。

您认为证据应按如下方式进行:

  

列表不能为nil,因为contains为真,因此x中必须有l元素,beq_nat h x为{{1} }}

尽管这对人类来说具有直观意义,但对于Coq来说,它并不够精确。正如ejgallego的回答所显示的那样,问题在于你的非正式推理隐瞒了归纳的使用。实际上,即使在将其转化为策略之前,尝试更详细地扩展您的论点也是有用的。我们可以这样做,例如:

让我们证明,对于每个truen : natns : list nat隐含contains n ns。我们在列表count n 0 ns > 0上进行归纳。如果ns,则ns = nil的定义意味着contains成立;矛盾。因此,我们留下案例False,我们可以使用以下归纳假设:ns = n' :: ns'。需要考虑两个子案例:contains n ns' -> count n 0 ns' > 0是否为beq_nat n n'

  • 如果truebeq_nat n n',根据true的定义,我们只需要显示count。请注意,这里没有直接的方法。这是因为您使用累加器以递归方式编写count n (0 + 1) ns' > 0。虽然这在函数式编程中非常合理,但它可以使count的证明属性更加困难。在这种情况下,我们需要以下辅助引理,也可以通过归纳证明:count。我会让你弄清楚如何证明这一点。但假设我们已经建立了它,目标将减少到显示forall n acc ns, count n acc ns = acc + count n 0 ns。通过简单的算术就是这样。 (有一种更简单的方法,不需要辅助引理,但它需要略微概括你所证明的陈述。)

  • 如果1 + count n 0 ns' > 0beq_nat n n',则根据falsecontains的定义,我们需要证明count暗示{{1} }}。这正是诱导假设给我们的,我们已经完成了。

这里有两个可以吸取的教训。第一个问题是,做正式证明通常需要用系统可以理解的正式术语来翻译你的直觉。我们直观地知道在列表中出现一些元素意味着什么。但是如果我们要更正式地解释这意味着什么,我们会采用某种递归遍历的方式,这可能会成为你在Coq中写的contains n ns'的定义。为了推理递归,我们需要归纳。第二个教训是,您在Coq中定义事物的方式对您编写的证明具有重要影响。 ejgallego的解决方案不需要任何超出标准库中的辅助引理,正是因为他对count n 0 ns' > 0的定义不是尾递归的。

答案 1 :(得分:2)

嗯,你提出了许多关于基本Coq的问题,超出了IMO可以解决的问题。对于这个特殊的问题,我会这样做(实际上我会使用MathComp中已经提供的引理):

From Coq Require Import PeanoNat Bool List.

Fixpoint contains (n: nat) (l: list nat) : bool :=
  match l with
  | nil    => false
  | h :: t => if Nat.eqb h n then true else contains n t
  end.

Fixpoint count (n : nat) (l: list nat) : nat :=
  match l with
  | nil => 0
  | h :: t => if Nat.eqb h n then S (count n t) else count n t
  end.

Lemma contains_count_ge1 n l : contains n l = true -> count n l > 0.
Proof.
induction l as [|x l IHl]; simpl; [now congruence|].
now destruct (Nat.eqb_spec x n); auto with arith.
Qed.

我的标准"溶液:

Lemma test n (l : list nat) : n \in l -> 0 < count_mem n l.
Proof. by rewrite lt0n => /count_memPn/eqP. Qed.

以及可能有用的countcontains的不同定义:

Fixpoint contains (n: nat) (l: list nat) : bool :=
  match l with
  | nil    => false
  | h :: t => Nat.eqb h n || contains n t
  end.

Fixpoint count (n : nat) (l: list nat) : nat :=
  match l with
  | nil    => 0
  | h :: t => Nat.b2n (Nat.eqb h n) + (count n t)
  end.