我开始学习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}} {}} {}} {}}} {}} {}} {}} {} {}} {} {}}任何指导都将不胜感激。
答案 0 :(得分:6)
您认为证据应按如下方式进行:
列表不能为
nil
,因为contains
为真,因此x
中必须有l
元素,beq_nat h x
为{{1} }}
尽管这对人类来说具有直观意义,但对于Coq来说,它并不够精确。正如ejgallego的回答所显示的那样,问题在于你的非正式推理隐瞒了归纳的使用。实际上,即使在将其转化为策略之前,尝试更详细地扩展您的论点也是有用的。我们可以这样做,例如:
让我们证明,对于每个true
和n : nat
,ns : 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'
。
如果true
为beq_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' > 0
为beq_nat n n'
,则根据false
和contains
的定义,我们需要证明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.
以及可能有用的count
和contains
的不同定义:
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.