Coq 证明偶数+;偶数=偶数,使用策略相互感应
我在Coq中尝试了相互感应,我定义的第一种类型是Coq 证明偶数+;偶数=偶数,使用策略相互感应,coq,Coq,我在Coq中尝试了相互感应,我定义的第一种类型是 Inductive IsEven : nat -> Prop := | EvenO : IsEven O | EvenS n : IsOdd n -> IsEven (S n) with IsOdd : nat -> Prop := | OddS n : IsEven n -> IsOdd (S n). 我现在想证明偶数之和是偶数。我可以通过定点和模式匹配来实现这一点: Fixpoint even_plus_
Inductive IsEven : nat -> Prop :=
| EvenO : IsEven O
| EvenS n : IsOdd n -> IsEven (S n)
with IsOdd : nat -> Prop :=
| OddS n : IsEven n -> IsOdd (S n).
我现在想证明偶数之和是偶数。我可以通过定点和模式匹配来实现这一点:
Fixpoint even_plus_even (n m : nat) (evenn : IsEven n) (evenm : IsEven m) : IsEven (n + m) :=
match evenn with
| EvenO => evenm
| EvenS n' oddn' => EvenS (n' + m) (odd_plus_even n' m oddn' evenm)
end
with odd_plus_even (n m : nat) (oddn : IsOdd n) (evenm : IsEven m) : IsOdd (n + m) :=
match oddn with
| OddS n' evenn' => OddS (n' + m) (even_plus_even n' m evenn' evenm)
end.
这定义了偶数加偶数
和奇数加偶数
。我现在想用一种更简洁的方法来证明这一点(最好不要使用许多预定义的引理来尽可能地保持代码的自包含性),但我还没走多远
具体地说,是否可以像我们在不动点上所能使用的那样,只用一个引理来证明偶数加偶数
和奇数加偶数
编辑:非常感谢您的回答,引理。。。使用…
语法正是我想要的。其实
Lemma even_plus_even2 (n m : nat) (evenn : IsEven n) (evenm : IsEven m) : IsEven (n + m)
with odd_plus_even2 (n m : nat) (oddn : IsOdd n) (evenm : IsEven m) : IsOdd (n + m).
Proof.
induction evenn; simpl. assumption. constructor. auto.
induction oddn; simpl. constructor. auto.
Defined.
生成与我原始问题中的
不动点
完全相同的证明项。Coq中支持相互感应。我知道两种方法,但我只记得如何使用其中一种:
Scheme IsEven_ind2 := Induction for IsEven Sort Prop
with IsOdd_ind2 := Induction for IsOdd Sort Prop.
Combined Scheme IsEvenOdd_ind from IsEven_ind2, IsOdd_ind2.
Lemma foo: (forall (n: nat) (evenn: IsEven n), forall m (evenm: IsEven m), IsEven (n + m) ) /\
(forall (n: nat) (oddn: IsOdd n), forall m (evenm: IsEven m), IsOdd (n + m)).
Proof.
apply IsEvenOdd_ind.
- now intros m hm.
- intros h hn hi m hm.
rewrite plus_Sn_m.
apply EvenS.
now apply hi.
- intros h hn hi m hm.
rewrite plus_Sn_m.
apply OddS.
now apply hi.
Qed.
引理
带
Lemma foo: forall (n m: nat) (evenn: IsEven n) (evenm: IsEven m), IsEven (n + m)
with bar: forall (n m: nat) (oddn: IsOdd n) (evenm: IsEven m), IsOdd (n + m).
Proof.
- intros n m hn; revert m; induction hn as [ | p hp]; intros m hm; simpl in *.
+ exact hm.
+ now apply EvenS; apply bar.
- intros n m hn hm; revert n hn; induction hm as [ | p hp]; intros n hn; simpl in *.
+ now apply bar; [ exact hn | apply EvenO ].
+ apply bar; [ exact hn | ].
now apply EvenS.
(* can't Qed, I get a Error: Cannot guess decreasing argument of fix. *)
Qed.
编辑:
下面是带有解决方案的引理的有效语法
Lemma foo (n: nat) (evenn: IsEven n): forall (m: nat) (evenm: IsEven m), IsEven (n + m)
with bar (n: nat) (oddn: IsOdd n): forall (m: nat) (evenm: IsEven m), IsOdd (n + m).
Proof.
- induction evenn as [ | p hp]; intros m hm; simpl in *.
+ exact hm.
+ now apply EvenS; apply bar.
- induction oddn as [p hp]; intros n hn; simpl in *.
+ apply OddS.
now apply foo.
Qed.
在Coq中有相互感应的支持。我知道两种方法,但我只记得如何使用其中一种:
组合方案
以下是它的工作原理:
Scheme IsEven_ind2 := Induction for IsEven Sort Prop
with IsOdd_ind2 := Induction for IsOdd Sort Prop.
Combined Scheme IsEvenOdd_ind from IsEven_ind2, IsOdd_ind2.
Lemma foo: (forall (n: nat) (evenn: IsEven n), forall m (evenm: IsEven m), IsEven (n + m) ) /\
(forall (n: nat) (oddn: IsOdd n), forall m (evenm: IsEven m), IsOdd (n + m)).
Proof.
apply IsEvenOdd_ind.
- now intros m hm.
- intros h hn hi m hm.
rewrite plus_Sn_m.
apply EvenS.
now apply hi.
- intros h hn hi m hm.
rewrite plus_Sn_m.
apply OddS.
now apply hi.
Qed.
引理
带
在这个问题上,我只是不知道如何完成它,但这是一个语法问题iirc:
Lemma foo: forall (n m: nat) (evenn: IsEven n) (evenm: IsEven m), IsEven (n + m)
with bar: forall (n m: nat) (oddn: IsOdd n) (evenm: IsEven m), IsOdd (n + m).
Proof.
- intros n m hn; revert m; induction hn as [ | p hp]; intros m hm; simpl in *.
+ exact hm.
+ now apply EvenS; apply bar.
- intros n m hn hm; revert n hn; induction hm as [ | p hp]; intros n hn; simpl in *.
+ now apply bar; [ exact hn | apply EvenO ].
+ apply bar; [ exact hn | ].
now apply EvenS.
(* can't Qed, I get a Error: Cannot guess decreasing argument of fix. *)
Qed.
编辑:
下面是带有
解决方案的引理的有效语法
Lemma foo (n: nat) (evenn: IsEven n): forall (m: nat) (evenm: IsEven m), IsEven (n + m)
with bar (n: nat) (oddn: IsOdd n): forall (m: nat) (evenm: IsEven m), IsOdd (n + m).
Proof.
- induction evenn as [ | p hp]; intros m hm; simpl in *.
+ exact hm.
+ now apply EvenS; apply bar.
- induction oddn as [p hp]; intros n hn; simpl in *.
+ apply OddS.
now apply foo.
Qed.
例如,您可以通过将两个引理“并”成一个引理来同时证明这两个引理,然后使用proj1
和proj2
提取子句的左或右部分
Lemma even_or_odd_plus_even: forall (n m : nat),
(forall (evenn : IsEven n) (evenm : IsEven m), IsEven (n + m)) /\
(forall (oddn : IsOdd n) (evenm : IsEven m), IsOdd (n + m)).
Proof.
induction n; split; intros;
try destruct (IHn m) as [He Ho];
try apply evenm;
try inversion oddn;
try inversion evenn;
constructor; auto.
Qed.
Definition even_plus_even n m := proj1 (even_or_odd_plus_even n m).
Definition odd_plus_even n m := proj2 (even_or_odd_plus_even n m).
给你
even_plus_even : forall n m : nat, IsEven n -> IsEven m -> IsEven (n + m)
odd_plus_even : forall n m : nat, IsOdd n -> IsEven m -> IsOdd (n + m)
请注意,这两个子句共享n
和m
,如果无法单独证明这两个子句,则需要使用这两个子句,因为它们需要相互依赖。(但在这种情况下,他们没有。你可以单独证明这些陈述,正如安东所示。)
编辑:刚刚看到了Vinz解决方案。我不知道引理有和语法(谢谢展示!),但这是有意义的,我认为这是一种更简洁的方法来定义这个相互依赖的定义
Lemma even_plus_even: forall n m, IsEven n -> IsEven m -> IsEven (n+m)
with odd_plus_even: forall n m, IsOdd n -> IsEven m -> IsOdd (n+m).
Proof.
induction 1; simpl; auto using EvenS.
induction 1; simpl; auto using OddS.
Qed.
例如,您可以通过将两个引理“并”成一个引理来同时证明这两个引理,然后使用proj1
和proj2
提取子句的左或右部分
Lemma even_or_odd_plus_even: forall (n m : nat),
(forall (evenn : IsEven n) (evenm : IsEven m), IsEven (n + m)) /\
(forall (oddn : IsOdd n) (evenm : IsEven m), IsOdd (n + m)).
Proof.
induction n; split; intros;
try destruct (IHn m) as [He Ho];
try apply evenm;
try inversion oddn;
try inversion evenn;
constructor; auto.
Qed.
Definition even_plus_even n m := proj1 (even_or_odd_plus_even n m).
Definition odd_plus_even n m := proj2 (even_or_odd_plus_even n m).
给你
even_plus_even : forall n m : nat, IsEven n -> IsEven m -> IsEven (n + m)
odd_plus_even : forall n m : nat, IsOdd n -> IsEven m -> IsOdd (n + m)
请注意,这两个子句共享n
和m
,如果无法单独证明这两个子句,则需要使用这两个子句,因为它们需要相互依赖。(但在这种情况下,他们没有。你可以单独证明这些陈述,正如安东所示。)
编辑:刚刚看到了Vinz解决方案。我不知道引理有和语法(谢谢展示!),但这是有意义的,我认为这是一种更简洁的方法来定义这个相互依赖的定义
Lemma even_plus_even: forall n m, IsEven n -> IsEven m -> IsEven (n+m)
with odd_plus_even: forall n m, IsOdd n -> IsEven m -> IsOdd (n+m).
Proof.
induction 1; simpl; auto using EvenS.
induction 1; simpl; auto using OddS.
Qed.
TTBOMK您将不得不使用一种棘手的修复策略,因此您的生活不会更好。我的观点是,你使用了错误的Coq工具来解决你的问题。归纳定义是非常强大的理论工具,而奇数
/偶数
是简单的函数,更好地定义为函数nat->bool
,偶数只定义为偶数n=~奇数n
,就像在数学竞赛中所做的那样,所以你的生活不会好很多。我的观点是,你使用了错误的Coq工具来解决你的问题。归纳定义是非常强大的理论工具,奇数
/偶数
是简单的函数,可以更好地定义为函数nat->bool
,偶数只定义为偶数n=~奇数n
,例如在数学竞赛中,引理
和不动点
都只是定理
的别名,请参见,这意味着您也可以使用证明策略定义不动点定义,而无需预先给出明确的证明项。顺便说一句,refine
策略非常有用,如果你想明确给出部分证明项,同时留下漏洞来用策略来填补。实际上,引理和不动点
都只是定理
的别名,请参见,这意味着你也可以用证明策略来定义不动点定义,没有预先给出明确的证明项。顺便说一句,如果您想明确给出部分证明术语,同时留下漏洞以用策略来填补,那么refine
策略非常有用。