diff --git a/common/css/sf.css b/common/css/sf.css index be9fcb10..12d4abc1 100644 --- a/common/css/sf.css +++ b/common/css/sf.css @@ -489,6 +489,9 @@ tr.infrulemiddle hr { color: rgb(0%,0%,0%); } +.nowrap { + white-space: nowrap; +} /* TOC */ diff --git a/common/css/slides.css b/common/css/slides.css index 0f1fc55a..b9d0327d 100644 --- a/common/css/slides.css +++ b/common/css/slides.css @@ -34,5 +34,7 @@ h1.libtitle { line-height: 34px; } - +body { + background: white; +} diff --git a/lf-current/Auto.html b/lf-current/Auto.html index c9afe73c..4a610637 100644 --- a/lf-current/Auto.html +++ b/lf-current/Auto.html @@ -35,7 +35,7 @@
factorial(0) = 1 @@ -952,7 +952,7 @@BasicsCoq 函数式编程
-练习:1 星 (ltb)
+练习:1 星, standard (ltb)
ltb 函数检查自然数间的小于关系,以布尔值表示。 利用前文定义的函数写出该定义,不要使用 Fixpoint 构造新的递归。 (只需前文中的一个函数即可实现定义,但亦可两者皆用。) @@ -973,7 +973,7 @@BasicsCoq 函数式编程
☐-- 其次,我们增加了量词 ∀n:nat,因此我们的定理讨论了所有的 自然数 n。 + 其次,我们增加了量词 ∀ n:nat,因此我们的定理讨论了所有的 自然数 n。 在非形式化的证明中,为了证明这种形式的定理,我们通常会说“假设 存在一个任意自然数 n...”。而在形式化证明中,这是用 intros n 来实现的,它会将量词从证明目标转移到当前假设的上下文中。 @@ -1051,10 +1051,10 @@基于化简的证明
+基于化简的证明
@@ -990,7 +990,7 @@BasicsCoq 函数式编程
-Theorem plus_O_n : ∀ n : nat, 0 + n = n.@@ -1009,7 +1009,7 @@
+Theorem plus_O_n : ∀n : nat, 0 + n = n.
Proof.
intros n. simpl. reflexivity. Qed.
BasicsCoq 函数式编程
-Theorem plus_O_n' : ∀ n : nat, 0 + n = n.@@ -1034,7 +1034,7 @@
+Theorem plus_O_n' : ∀n : nat, 0 + n = n.
Proof.
intros n. reflexivity. Qed.
BasicsCoq 函数式编程
BasicsCoq 函数式编程
-Theorem plus_1_l : ∀ n:nat, 1 + n = S n.@@ -1069,7 +1069,7 @@
+Theorem plus_1_l : ∀n:nat, 1 + n = S n.
Proof.
intros n. reflexivity. Qed.
-Theorem mult_0_l : ∀ n:nat, 0 * n = 0.
+Theorem mult_0_l : ∀n:nat, 0 * n = 0.
Proof.
intros n. reflexivity. Qed.
BasicsCoq 函数式编程
--基于改写的证明
+基于改写的证明
@@ -1077,7 +1077,7 @@BasicsCoq 函数式编程
-Theorem plus_id_example : ∀ n m:nat,@@ -1123,12 +1123,12 @@
+Theorem plus_id_example : ∀n m:nat,
n = m →
n + n = m + m.
BasicsCoq 函数式编程
练习:1 星 (plus_id_exercise)
+练习:1 星, standard (plus_id_exercise)
删除 "Admitted." 并补完证明。-Theorem plus_id_exercise : ∀ n m o : nat,
+Theorem plus_id_exercise : ∀n m o : nat,
n = m → m = o → n + m = m + o.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1152,7 +1152,7 @@BasicsCoq 函数式编程
-Theorem mult_0_plus : ∀ n m : nat,
+Theorem mult_0_plus : ∀n m : nat,
(0 + n) * m = n * m.
Proof.
intros n m.
@@ -1161,11 +1161,11 @@BasicsCoq 函数式编程
-Theorem mult_S_1 : ∀ n m : nat,
+Theorem mult_S_1 : ∀n m : nat,
m = S n →
m * (1 + n) = m * m.
Proof.
@@ -1176,7 +1176,7 @@BasicsCoq 函数式编程
☐-利用情况分析来证明
+利用情况分析来证明
@@ -1187,7 +1187,7 @@BasicsCoq 函数式编程
-Theorem plus_1_neq_0_firsttry : ∀ n : nat,
+Theorem plus_1_neq_0_firsttry : ∀n : nat,
(n + 1) =? 0 = false.
Proof.
intros n.
@@ -1213,7 +1213,7 @@BasicsCoq 函数式编程
-Theorem plus_1_neq_0 : ∀ n : nat,
+Theorem plus_1_neq_0 : ∀n : nat,
(n + 1) =? 0 = false.
Proof.
intros n. destruct n as [| n'] eqn:E.
@@ -1284,7 +1284,7 @@BasicsCoq 函数式编程
-Theorem negb_involutive : ∀ b : bool,-
+Theorem negb_involutive : ∀b : bool,
negb (negb b) = b.
Proof.
intros b. destruct b eqn:E.
@@ -1306,7 +1306,7 @@BasicsCoq 函数式编程
-Theorem andb_commutative : ∀ b c, andb b c = andb c b.diff --git a/lf-current/Bib.v b/lf-current/Bib.v index 56c9d85d..a307c142 100644 --- a/lf-current/Bib.v +++ b/lf-current/Bib.v @@ -32,3 +32,4 @@ *) +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/BibTest.v b/lf-current/BibTest.v index d66c65a1..92479244 100644 --- a/lf-current/BibTest.v +++ b/lf-current/BibTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:15:05 UTC 2019 *) diff --git a/lf-current/Extraction.html b/lf-current/Extraction.html index 6bd783e9..ee0b54ae 100644 --- a/lf-current/Extraction.html +++ b/lf-current/Extraction.html @@ -36,7 +36,7 @@
+Theorem andb_commutative : ∀b c, andb b c = andb c b.
Proof.
intros b c. destruct b eqn:Eb.
- destruct c eqn:Ec.
@@ -1328,7 +1328,7 @@BasicsCoq 函数式编程
-Theorem andb_commutative' : ∀ b c, andb b c = andb c b.+
+Theorem andb_commutative' : ∀b c, andb b c = andb c b.
Proof.
intros b c. destruct b eqn:Eb.
{ destruct c eqn:Ec.
@@ -1347,7 +1347,7 @@BasicsCoq 函数式编程
Theorem andb3_exchange :
- ∀ b c d, andb (andb b c) d = andb (andb b d) c.
+ ∀b c d, andb (andb b c) d = andb (andb b d) c.
Proof.
intros b c d. destruct b eqn:Eb.
- destruct c eqn:Ec.
@@ -1388,7 +1388,7 @@BasicsCoq 函数式编程
-Theorem plus_1_neq_0' : ∀ n : nat,
+Theorem plus_1_neq_0' : ∀n : nat,
(n + 1) =? 0 = false.
Proof.
intros [|n].
@@ -1402,7 +1402,7 @@BasicsCoq 函数式编程
Theorem andb_commutative'' :
- ∀ b c, andb b c = andb c b.
+ ∀b c, andb b c = andb c b.
Proof.
intros [] [].
- reflexivity.
@@ -1413,12 +1413,12 @@BasicsCoq 函数式编程
-练习:2 星 (andb_true_elim2)
+练习:2 星, standard (andb_true_elim2)
证明以下断言, 当使用 destruct 时请用标号标出情况(以及子情况)。-Theorem andb_true_elim2 : ∀ b c : bool,
+Theorem andb_true_elim2 : ∀b c : bool,
andb b c = true → c = true.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1428,11 +1428,11 @@BasicsCoq 函数式编程
-练习:1 星 (zero_nbeq_plus_1)
+练习:1 星, standard (zero_nbeq_plus_1)
-Theorem zero_nbeq_plus_1 : ∀ n : nat,@@ -1583,14 +1583,14 @@
+Theorem zero_nbeq_plus_1 : ∀n : nat,
0 =? (n + 1) = false.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1441,7 +1441,7 @@BasicsCoq 函数式编程
☐-关于记法的更多内容 (可选)
+关于记法的更多内容 (可选)
@@ -1492,7 +1492,7 @@BasicsCoq 函数式编程
-练习:2 星, optional (decreasing)
+练习:2 星, standard, optional (decreasing)
To get a concrete sense of this, find a way to write a sensible Fixpoint definition (of a simple function on numbers, say) that _does_ terminate on all inputs, but that Coq will reject because @@ -1537,7 +1537,7 @@BasicsCoq 函数式编程
☐ -练习:1 星 (indentity_fn_applied_twice)
+练习:1 星, standard (indentity_fn_applied_twice)
用你学过的策略证明以下关于布尔函数的定理。Theorem identity_fn_applied_twice :@@ -1564,7 +1564,7 @@
- ∀ (f : bool → bool),
- (∀ (x : bool), f x = x) →
- ∀ (b : bool), f (f b) = b.
+ ∀(f : bool → bool),
+ (∀(x : bool), f x = x) →
+ ∀(b : bool), f (f b) = b.
Proof.
(* 请在此处解答 *) Admitted.
BasicsCoq 函数式编程
-练习:1 星 (negation_fn_applied_twice)
+练习:1 星, standard (negation_fn_applied_twice)
现在声明并证明定理 negation_fn_applied_twice,与上一个类似, 但是第二个前提说明函数 f 有 f x = negb x 的性质。BasicsCoq 函数式编程
-练习:3 星, optional (andb_eq_orb)
+练习:3 星, standard, optional (andb_eq_orb)
请证明下列定理。(提示:此定理的证明可能会有点棘手,取决于你如何证明它。 或许你需要先证明一到两个辅助引理。或者,你要记得未必要同时引入所有前提。)Theorem andb_eq_orb :diff --git a/lf-current/Basics.v b/lf-current/Basics.v index e21b949a..ab27e2bd 100644 --- a/lf-current/Basics.v +++ b/lf-current/Basics.v @@ -6,7 +6,7 @@ ### 请勿公开发布习题解答 ### ############################## - (原因见 [Preface]。) + (原因见 [Preface]。) *) (* ################################################################# *) @@ -18,7 +18,6 @@ “函数式编程”中“函数式”一词的含义之一。程序与简单数学对象之间这种直接的联系, 同时支撑了对程序行为进行形式化证明的正确性以及非形式化论证的可靠性。 - 函数式编程中“函数式”一词的另一个含义是它强调把函数(或方法) 作为_'一等'_的值 —— 即,这类值可以作为参数传递给其它函数,可以作为结果返回, 也可以包含在数据结构中等等。这种将函数当做数据的方式, @@ -221,8 +220,9 @@ Proof. simpl. reflexivity. Qed. 我们会在练习中用它来表示留给你的部分。你的练习作业就是将 [Admitted] 替换为具体的证明。 *) -(** **** 练习:1 星 (nandb) *) -(** 移除“[Admitted.]”并补完以下函数的定义,然后确保下列每一个 [Example] +(** **** 练习:1 星, standard (nandb) + + 移除“[Admitted.]”并补完以下函数的定义,然后确保下列每一个 [Example] 中的断言都能被 Coq 验证通过。(即仿照上文 [orb] 测试的模式补充证明。) 此函数应在两个输入中包含 [false] 时返回 [true] 。 *) @@ -239,8 +239,9 @@ Example test_nandb4: (nandb true true) = false. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (andb3) *) -(** 与此前相同,完成下面的 [andb3] 函数。 +(** **** 练习:1 星, standard (andb3) + + 与此前相同,完成下面的 [andb3] 函数。 此函数应在所有输入均为 [true] 时返回 [true],否则返回 [false]。 *) Definition andb3 (b1:bool) (b2:bool) (b3:bool) : bool @@ -299,8 +300,9 @@ Inductive color : Type := 每个归纳定义的类型(如 [day]、[bool]、[rgb]、[color] 等)包含一个由构造子 (如 [red]、[primary]、[true]、[false]、[monday] 等)构建的 - _'构造子表达式'_ 的集合。 *) -(** [rgb] 和 [color] 的定义描述了如何构造这两个集合中的元素(即表达式): + _'构造子表达式'_ 的集合。 + + [rgb] 和 [color] 的定义描述了如何构造这两个集合中的元素(即表达式): - [red]、[green] 和 [blue] 是 [rgb] 的构造子; - [black]、[white] 和 [primary] 是 [color] 的构造子; @@ -343,7 +345,7 @@ Definition isred (c : color) : bool := a datatype [bit] that resembles [bool] (using the constructors [B0] and [B1] for the two possible bit values), and then define the datatype [nybble], which is essentially - a tuple of four bits.*) + a tuple of four bits. *) Inductive bit : Type := | B0 @@ -359,8 +361,7 @@ Check (bits B1 B0 B1 B0). Unwrapping can be done by pattern-matching, as in the [all_zero] function which tests a nybble to see if all its bits are O. Note that we are using underscore (_) as a _wildcard pattern_ to - avoid inventing variable names that will not be used.*) - + avoid inventing variable names that will not be used. *) Definition all_zero (nb : nybble) : bool := match nb with @@ -451,7 +452,6 @@ Inductive nat : Type := 它们只是我们能用来写下数字的两个不同的记号(以及一个说明了任何 [nat] 都能写成一串 [S] 后跟一个 [O] 的规则)。如果你喜欢,完全可以将同样的定义写成: *) - Inductive nat' : Type := | stop | tick (foo : nat'). @@ -578,8 +578,9 @@ Fixpoint exp (base power : nat) : nat := | S p => mult base (exp base p) end. -(** **** 练习:1 星 (factorial) *) -(** 回想一下标准的阶乘函数: +(** **** 练习:1 星, standard (factorial) + + 回想一下标准的阶乘函数: factorial(0) = 1 factorial(n) = n * factorial(n-1) (if n>0) @@ -663,8 +664,9 @@ Notation "x <=? y" := (leb x y) (at level 70) : nat_scope. Example test_leb3': (4 <=? 2) = false. Proof. simpl. reflexivity. Qed. -(** **** 练习:1 星 (ltb) *) -(** [ltb] 函数检查自然数间的小于关系,以布尔值表示。 +(** **** 练习:1 星, standard (ltb) + + [ltb] 函数检查自然数间的小于关系,以布尔值表示。 利用前文定义的函数写出该定义,不要使用 [Fixpoint] 构造新的递归。 (只需前文中的一个函数即可实现定义,但亦可两者皆用。) *) @@ -787,8 +789,9 @@ Proof. 若要从右往左改写,可以使用 [rewrite <-]。在上面的证明中试一试这种改变, 看看 Coq 的反应有何不同。) *) -(** **** 练习:1 星 (plus_id_exercise) *) -(** 删除 "[Admitted.]" 并补完证明。 *) +(** **** 练习:1 星, standard (plus_id_exercise) + + 删除 "[Admitted.]" 并补完证明。 *) Theorem plus_id_exercise : forall n m o : nat, n = m -> m = o -> n + m = m + o. @@ -814,15 +817,16 @@ Proof. rewrite -> plus_O_n. reflexivity. Qed. -(** **** 练习:2 星 (mult_S_1) *) +(** **** 练习:2 星, standard (mult_S_1) *) Theorem mult_S_1 : forall n m : nat, m = S n -> m * (1 + n) = m * m. Proof. (* 请在此处解答 *) Admitted. -(* (注意,该命题可用 [rewrite] 以外的策略证明,不过请使用 [rewrite] 来做练习。) *) -(** [] *) +(* (注意,该命题可用 [rewrite] 以外的策略证明,不过请使用 [rewrite] 来做练习。) + + [] *) (* ################################################################# *) (** * 利用情况分析来证明 *) @@ -878,7 +882,6 @@ Proof. documentation, as they can help keep you oriented when working with the subgoals.) - 第二行和第三行中的 [-] 符号叫做_'标号'_,它标明了每个生成的子目标所对应的证明部分。 (译注:此处的“标号”应理解为一个项目列表中每个 _'条目'_ 前的小标记,如 ‣ 或 •。) 标号后面的代码是一个子目标的完整证明。在本例中,每个子目标都简单地使用 @@ -904,7 +907,6 @@ Proof. [destruct] 策略可用于任何归纳定义的数据类型。比如,我们接下来会用它来证明 布尔值的取反是对合(Involutive)的 —— 即,取反是自身的逆运算。 *) - Theorem negb_involutive : forall b : bool, negb (negb b) = b. Proof. @@ -1004,8 +1006,9 @@ Proof. - reflexivity. Qed. -(** **** 练习:2 星 (andb_true_elim2) *) -(** 证明以下断言, 当使用 [destruct] 时请用标号标出情况(以及子情况)。 *) +(** **** 练习:2 星, standard (andb_true_elim2) + + 证明以下断言, 当使用 [destruct] 时请用标号标出情况(以及子情况)。 *) Theorem andb_true_elim2 : forall b c : bool, andb b c = true -> c = true. @@ -1013,7 +1016,7 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (zero_nbeq_plus_1) *) +(** **** 练习:1 星, standard (zero_nbeq_plus_1) *) Theorem zero_nbeq_plus_1 : forall n : nat, 0 =? (n + 1) = false. Proof. @@ -1076,8 +1079,9 @@ Fixpoint plus' (n : nat) (m : nat) : nat := 然而,由于 Coq 的“递减分析”不是非常精致, 因此有时必须用一点不同寻常的方式来编写函数。 *) -(** **** 练习:2 星, optional (decreasing) *) -(** To get a concrete sense of this, find a way to write a sensible +(** **** 练习:2 星, standard, optional (decreasing) + + To get a concrete sense of this, find a way to write a sensible [Fixpoint] definition (of a simple function on numbers, say) that _does_ terminate on all inputs, but that Coq will reject because of this restriction. (If you choose to turn in this optional @@ -1085,8 +1089,9 @@ Fixpoint plus' (n : nat) (m : nat) : nat := out your solution so that it doesn't cause Coq to reject the whole file!) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * 更多练习 *) @@ -1096,8 +1101,9 @@ Fixpoint plus' (n : nat) (m : nat) : nat := [make BasicsTest.vo] in a terminal and check its output to make sure you didn't miss anything. *) -(** **** 练习:1 星 (indentity_fn_applied_twice) *) -(** 用你学过的策略证明以下关于布尔函数的定理。 *) +(** **** 练习:1 星, standard (indentity_fn_applied_twice) + + 用你学过的策略证明以下关于布尔函数的定理。 *) Theorem identity_fn_applied_twice : forall (f : bool -> bool), @@ -1108,8 +1114,9 @@ Proof. (** [] *) -(** **** 练习:1 星 (negation_fn_applied_twice) *) -(** 现在声明并证明定理 [negation_fn_applied_twice],与上一个类似, +(** **** 练习:1 星, standard (negation_fn_applied_twice) + + 现在声明并证明定理 [negation_fn_applied_twice],与上一个类似, 但是第二个前提说明函数 [f] 有 [f x = negb x] 的性质。 *) (* 请在此处解答 *) @@ -1122,8 +1129,9 @@ From Coq Require Export String. Definition manual_grade_for_negation_fn_applied_twice : option (nat*string) := None. (** [] *) -(** **** 练习:3 星, optional (andb_eq_orb) *) -(** 请证明下列定理。(提示:此定理的证明可能会有点棘手,取决于你如何证明它。 +(** **** 练习:3 星, standard, optional (andb_eq_orb) + + 请证明下列定理。(提示:此定理的证明可能会有点棘手,取决于你如何证明它。 或许你需要先证明一到两个辅助引理。或者,你要记得未必要同时引入所有前提。) *) Theorem andb_eq_orb : @@ -1135,8 +1143,9 @@ Proof. (** [] *) -(** **** 练习:3 星 (binary) *) -(** We can generalize our unary representation of natural numbers to +(** **** 练习:3 星, standard (binary) + + We can generalize our unary representation of natural numbers to the more efficient binary representation by treating a binary number as a sequence of constructors [A] and [B] (representing 0s and 1s), terminated by a [Z]. For comparison, in the unary @@ -1189,9 +1198,4 @@ Fixpoint bin_to_nat (m:bin) : nat Definition manual_grade_for_binary : option (nat*string) := None. (** [] *) -(** NEW NAME: The next line is a temporary hack to allow - [zero_nbeq_plus_1] to be used as a synonym for the "more - up-to-date" (i.e., consistent with the Coq library) name - [zero_neqb_plus_1]... *) -Notation zero_neqb_plus_1 := zero_nbeq_plus_1 (only parsing). - +(* Sat Jan 26 15:14:45 UTC 2019 *) diff --git a/lf-current/BasicsTest.v b/lf-current/BasicsTest.v index a363cfb1..e4bc6027 100644 --- a/lf-current/BasicsTest.v +++ b/lf-current/BasicsTest.v @@ -191,3 +191,5 @@ idtac "MANUAL". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:14:47 UTC 2019 *) diff --git a/lf-current/Bib.html b/lf-current/Bib.html index baf587cb..e4c6af6a 100644 --- a/lf-current/Bib.html +++ b/lf-current/Bib.html @@ -36,7 +36,7 @@
- ∀ (b c : bool),
+ ∀(b c : bool),
(andb b c = orb b c) →
b = c.
Proof.
@@ -1601,7 +1601,7 @@BasicsCoq 函数式编程
-练习:3 星 (binary)
+练习:3 星, standard (binary)
We can generalize our unary representation of natural numbers to the more efficient binary representation by treating a binary number as a sequence of constructors A and B (representing 0s @@ -1671,16 +1671,9 @@BasicsCoq 函数式编程
☐ --- - NEW NAME: The next line is a temporary hack to allow - zero_nbeq_plus_1 to be used as a synonym for the "more - up-to-date" (i.e., consistent with the Coq library) name - zero_neqb_plus_1... --Notation zero_neqb_plus_1 := zero_nbeq_plus_1 (only parsing).
+ +(* Sat Jan 26 15:14:45 UTC 2019 *)
Bib参考文献
-本卷中出现的引用
+本卷中出现的引用
@@ -81,6 +81,10 @@Bib参考文献
++ +(* Sat Jan 26 15:14:46 UTC 2019 *)
Extraction从 Coq 中提取 ML
基本的提取方式
+基本的提取方式
@@ -59,9 +59,9 @@Extraction从 Coq 中提取 ML
-Require Import Coq.Arith.Arith.@@ -80,7 +80,7 @@
-Require Import Coq.Init.Nat.
-Require Import Coq.Arith.EqNat.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Init.Nat.
+From Coq Require Import Arith.EqNat.
From LF Require Import ImpCEvalFun.
Extraction从 Coq 中提取 ML
-控制提取特定的类型
+控制提取特定的类型
@@ -154,7 +154,7 @@Extraction从 Coq 中提取 ML
-一个完整的示例
+一个完整的示例
@@ -193,8 +193,7 @@Extraction从 Coq 中提取 MLFrom LF Require Import Imp.
From LF Require Import ImpParser.
From LF Require Import Maps.
-Definition empty_state := { --> 0 }.
-Extraction "imp.ml" empty_state ceval_step parse.
+Extraction "imp.ml" empty_st ceval_step parse.
@@ -212,7 +211,7 @@Extraction从 Coq 中提取 ML diff --git a/lf-current/Extraction.v b/lf-current/Extraction.v index ba499373..520a73d8 100644 --- a/lf-current/Extraction.v +++ b/lf-current/Extraction.v @@ -14,9 +14,9 @@ Extraction Language OCaml. (** 现在我们将待提取的定义加载到 Coq 环境中。你可以直接写出定义, 也可以从其它模块中加载。 *) -Require Import Coq.Arith.Arith. -Require Import Coq.Init.Nat. -Require Import Coq.Arith.EqNat. +From Coq Require Import Arith.Arith. +From Coq Require Import Init.Nat. +From Coq Require Import Arith.EqNat. From LF Require Import ImpCEvalFun. (** 最后,我们来指定需要提取的定义,以及用于保存提取结果的文件名。 *) @@ -91,8 +91,7 @@ From LF Require Import Imp. From LF Require Import ImpParser. From LF Require Import Maps. -Definition empty_state := { --> 0 }. -Extraction "imp.ml" empty_state ceval_step parse. +Extraction "imp.ml" empty_st ceval_step parse. (** 现在我们来运行一下生成的 Imp 求值器。首先你应该阅览一下 [impdriver.ml](这并非从某个 Coq 源码提取而来,它是手写的。) @@ -116,3 +115,5 @@ Extraction "imp.ml" empty_state ceval_step parse. (** 有关提取的更多详情见_'软件基础'_第三卷_'已验证的函数式算法'_中的 Extract 一章。 *) + +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/ExtractionTest.v b/lf-current/ExtractionTest.v index f7cb4fb9..09813245 100644 --- a/lf-current/ExtractionTest.v +++ b/lf-current/ExtractionTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:15:03 UTC 2019 *) diff --git a/lf-current/Imp.html b/lf-current/Imp.html index f80b75fb..b8ca84d8 100644 --- a/lf-current/Imp.html +++ b/lf-current/Imp.html @@ -36,7 +36,7 @@
Imp简单的指令式程序
- 在本章中,我们会更加认真地看待如何用 Coq 来研究自身以外的有趣的东西。 + 在本章中,我们会更加认真地看待如何用 Coq 来研究其它东西。 我们的案例研究是一个名为 Imp 的简单的指令式编程语言, 它包含了传统主流语言(如 C 和 Java)的一小部分核心片段。下面是一个用 Imp 编写的常见数学函数: @@ -46,7 +46,7 @@Imp简单的指令式程序
Z ::= X;;
Y ::= 1;;
- WHILE ! (Z = 0) DO
+ WHILE ~(Z = 0) DO
Y ::= Y * Z;;
Z ::= Z - 1
END @@ -64,18 +64,19 @@Imp简单的指令式程序
Set Warnings "-notation-overridden,-parsing".
-Require Import Coq.Bool.Bool.
-Require Import Coq.Init.Nat.
-Require Import Coq.Arith.Arith.
-Require Import Coq.Arith.EqNat.
-Require Import Coq.omega.Omega.
-Require Import Coq.Lists.List.
+From Coq Require Import Bool.Bool.
+From Coq Require Import Init.Nat.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Arith.EqNat.
+From Coq Require Import omega.Omega.
+From Coq Require Import Lists.List.
+From Coq Require Import Strings.String.
Import ListNotations.
From LF Require Import Maps.
@@ -115,7 +116,7 @@@@ -157,7 +158,7 @@Imp简单的指令式程序
在本章中,我们省略了大部分从程序员实际编写的具体语法到其抽象语法树的翻译 - 例如,它会将字符串 "1+2*3" 翻译成如下 AST: + 例如,它会将字符串 "1 + 2 * 3" 翻译成如下 AST:- 可选的章节 ImpParser 中开发了一个简单的词法分析器和解析器的实现, + 可选的章节 ImpParser 中开发了一个简单的词法分析器和解析器, 它可以进行这种翻译。你无需通过理解该章来理解本章, 但如果你没有上过涵盖这些技术的课程(例如编译器课程),可能想要略读一下该章节。@@ -124,7 +125,7 @@Imp简单的指令式程序
@@ -143,8 +144,8 @@Imp简单的指令式程序 | false
| a = a
| a ≤ a
- | not b
- | b and b + | ¬b
+ | b && bImp简单的指令式程序
- BNF 是非形式化的 — 例如,它给出了表达式表面上的语法的建议 - (例如加法运算写作 + 且它是一个中缀符),而没有指定词法分析和解析的其它方面 + (例如加法运算符写作中缀的 +),而没有指定词法分析和解析的其它方面 (如 +、- 和 * 的相对优先级,用括号来明确子表达式的分组等)。 在实现编译器时,需要一些附加的信息(以及人类的智慧) 才能将此描述转换成形式化的定义。 @@ -170,14 +171,14 @@
-Imp简单的指令式程序
- 另一方面 BNF 版本则更加清晰易读。它的非形式化使其更加灵活, +
- 反之,BNF 版本则更加清晰易读。它的非形式化使其更加灵活, 在讨论和在黑板上书写时,它有很大的优势, 此时传达一般的概念要比精确定下所有细节更加重要。
@@ -190,7 +191,7 @@确实,存在很多种类似 BNF 的记法,人们可以随意使用它们, - 而无需关心具体使用了哪种 BNF 的形式,因为没有必要: + 而无需关心具体使用了哪种 BNF,因为没有必要: 大致的理解是非常重要的。Imp简单的指令式程序
-求值
+求值
@@ -201,9 +202,9 @@Imp简单的指令式程序 Fixpoint aeval (a : aexp) : nat :=
match a with
| ANum n ⇒ n
- | APlus a1 a2 ⇒ (aeval a1) + (aeval a2)
- | AMinus a1 a2 ⇒ (aeval a1) - (aeval a2)
- | AMult a1 a2 ⇒ (aeval a1) * (aeval a2)
+ | APlus a1 a2 ⇒ (aeval a1) + (aeval a2)
+ | AMinus a1 a2 ⇒ (aeval a1) - (aeval a2)
+ | AMult a1 a2 ⇒ (aeval a1) * (aeval a2)
end.
Example test_aeval1:
aeval (APlus (ANum 2) (ANum 2)) = 4.
@@ -230,28 +231,23 @@Imp简单的指令式程序
-优化
+优化
我们尚未定义太多东西,不过从这些定义出发,已经能前进不少了。 假设我们定义了一个接收算术表达式并对它稍微进行化简的函数,即将所有的 - 0+e(如 (APlus (ANum 0) e)化简为 e。 + 0 + e(如 (APlus (ANum 0) e)化简为 e。Fixpoint optimize_0plus (a:aexp) : aexp :=@@ -277,8 +273,10 @@
match a with
- | ANum n ⇒
- ANum n
- | APlus (ANum 0) e2 ⇒
- optimize_0plus e2
- | APlus e1 e2 ⇒
- APlus (optimize_0plus e1) (optimize_0plus e2)
- | AMinus e1 e2 ⇒
- AMinus (optimize_0plus e1) (optimize_0plus e2)
- | AMult e1 e2 ⇒
- AMult (optimize_0plus e1) (optimize_0plus e2)
+ | ANum n ⇒ ANum n
+ | APlus (ANum 0) e2 ⇒ optimize_0plus e2
+ | APlus e1 e2 ⇒ APlus (optimize_0plus e1) (optimize_0plus e2)
+ | AMinus e1 e2 ⇒ AMinus (optimize_0plus e1) (optimize_0plus e2)
+ | AMult e1 e2 ⇒ AMult (optimize_0plus e1) (optimize_0plus e2)
end.
Imp简单的指令式程序
-Theorem optimize_0plus_sound: ∀ a,
+Theorem optimize_0plus_sound: ∀a,
aeval (optimize_0plus a) = aeval a.
++Proof.+
intros a. induction a.
- (* ANum *) reflexivity.
@@ -300,9 +298,10 @@Imp简单的指令式程序 - (* AMult *)
simpl. rewrite IHa1. rewrite IHa2. reflexivity. Qed.
-try 泛策略
+try 泛策略
如果 T 是一个策略,那么 try T 是一个和 T 一样的策略,只是如果 - T 失败的话,try T 就会成功地什么也不做(而非失败)。 + T 失败的话,try T 就会成功地什么也不做(而非失败)。-Theorem silly1 : ∀ ae, aeval ae = aeval ae.@@ -353,7 +352,7 @@
-Proof. try reflexivity. (* 它和 reflexivity 做的一样 *) Qed.
-Theorem silly2 : ∀ (P : Prop), P → P.
+Theorem silly1 : ∀ae, aeval ae = aeval ae.
+Proof. try reflexivity. (* 它和 reflexivity 做的一样。 *) Qed.
+Theorem silly2 : ∀(P : Prop), P → P.
Proof.
intros P HP.
- try reflexivity. (* 和 reflexivity 失败时一样 *)
- apply HP. (* 我们仍然可以换种方式来结束此证明 *)
+ try reflexivity. (* 和 reflexivity 失败时一样。 *)
+ apply HP. (* 我们仍然可以换种方式来结束此证明。 *)
Qed.
Imp简单的指令式程序
-Lemma foo : ∀ n, 0 <=? n = true.
+Lemma foo : ∀n, 0 <=? n = true.
Proof.
intros.
- destruct n eqn:E.
+ destruct n.
(* 会产生两个执行过程相同的子目标... *)
- (* n=0 *) simpl. reflexivity.
- (* n=Sn' *) simpl. reflexivity.
@@ -380,7 +379,7 @@Imp简单的指令式程序
-Lemma foo' : ∀ n, 0 <=? n = true.
+Lemma foo' : ∀n, 0 <=? n = true.
Proof.
intros.
(* destruct 解构当前子目标 *)
@@ -397,7 +396,7 @@Imp简单的指令式程序
-Theorem optimize_0plus_sound': ∀ a,
+Theorem optimize_0plus_sound': ∀a,
aeval (optimize_0plus a) = aeval a.
Proof.
intros a.
@@ -493,7 +492,7 @@Imp简单的指令式程序
-Theorem optimize_0plus_sound'': ∀ a,
+Theorem optimize_0plus_sound'': ∀a,
aeval (optimize_0plus a) = aeval a.
Proof.
intros a.
@@ -511,7 +510,7 @@Imp简单的指令式程序
-repeat 泛策略
+repeat 泛策略
@@ -577,11 +576,11 @@Imp简单的指令式程序 那么重复 T 会永远循环(例如 repeat simpl 会一直循环,因为 simpl 总是会成功)。虽然 Coq 的主语言 Gallina 中的求值保证会终止, 然而策略却不会!然而这并不会影响 Coq 的逻辑一致性,因为 repeat - 和其它策略的工作就是指导 Coq 去构造证明;如果构造过程发散(即不终止), + 和其它策略的工作就是指导 Coq 去构造证明;如果构造过程发散(即不停机), 那就意味着我们构造证明失败,而非构造出了错误的证明。
-练习:3 星 (optimize_0plus_b_sound)
+练习:3 星, standard (optimize_0plus_b_sound)
由于 optimize_0plus 变换不会改变 aexp 的值, 因此我们可以将它应用到所有出现在 bexp 中的 aexp 上而不改变 bexp 的值。请编写一个对 bexp 执行此变换的函数,并证明它的可靠性。 @@ -591,7 +590,7 @@Imp简单的指令式程序 Fixpoint optimize_0plus_b (b : bexp) : bexp
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem optimize_0plus_b_sound : ∀ b,
+Theorem optimize_0plus_b_sound : ∀b,
beval (optimize_0plus_b b) = beval b.
Proof.
(* 请在此处解答 *) Admitted.
@@ -601,7 +600,7 @@Imp简单的指令式程序
-练习:4 星, optional (optimizer)
+练习:4 星, standard, optional (optimize)
设计练习:optimize_0plus 函数只是众多算术和布尔表达式优化的方法之一。 请编写一个更加聪明的优化器并证明它的正确性。(最容易的方法就是从小处着手: 一开始只添加单个简单的优化并证明它的正确性,然后逐渐增加其它更有趣的优化。) @@ -614,7 +613,7 @@Imp简单的指令式程序 ☐
-Example silly_presburger_example : ∀ m n o p,
+Example silly_presburger_example : ∀m n o p,
m + n ≤ n + o ∧ o + 3 = p + 3 →
m ≤ p.
Proof.
@@ -710,11 +709,11 @@Imp简单的指令式程序
-(注意本文件顶部 Require Import Coq.omega.Omega.。) +(注意本文件顶部 From Coq Require Import omega.Omega.。)-更多方便的策略
+更多方便的策略
@@ -729,14 +728,14 @@Imp简单的指令式程序 -
subst x:在上下文中查找假设 x = e 或 e = x, + subst x:对于变量 x,在上下文中查找假设 x = e 或 e = x, 将整个上下文和当前目标中的所有 x 替换为 e 并清除该假设。 -subst:替换掉所有形如 x = e 或 e = x 的假设。 + subst:替换掉所有形如 x = e 或 e = x 的假设(其中 x 为变量)。 @@ -773,11 +772,11 @@Imp简单的指令式程序
- 我们之后会看到它们的例子。 + 我们之后会看到所有它们的例子。-+求值作为关系
+求值作为关系
@@ -803,9 +802,39 @@Imp简单的指令式程序 | E_AMult (e1 e2: aexp) (n1 n2: nat) :
aevalR e1 n1 →
aevalR e2 n2 →
+ aevalR (AMult e1 e2) (n1 * n2).
+Module TooHardToRead.
+(* A small notational aside. We would previously have written the
+ definition of aevalR like this, with explicit names for the
+ hypotheses in each case: *)
+Inductive aevalR : aexp → nat → Prop :=
+ | E_ANum n :
+ aevalR (ANum n) n
+ | E_APlus (e1 e2: aexp) (n1 n2: nat)
+ (H1 : aevalR e1 n1)
+ (H2 : aevalR e2 n2) :
+ aevalR (APlus e1 e2) (n1 + n2)
+ | E_AMinus (e1 e2: aexp) (n1 n2: nat)
+ (H1 : aevalR e1 n1)
+ (H2 : aevalR e2 n2) :
+ aevalR (AMinus e1 e2) (n1 - n2)
+ | E_AMult (e1 e2: aexp) (n1 n2: nat)
+ (H1 : aevalR e1 n1)
+ (H2 : aevalR e2 n2) :
aevalR (AMult e1 e2) (n1 * n2).
+Instead, we've chosen to leave the hypotheses anonymous, just + giving their types. This style gives us less control over the + names that Coq chooses during proofs involving aevalR, but it + makes the definition itself quite a bit lighter. +++ +End TooHardToRead.+
+如果 aevalR 有中缀记法的话会很方便。我们用 e \\ n 表示算术表达式 e 求值为 n。 @@ -830,22 +859,22 @@Imp简单的指令式程序
-Reserved Notation "e '\\' n" (at level 50, left associativity).
+Reserved Notation "e '\\' n" (at level 90, left associativity).
Inductive aevalR : aexp → nat → Prop :=
- | E_ANum n :
+ | E_ANum (n : nat) :
(ANum n) \\ n
- | E_APlus e1 e2 n1 n2 :
+ | E_APlus (e1 e2 : aexp) (n1 n2 : nat) :
(e1 \\ n1) → (e2 \\ n2) → (APlus e1 e2) \\ (n1 + n2)
- | E_AMinus e1 e2 n1 n2 :
+ | E_AMinus (e1 e2 : aexp) (n1 n2 : nat) :
(e1 \\ n1) → (e2 \\ n2) → (AMinus e1 e2) \\ (n1 - n2)
- | E_AMult e1 e2 n1 n2 :
+ | E_AMult (e1 e2 : aexp) (n1 n2 : nat) :
(e1 \\ n1) → (e2 \\ n2) → (AMult e1 e2) \\ (n1 * n2)
where "e '\\' n" := (aevalR e n) : type_scope.
-推理规则的记法
+推理规则的记法
@@ -860,7 +889,7 @@Imp简单的指令式程序
- | E_APlus : ∀ (e1 e2: aexp) (n1 n2: nat),+
+ | E_APlus : ∀(e1 e2: aexp) (n1 n2: nat),
aevalR e1 n1 →
aevalR e2 n2 →
aevalR (APlus e1 e2) (n1 + n2) @@ -964,10 +993,38 @@Imp简单的指令式程序
+ + +练习:1 星, standard, optional (beval_rules)
+ 下面是 Coq 中 beval 函数的定义: + ++ ++ Fixpoint beval (e : bexp) : bool :=+ 请用推理规则记法将布尔求值的定义写成关系的形式。
+ match e with
+ | BTrue ⇒ true
+ | BFalse ⇒ false
+ | BEq a1 a2 ⇒ (aeval a1) =? (aeval a2)
+ | BLe a1 a2 ⇒ (aeval a1) <=? (aeval a2)
+ | BNot b1 ⇒ negb (beval b1)
+ | BAnd b1 b2 ⇒ andb (beval b1) (beval b2)
+ end. ++ ++(* 请在此处解答 *)+ +☐
+(* 请勿修改下面这一行: *)
+Definition manual_grade_for_beval_rules : option (nat*string) := None.
+-Theorem aeval_iff_aevalR : ∀ a n,
+Theorem aeval_iff_aevalR : ∀a n,
(a \\ n) ↔ aeval a = n.
--++Proof.
split.
- - (* -> *)
+ - (* -> *)
intros H.
induction H; simpl.
+ (* E_ANum *)
@@ -1019,12 +1076,12 @@Imp简单的指令式程序
-Theorem aeval_iff_aevalR' : ∀ a n,
+Theorem aeval_iff_aevalR' : ∀a n,
(a \\ n) ↔ aeval a = n.
Proof.
(* 课上已完成 *)
split.
- - (* -> *)
+ - (* -> *)
intros H; induction H; subst; reflexivity.
- (* <- *)
generalize dependent n.
@@ -1034,7 +1091,7 @@Imp简单的指令式程序
@@ -1042,7 +1099,7 @@Imp简单的指令式程序 Inductive bevalR: bexp → bool → Prop :=
(* 请在此处解答 *)
.
-Lemma beval_iff_bevalR : ∀ b bv,
+Lemma beval_iff_bevalR : ∀b bv,
bevalR b bv ↔ beval b = bv.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1055,7 +1112,7 @@Imp简单的指令式程序
-例如,假设我们想要用除法运算来扩展算术运算: +例如,假设我们想要用除法来扩展算术运算:@@ -1091,17 +1148,17 @@Imp简单的指令式程序
Reserved Notation "e '\\' n"
- (at level 50, left associativity).
+ (at level 90, left associativity).
Inductive aevalR : aexp → nat → Prop :=
- | E_ANum : ∀ (n:nat),
+ | E_ANum (n : nat) :
(ANum n) \\ n
- | E_APlus : ∀ (a1 a2: aexp) (n1 n2 : nat),
+ | E_APlus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (APlus a1 a2) \\ (n1 + n2)
- | E_AMinus : ∀ (a1 a2: aexp) (n1 n2 : nat),
+ | E_AMinus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (AMinus a1 a2) \\ (n1 - n2)
- | E_AMult : ∀ (a1 a2: aexp) (n1 n2 : nat),
+ | E_AMult (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (AMult a1 a2) \\ (n1 * n2)
- | E_ADiv : ∀ (a1 a2: aexp) (n1 n2 n3: nat),
+ | E_ADiv (a1 a2 : aexp) (n1 n2 n3 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (n2 > 0) →
(mult n2 n3 = n1) → (ADiv a1 a2) \\ n3
@@ -1111,16 +1168,16 @@Imp简单的指令式程序
-假设,我们转而想要用非确定性的数值生成器 any 来扩展算术运算, +假设我们想要用非确定性的数值生成器 any 来扩展算术运算, 该生成器会在求值时产生任何数。(注意,这不同于在所有可能的数值中作出 - 概率上的选择 — 我们没有为结果指定任何具体的分布,只是说了 + 概率上的选择 — 我们没有为结果指定任何具体的概率分布,只是说了 可能的结果。)-Reserved Notation "e '\\' n" (at level 50, left associativity).
+Reserved Notation "e '\\' n" (at level 90, left associativity).
Inductive aexp : Type :=
- | AAny (* <--- NEW *)
+ | AAny (* <--- NEW *)
| ANum (n : nat)
| APlus (a1 a2 : aexp)
| AMinus (a1 a2 : aexp)
@@ -1134,15 +1191,15 @@Imp简单的指令式程序
Inductive aevalR : aexp → nat → Prop :=
- | E_Any : ∀ (n:nat),
- AAny \\ n (* <--- new *)
- | E_ANum : ∀ (n:nat),
+ | E_Any (n : nat) :
+ AAny \\ n (* <--- NEW *)
+ | E_ANum (n : nat) :
(ANum n) \\ n
- | E_APlus : ∀ (a1 a2: aexp) (n1 n2 : nat),
+ | E_APlus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (APlus a1 a2) \\ (n1 + n2)
- | E_AMinus : ∀ (a1 a2: aexp) (n1 n2 : nat),
+ | E_AMinus (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (AMinus a1 a2) \\ (n1 - n2)
- | E_AMult : ∀ (a1 a2: aexp) (n1 n2 : nat),
+ | E_AMult (a1 a2 : aexp) (n1 n2 : nat) :
(a1 \\ n1) → (a2 \\ n2) → (AMult a1 a2) \\ (n1 * n2)
where "a '\\' n" := (aevalR a n) : type_scope.
@@ -1151,7 +1208,7 @@Imp简单的指令式程序
这时你可能会问:默认情况下应该使用哪种风格? - 上面的例子表明关系式定义从根本上要比函数式的更加强大。 + 我们刚看到的例子表明关系式的定义反而比函数式的更加有用。 对于这种定义的东西不太容易用函数表达,或者确实不是函数的情况来说, 明显别无选择。但如果两种风格均可行呢? @@ -1180,7 +1237,7 @@Imp简单的指令式程序
- 此外,函数还可以直“提取为”OCaml 或 Haskell 的可执行代码。 + 此外,函数还可以直接从 Gallina“提取”出 OCaml 或 Haskell 的可执行代码。最终,选择视具体情况而定,或者只是品味问题。确实,在大型的 Coq @@ -1189,7 +1246,7 @@Imp简单的指令式程序
-语法
+语法
@@ -1232,7 +1289,7 @@Imp简单的指令式程序 Inductive aexp : Type :=
| ANum (n : nat)
- | AId (x : string) (* <----- 新增 *)
+ | AId (x : string) (* <--- 新增 *)
| APlus (a1 a2 : aexp)
| AMinus (a1 a2 : aexp)
| AMult (a1 a2 : aexp).
@@ -1269,45 +1326,64 @@Imp简单的指令式程序
-记法
+记法
要让 Imp 程序更易读写,我们引入了一些记法和隐式转换(Coercion)。- 在本章中你无需理解以下声明具体做了些什么。简言而之,Coq 中的 Coercion + 你无需理解以下声明具体做了些什么。简言而之,Coq 中的 Coercion 声明规定了一个函数(或构造子)可以被类型系统隐式地用于将一个输入类型的值 转换成输出类型的值。例如,AId 的转换声明在需要一个 aexp 时直接使用普通的字符串,该字符串会被隐式地用 AId 来包装。下列记法在具体的记法作用域中声明,以避免与其它符号相同的解释相冲突。 - 同样,你也暂时无需理解其中的细节。 + 同样,你暂时也无需理解其中的细节,但要意识到到我们为 +、-、*、=、≤ + 等运算符定义了新的解释十分重要。-Coercion AId : string >-> aexp.
-Coercion ANum : nat >-> aexp.
-Definition bool_to_bexp (b: bool) : bexp :=
+Coercion AId : string >-> aexp.
+Coercion ANum : nat >-> aexp.
+Definition bool_to_bexp (b : bool) : bexp :=
if b then BTrue else BFalse.
-Coercion bool_to_bexp : bool >-> bexp.
-Bind Scope aexp_scope with aexp.
-Infix "+" := APlus : aexp_scope.
-Infix "-" := AMinus : aexp_scope.
-Infix "*" := AMult : aexp_scope.
-Bind Scope bexp_scope with bexp.
-Infix "≤" := BLe : bexp_scope.
-Infix "=" := BEq : bexp_scope.
-Infix "&&" := BAnd : bexp_scope.
-Notation "'!' b" := (BNot b) (at level 60) : bexp_scope.
+Coercion bool_to_bexp : bool >-> bexp.
+Bind Scope imp_scope with aexp.
+Bind Scope imp_scope with bexp.
+Delimit Scope imp_scope with imp.
+Notation "x + y" := (APlus x y) (at level 50, left associativity) : imp_scope.
+Notation "x - y" := (AMinus x y) (at level 50, left associativity) : imp_scope.
+Notation "x * y" := (AMult x y) (at level 40, left associativity) : imp_scope.
+Notation "x ≤ y" := (BLe x y) (at level 70, no associativity) : imp_scope.
+Notation "x = y" := (BEq x y) (at level 70, no associativity) : imp_scope.
+Notation "x && y" := (BAnd x y) (at level 40, left associativity) : imp_scope.
+Notation "'¬' b" := (BNot b) (at level 75, right associativity) : imp_scope.
现在我们可以用 3 + (X * 2) 来代替 APlus 3 (AMult X 2) 了,同样可以用 - true && !(X ≤ 4) 来代替 BAnd true (BNot (BLe X 4)) + true && !(X ≤ 4) 来代替 BAnd true (BNot (BLe X 4))。 +++ +Definition example_aexp := (3 + (X * 2))%imp : aexp.+ +
+Definition example_bexp := (true && ~(X ≤ 4))%imp : bexp.
++强制转换有一点不便之处,即它会略微提高人类推导表达式类型的难度。 + 如果你感到有点困惑,请用 Set Printing Coercions 来查看具体发生了什么。 +++ +Set Printing Coercions.
+Print example_bexp.
+(* ===> example_bexp = bool_to_bexp true && ~ (AId X <= ANum 4) *)
+Unset Printing Coercions.
-求值
+求值
@@ -1319,7 +1395,7 @@Imp简单的指令式程序 Fixpoint aeval (st : state) (a : aexp) : nat :=
match a with
| ANum n ⇒ n
- | AId x ⇒ st x (* <----- 新增 *)
+ | AId x ⇒ st x (* <--- 新增 *)
| APlus a1 a2 ⇒ (aeval st a1) + (aeval st a2)
| AMinus a1 a2 ⇒ (aeval st a1) - (aeval st a2)
| AMult a1 a2 ⇒ (aeval st a1) * (aeval st a2)
@@ -1336,42 +1412,39 @@Imp简单的指令式程序
-我们为具体状态的全映射声明具体的记法,即使用 { --> 0 } 作为空状态。 +我们为具体状态的全映射声明具体的记法,即使用 (_ !-> 0) 作为空状态。-Notation "{ a --> x }" :=+ +
- (t_update { --> 0 } a x) (at level 0).
-Notation "{ a --> x ; b --> y }" :=
- (t_update ({ a --> x }) b y) (at level 0).
-Notation "{ a --> x ; b --> y ; c --> z }" :=
- (t_update ({ a --> x ; b --> y }) c z) (at level 0).
-Notation "{ a --> x ; b --> y ; c --> z ; d --> t }" :=
- (t_update ({ a --> x ; b --> y ; c --> z }) d t) (at level 0).
-Notation "{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }" :=
- (t_update ({ a --> x ; b --> y ; c --> z ; d --> t }) e u) (at level 0).
-Notation "{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }" :=
- (t_update ({ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }) f v) (at level 0).
+Definition empty_st := (_ !-> 0).
++现在我们可以为“单例状态(singleton state)”添加新的记法了, + 即只有一个绑定到值的变量。 +++Notation "a '!->' x" := (t_update empty_st a x) (at level 100).+ + +
Example aexp1 :
- aeval { X --> 5 } (3 + (X * 2))
+ aeval (X !-> 5) (3 + (X * 2))%imp
= 13.
--+diff --git a/lf-current/lf.tgz b/lf-current/lf.tgz index 884c5d51..20717940 100644 Binary files a/lf-current/lf.tgz and b/lf-current/lf.tgz differ diff --git a/lf-current/toc.html b/lf-current/toc.html index 90c9bbc0..a1de4c77 100644 --- a/lf-current/toc.html +++ b/lf-current/toc.html @@ -105,20 +105,30 @@+Proof. reflexivity. Qed.
Example bexp1 :
- beval { X --> 5 } (true && !(X ≤ 4))
+ beval (X !-> 5) (true && ~(X ≤ 4))%imp
= true.
--++Proof. reflexivity. Qed.
-语法
+语法
- 指令 c 可以用以下 BNF 文法非形式化地描述。(为了能够使用 Coq - 的记法机制来定义 Imp 语法,我们选择了这种略尴尬的具体语法。具体来说, - 我们使用了 IFB 来避免与表中库中的 if 记法相冲突。) + 指令 c 可以用以下 BNF 文法非形式化地描述。- c ::= SKIP | x ::= a | c ;; c | IFB b THEN c ELSE c FI- + (为了能够使用 Coq 的记法机制来定义 Imp 语法,我们选择了这种略尴尬的具体语法。 + 具体来说,我们使用了 TEST 来避免与表中库中的 if 记法相冲突。)
+ c ::= SKIP | x ::= a | c ;; c | TEST b THEN c ELSE c FI
| WHILE b DO c END例如,下面是用 Imp 编写的阶乘: @@ -1406,7 +1478,7 @@Imp简单的指令式程序
Z ::= X;;
Y ::= 1;;
- WHILE ! (Z = 0) DO
+ WHILE ~(Z = 0) DO
Y ::= Y * Z;;
Z ::= Z - 1
END @@ -1433,24 +1505,17 @@Imp简单的指令式程序
-Bind Scope com_scope with com.- -
+Bind Scope imp_scope with com.
Notation "'SKIP'" :=
- CSkip : com_scope.
+ CSkip : imp_scope.
Notation "x '::=' a" :=
- (CAss x a) (at level 60) : com_scope.
+ (CAss x a) (at level 60) : imp_scope.
Notation "c1 ;; c2" :=
- (CSeq c1 c2) (at level 80, right associativity) : com_scope.
+ (CSeq c1 c2) (at level 80, right associativity) : imp_scope.
Notation "'WHILE' b 'DO' c 'END'" :=
- (CWhile b c) (at level 80, right associativity) : com_scope.
-Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" :=
- (CIf c1 c2 c3) (at level 80, right associativity) : com_scope.
--以下声明可以让这些记法在模式匹配中使用。 ---Open Scope com_scope.
+ (CWhile b c) (at level 80, right associativity) : imp_scope.
+Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" :=
+ (CIf c1 c2 c3) (at level 80, right associativity) : imp_scope.
@@ -1459,16 +1524,113 @@-Imp简单的指令式程序
Definition fact_in_coq : com :=
- Z ::= X;;
+ (Z ::= X;;
Y ::= 1;;
- WHILE ! (Z = 0) DO
+ WHILE ~(Z = 0) DO
Y ::= Y * Z;;
Z ::= Z - 1
- END.
+ END)%imp.
-+更多示例
+脱糖记法
+ ++ + Coq 为管理日益复杂的工作对象提供了丰富的特性,例如隐式转换和记法。 + 然而,过度使用它们会产生繁杂的语法。为了教学,我们通常会用以下命令来 + “关闭”这些特性以获得对事物更加本质的描述: + ++ ++
+ 这些命令也可在证明过程中详述当前目标和上下文。 +- Unset Printing Notations(用 Set Printing Notations 撤销) + +
+- Set Printing Coercions(用 Unset Printing Coercions 撤销) + +
+- Set Printing All(用 Unset Printing All 撤销) + +
++ +Unset Printing Notations.+ + +
+Print fact_in_coq.
+(* ===>
+ fact_in_coq =
+ CSeq (CAss Z X)
+ (CSeq (CAss Y (S O))
+ (CWhile (BNot (BEq Z O))
+ (CSeq (CAss Y (AMult Y Z))
+ (CAss Z (AMinus Z (S O))))))
+ : com *)
+Set Printing Notations.
+Set Printing Coercions.
+Print fact_in_coq.
+(* ===>
+ fact_in_coq =
+ (Z ::= AId X;;
+ Y ::= ANum 1;;
+ WHILE ~ (AId Z = ANum 0) DO
+ Y ::= AId Y * AId Z;;
+ Z ::= AId Z - ANum 1
+ END)%imp
+ : com *)
+Unset Printing Coercions.
++Locate "&&".+ + +
+(* ===>
+ Notation "x && y" := andb x y : bool_scope (default interpretation) *)
+Locate ";;".
+(* ===>
+ Notation "c1 ;; c2" := CSeq c1 c2 : imp_scope (default interpretation) *)
+Locate "WHILE".
+(* ===>
+ Notation "'WHILE' b 'DO' c 'END'" := CWhile b c : imp_scope
+ (default interpretation) *)
++Locate aexp.+ +
+(* ===>
+ Inductive Top.aexp
+ Inductive Top.AExp.aexp
+ (shorter name to refer to it in current context is AExp.aexp)
+ Inductive Top.aevalR_division.aexp
+ (shorter name to refer to it in current context is aevalR_division.aexp)
+ Inductive Top.aevalR_extended.aexp
+ (shorter name to refer to it in current context is aevalR_extended.aexp)
+*)
+
Definition subtract_slowly : com :=
- WHILE ! (X = 0) DO
+ (WHILE ~(X = 0) DO
subtract_slowly_body
- END.
+ END)%imp.
Definition subtract_3_from_5_slowly : com :=
X ::= 3 ;;
Z ::= 5 ;;
@@ -1503,7 +1665,7 @@Imp简单的指令式程序
@@ -1516,7 +1678,7 @@Imp简单的指令式程序
- +Open Scope imp_scope.
Fixpoint ceval_fun_no_while (st : state) (c : com)
: state :=
match c with
| SKIP ⇒
st
| x ::= a1 ⇒
- st & { x --> (aeval st a1) }
+ (x !-> (aeval st a1) ; st)
| c1 ;; c2 ⇒
let st' := ceval_fun_no_while st c1 in
ceval_fun_no_while st' c2
- | IFB b THEN c1 ELSE c2 FI ⇒
+ | TEST b THEN c1 ELSE c2 FI ⇒
if (beval st b)
then ceval_fun_no_while st c1
else ceval_fun_no_while st c2
| WHILE b DO c END ⇒
st (* 假装能用 *)
end.
+Close Scope imp_scope.
@@ -1561,7 +1727,7 @@Imp简单的指令式程序 ... | WHILE b DO c END => if (beval st b) - then ceval_fun st (c;; WHILE b DO c END) + then ceval_fun st (c ;; WHILE b DO c END) else st end. @@ -1585,7 +1751,7 @@
Imp简单的指令式程序
-diff --git a/lf-current/imp.ml b/lf-current/imp.ml index 859b00a5..0df05a9a 100644 --- a/lf-current/imp.ml +++ b/lf-current/imp.ml @@ -323,6 +323,11 @@ let rec beval st = function | BNot b1 -> negb (beval st b1) | BAnd (b1, b2) -> (&&) (beval st b1) (beval st b2) +(** val empty_st : int total_map **) + +let empty_st = + t_empty 0 + type com = | CSkip | CAss of char list * aexp @@ -1637,7 +1642,7 @@ let rec parseAtomicExp steps xs = (match expect ('f'::('a'::('l'::('s'::('e'::[]))))) xs with | SomeE x -> let (_, rest) = x in SomeE (BFalse, rest) | NoneE _ -> - (match firstExpect ('!'::[]) (parseAtomicExp steps') xs with + (match firstExpect ('~'::[]) (parseAtomicExp steps') xs with | SomeE x -> let (e, rest) = x in SomeE ((BNot e), rest) | NoneE _ -> (match firstExpect ('('::[]) (parseConjunctionExp steps') xs with @@ -1702,7 +1707,7 @@ let rec parseSimpleCommand steps xs = match expect ('S'::('K'::('I'::('P'::[])))) xs with | SomeE x -> let (_, rest) = x in SomeE (CSkip, rest) | NoneE _ -> - (match firstExpect ('I'::('F'::('B'::[]))) (parseBExp steps') xs with + (match firstExpect ('T'::('E'::('S'::('T'::[])))) (parseBExp steps') xs with | SomeE x -> let (e, rest) = x in (match firstExpect ('T'::('H'::('E'::('N'::[])))) @@ -1737,11 +1742,14 @@ let rec parseSimpleCommand steps xs = (match parseIdentifier xs with | SomeE x -> let (i, rest) = x in - (match firstExpect (':'::('='::[])) (parseAExp steps') rest with + (match firstExpect (':'::(':'::('='::[]))) (parseAExp steps') + rest with | SomeE x0 -> let (e, rest') = x0 in SomeE ((CAss (i, e)), rest') | NoneE err -> NoneE err) - | NoneE err -> NoneE err)))) + | NoneE _ -> + NoneE + ('E'::('x'::('p'::('e'::('c'::('t'::('i'::('n'::('g'::(' '::('a'::(' '::('c'::('o'::('m'::('m'::('a'::('n'::('d'::[]))))))))))))))))))))))) steps (** val parseSequencedCommand : @@ -2017,12 +2025,18 @@ let bignumber = ((fun x -> x + 1) ((fun x -> x + 1) ((fun x -> x + 1) ((fun x -> x + 1) 0))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) -(** val parse : char list -> (com * token list) optionE **) +(** val parse : char list -> com optionE **) let parse str = - let tokens = tokenize str in parseSequencedCommand bignumber tokens - -(** val empty_state : int total_map **) - -let empty_state = - t_empty 0 + let tokens = tokenize str in + (match parseSequencedCommand bignumber tokens with + | SomeE x -> + let (c, l) = x in + (match l with + | [] -> SomeE c + | t :: _ -> + NoneE + (append + ('T'::('r'::('a'::('i'::('l'::('i'::('n'::('g'::(' '::('t'::('o'::('k'::('e'::('n'::('s'::(' '::('r'::('e'::('m'::('a'::('i'::('n'::('i'::('n'::('g'::(':'::(' '::[]))))))))))))))))))))))))))) + t)) + | NoneE err -> NoneE err) diff --git a/lf-current/imp.mli b/lf-current/imp.mli index 228bae8c..6ec599fa 100644 --- a/lf-current/imp.mli +++ b/lf-current/imp.mli @@ -102,6 +102,8 @@ val aeval : state -> aexp -> int val beval : state -> bexp -> bool +val empty_st : int total_map + type com = | CSkip | CAss of char list * aexp @@ -177,6 +179,4 @@ val parseSequencedCommand : int -> token list -> (com * token list) optionE val bignumber : int -val parse : char list -> (com * token list) optionE - -val empty_state : int total_map +val parse : char list -> com optionE diff --git a/lf-current/impdriver.ml b/lf-current/impdriver.ml index 4869207e..4788c025 100644 --- a/lf-current/impdriver.ml +++ b/lf-current/impdriver.ml @@ -10,9 +10,9 @@ let test s = let parse_res = parse (explode s) in (match parse_res with NoneE _ -> print_endline ("Syntax error"); - | SomeE (c, _) -> + | SomeE c -> let fuel = 1000 in - match (ceval_step empty_state c fuel) with + match (ceval_step empty_st c fuel) with None -> print_endline ("Still running after " ^ string_of_int fuel ^ " steps") diff --git a/lf-current/index.html b/lf-current/index.html index 6a382460..1d6cd57b 100644 --- a/lf-current/index.html +++ b/lf-current/index.html @@ -50,6 +50,7 @@ Anthony Cowley, Jeffrey Foster, Dmitri Garbuzov, + Olek Gierczak, Michael Hicks, Ranjit Jhala, Greg Morrisett, @@ -60,6 +61,7 @@ Andrew Tolmach, Philip Wadler, Stephanie Weirich, + Li-Yao Xia, and Steve Zdancewic求值作为一种关系
+求值作为一种关系
@@ -1599,12 +1765,12 @@Imp简单的指令式程序 即,它不仅会有不完全性,甚至还可以不是个函数!
- 我们将使用记法 c / st \\ st' 来表示 ceval 这种关系:c / st \\ st' + 我们将使用记法 st =[ c ]⇒ st' 来表示 ceval 这种关系:st =[ c ]⇒ st' 表示在开始状态 st 下启动程序并在结束状态 st' 下产生结果。它可以读作: “c 将状态 st 变成 st'”。-操作语义
+操作语义
@@ -1619,7 +1785,7 @@Imp简单的指令式程序
- SKIP / st \\ st +st =[ SKIP ]=> st @@ -1632,16 +1798,16 @@
Imp简单的指令式程序
- x := a1 / st \\ st & { x --> n } +st =[ x := a1 ]=> (x !-> n ; st)
- c1 / st \\ st' +st =[ c1 ]=> st' - @@ -1649,7 +1815,7 @@c2 / st' \\ st'' +st' =[ c2 ]=> st'' (E_Seq) Imp简单的指令式程序
- c1;;c2 / st \\ st'' +st =[ c1;;c2 ]=> st'' @@ -1658,7 +1824,7 @@
Imp简单的指令式程序
- @@ -1666,7 +1832,7 @@c1 / st \\ st' +st =[ c1 ]=> st' (E_IfTrue) Imp简单的指令式程序
- IF b1 THEN c1 ELSE c2 FI / st \\ st' +st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st' @@ -1675,7 +1841,7 @@
Imp简单的指令式程序
- @@ -1683,7 +1849,7 @@c2 / st \\ st' +st =[ c2 ]=> st' (E_IfFalse) Imp简单的指令式程序
- IF b1 THEN c1 ELSE c2 FI / st \\ st' +st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st' @@ -1696,7 +1862,7 @@
Imp简单的指令式程序
- WHILE b DO c END / st \\ st +st =[ WHILE b DO c END ]=> st @@ -1727,36 +1893,36 @@ @@ -1705,11 +1871,11 @@
Imp简单的指令式程序
- c / st \\ st' +st =[ c ]=> st' - @@ -1717,7 +1883,7 @@WHILE b DO c END / st' \\ st'' +st' =[ WHILE b DO c END ]=> st'' (E_WhileTrue) Imp简单的指令式程序
- WHILE b DO c END / st \\ st'' +st =[ WHILE b DO c END ]=> st'' Imp简单的指令式程序
-Reserved Notation "c1 '/' st '\\' st'"
- (at level 40, st at level 39).
+Reserved Notation "st '=[' c ']⇒' st'"
+ (at level 40).
Inductive ceval : com → state → state → Prop :=
- | E_Skip : ∀ st,
- SKIP / st \\ st
- | E_Ass : ∀ st a1 n x,
+ | E_Skip : ∀st,
+ st =[ SKIP ]⇒ st
+ | E_Ass : ∀st a1 n x,
aeval st a1 = n →
- (x ::= a1) / st \\ st & { x --> n }
- | E_Seq : ∀ c1 c2 st st' st'',
- c1 / st \\ st' →
- c2 / st' \\ st'' →
- (c1 ;; c2) / st \\ st''
- | E_IfTrue : ∀ st st' b c1 c2,
+ st =[ x ::= a1 ]⇒ (x !-> n ; st)
+ | E_Seq : ∀c1 c2 st st' st'',
+ st =[ c1 ]⇒ st' →
+ st' =[ c2 ]⇒ st'' →
+ st =[ c1 ;; c2 ]⇒ st''
+ | E_IfTrue : ∀st st' b c1 c2,
beval st b = true →
- c1 / st \\ st' →
- (IFB b THEN c1 ELSE c2 FI) / st \\ st'
- | E_IfFalse : ∀ st st' b c1 c2,
+ st =[ c1 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_IfFalse : ∀st st' b c1 c2,
beval st b = false →
- c2 / st \\ st' →
- (IFB b THEN c1 ELSE c2 FI) / st \\ st'
- | E_WhileFalse : ∀ b st c,
+ st =[ c2 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_WhileFalse : ∀b st c,
beval st b = false →
- (WHILE b DO c END) / st \\ st
- | E_WhileTrue : ∀ st st' st'' b c,
+ st =[ WHILE b DO c END ]⇒ st
+ | E_WhileTrue : ∀st st' st'' b c,
beval st b = true →
- c / st \\ st' →
- (WHILE b DO c END) / st' \\ st'' →
- (WHILE b DO c END) / st \\ st''
+ st =[ c ]⇒ st' →
+ st' =[ WHILE b DO c END ]⇒ st'' →
+ st =[ WHILE b DO c END ]⇒ st''
- where "c1 '/' st '\\' st'" := (ceval c1 st st').
+ where "st =[ c ]⇒ st'" := (ceval c st st').
@@ -1766,31 +1932,34 @@@@ -1817,7 +1987,7 @@Imp简单的指令式程序
Example ceval_example1:
- (X ::= 2;;
- IFB X ≤ 1
+ empty_st =[
+ X ::= 2;;
+ TEST X ≤ 1
THEN Y ::= 3
ELSE Z ::= 4
- FI)
- / { --> 0 } \\ { X --> 2 ; Z --> 4 }.
+ FI
+ ]⇒ (Z !-> 4 ; X !-> 2).
Proof.
(* 我们必须提供中间状态 *)
- apply E_Seq with { X --> 2 }.
+ apply E_Seq with (X !-> 2).
- (* 赋值指令 *)
apply E_Ass. reflexivity.
- (* if 指令 *)
apply E_IfFalse.
- reflexivity.
- apply E_Ass. reflexivity. Qed.
+ reflexivity.
+ apply E_Ass. reflexivity.
+Qed.
Example ceval_example2:@@ -1799,7 +1968,7 @@
- (X ::= 0;; Y ::= 1;; Z ::= 2) / { --> 0 } \\
- { X --> 0 ; Y --> 1 ; Z --> 2 }.
+ empty_st =[
+ X ::= 0;; Y ::= 1;; Z ::= 2
+ ]⇒ (Z !-> 2 ; Y !-> 1 ; X !-> 0).
Proof.
(* 请在此处解答 *) Admitted.
Imp简单的指令式程序
@@ -1808,8 +1977,9 @@-练习:3 星, optional (pup_to_n)
+练习:3 星, standard, optional (pup_to_n)
写一个 Imp 程序对从 1 到 X 进行求值(包括:将 1 + 2 + ... + X) 赋予变量 Y。 证明此程序对于 X = 2 会按预期执行(这可能比你预想的还要棘手)。Imp简单的指令式程序 Definition pup_to_n : com
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
Theorem pup_to_2_ceval :
- pup_to_n / { X --> 2 }
- \\ { X --> 2 ; Y --> 0 ; Y --> 2 ; X --> 1 ; Y --> 3 ; X --> 0 }.
+ (X !-> 2) =[
+ pup_to_n
+ ]⇒ (X !-> 0 ; Y !-> 3 ; X !-> 1 ; Y !-> 2 ; Y !-> 0 ; X !-> 2).
Proof.
(* 请在此处解答 *) Admitted.
Imp简单的指令式程序 ☐
-Theorem ceval_deterministic: ∀ c st st1 st2,
- c / st \\ st1 →
- c / st \\ st2 →
+Theorem ceval_deterministic: ∀c st st1 st2,
+ st =[ c ]⇒ st1 →
+ st =[ c ]⇒ st2 →
st1 = st2.
--++Proof.
intros c st st1 st2 E1 E2.
generalize dependent st2.
@@ -1874,7 +2044,7 @@Imp简单的指令式程序
-Theorem plus2_spec : ∀ st n st',@@ -1903,7 +2073,7 @@
+Theorem plus2_spec : ∀st n st',
st X = n →
- plus2 / st \\ st' →
- st' X = (n + 2).
+ st =[ plus2 ]⇒ st' →
+ st' X = n + 2.
Proof.
intros st n st' HX Heval.
Imp简单的指令式程序
-练习:3 星, recommended (XtimesYinZ_spec)
+练习:3 星, standard, recommended (XtimesYinZ_spec)
叙述并证明 XtimesYinZ 的规范(Specification)。@@ -1917,15 +2087,15 @@Imp简单的指令式程序
-Theorem loop_never_stops : ∀ st st',@@ -1942,11 +2112,12 @@
- ~(loop / st \\ st').
+Theorem loop_never_stops : ∀st st',
+ ~(st =[ loop ]⇒ st').
Proof.
intros st st' contra. unfold loop in contra.
- remember (WHILE true DO SKIP END) as loopdef
+ remember (WHILE true DO SKIP END)%imp as loopdef
eqn:Heqloopdef.
Imp简单的指令式程序
+Open Scope imp_scope.
Fixpoint no_whiles (c : com) : bool :=
match c with
| SKIP ⇒
@@ -1955,11 +2126,12 @@Imp简单的指令式程序 true
| c1 ;; c2 ⇒
andb (no_whiles c1) (no_whiles c2)
- | IFB _ THEN ct ELSE cf FI ⇒
+ | TEST _ THEN ct ELSE cf FI ⇒
andb (no_whiles ct) (no_whiles cf)
| WHILE _ DO _ END ⇒
false
end.
+Close Scope imp_scope.
@@ -1973,7 +2145,7 @@@@ -1982,7 +2154,7 @@Imp简单的指令式程序 (* 请在此处解答 *)
.
Theorem no_whiles_eqv:
- ∀ c, no_whiles c = true ↔ no_whilesR c.
+ ∀c, no_whiles c = true ↔ no_whilesR c.
Proof.
(* 请在此处解答 *) Admitted.
Imp简单的指令式程序
@@ -1996,11 +2168,11 @@-练习:4 星 (no_whiles_terminating)
+练习:4 星, standard (no_whiles_terminating)
不涉及 WHILE 循环的 Imp 程序一定会终止。请陈述并证明定理 no_whiles_terminating 来说明这一点。 按照你的偏好使用 no_whiles 或 no_whilesR。Imp简单的指令式程序 ☐
-附加练习
+附加练习
-练习:3 星 (stack_compiler)
+练习:3 星, standard (stack_compiler)
旧式惠普计算器的编程语言类似于 Forth 和 Postscript,而其抽象机器类似于 Java 虚拟机,即所有对算术表达式的求值都使用栈来进行。例如,表达式@@ -2076,12 +2248,12 @@Imp简单的指令式程序 : list nat
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
Example s_execute1 :
- s_execute { --> 0 } []
+ s_execute empty_st []
[SPush 5; SPush 3; SPush 1; SMinus]
= [2; 5].
(* 请在此处解答 *) Admitted.
Example s_execute2 :
- s_execute { X --> 3 } [3;4]
+ s_execute (X !-> 3) [3;4]
[SPush 4; SLoad X; SMult; SPlus]
= [15; 4].
(* 请在此处解答 *) Admitted.
@@ -2103,7 +2275,7 @@Imp简单的指令式程序
Example s_compile1 :@@ -2112,7 +2284,7 @@
- s_compile (X - (2 * Y))
+ s_compile (X - (2 * Y))%imp
= [SLoad X; SPush 2; SLoad Y; SMult; SMinus].
(* 请在此处解答 *) Admitted.
Imp简单的指令式程序
-练习:4 星, advanced (stack_compiler_correct)
+练习:4 星, advanced (stack_compiler_correct)
现在我们将证明在之前练习中实现的编译器的正确性。记住当栈中的元素少于两个时, 规范并未指定 SPlus、SMinus 或 SMult 指令的行为。 (为了让正确性证明更加容易,你可能需要返回去修改你的实现!) @@ -2124,7 +2296,7 @@Imp简单的指令式程序
-Theorem s_compile_correct : ∀ (st : state) (e : aexp),@@ -2202,8 +2374,8 @@
+Theorem s_compile_correct : ∀(st : state) (e : aexp),
s_execute st [] (s_compile e) = [ aeval st e ].
Proof.
(* 请在此处解答 *) Admitted.
@@ -2134,7 +2306,7 @@Imp简单的指令式程序
-练习:3 星, optional (short_circuit)
+练习:3 星, standard, optional (short_circuit)
大部分现代编程语言对布尔 and 运算提供了“短路求值”的方法:要对 BAnd b1 b2 进行求值,首先对 b1 求值。如果结果为 false,那么整个 BAnd 表达式的求值就是 false,而无需对 b2 求值。否则,b2 @@ -2159,7 +2331,7 @@Imp简单的指令式程序
-@@ -2167,7 +2339,7 @@练习:4 星, advanced (break_imp)
+练习:4 星, advanced (break_imp)
像 C 和 Java 这样的指令式语言通常会包含 break 或类似地语句来中断循环的执行。 在本练习中,我们考虑如何为 Imp 加上 break。首先,我们需要丰富语言的指令。Imp简单的指令式程序 Inductive com : Type :=
| CSkip
- | CBreak (* <-- 新增 *)
+ | CBreak (* <--- 新增 *)
| CAss (x : string) (a : aexp)
| CSeq (c1 c2 : com)
| CIf (b : bexp) (c1 c2 : com)
@@ -2182,7 +2354,7 @@Imp简单的指令式程序 (CSeq c1 c2) (at level 80, right associativity).
Notation "'WHILE' b 'DO' c 'END'" :=
(CWhile b c) (at level 80, right associativity).
-Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" :=
+Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" :=
(CIf c1 c2 c3) (at level 80, right associativity).
Imp简单的指令式程序
X ::= 0;;
Y ::= 1;;
- WHILE 0 ≠ Y DO
- WHILE TRUE DO
+ WHILE ~(0 = Y) DO
+ WHILE true DO
BREAK
END;;
X ::= 1;;
@@ -2224,19 +2396,19 @@Imp简单的指令式程序 Inductive result : Type :=
| SContinue
| SBreak.
-Reserved Notation "c1 '/' st '\\' s '/' st'"
- (at level 40, st, s at level 39).
+Reserved Notation "st '=[' c ']⇒' st' '/' s"
+ (at level 40, st' at next level).
-直觉上说,c / st \\ s / st' 表示如果 c 在 st 状况下开始, +直觉上说,st =[ c ]⇒ st' / s 表示如果 c 在 st 状况下开始, 它会在 st' 状态下终止,围绕它的最内层循环(或整个程序) 要么收到立即退出的信号(s = SBreak),要么继续正常执行(s = SContinue)。diff --git a/lf-current/Imp.v b/lf-current/Imp.v index 3dd455f1..ae925d7e 100644 --- a/lf-current/Imp.v +++ b/lf-current/Imp.v @@ -1,13 +1,13 @@ (** * Imp: 简单的指令式程序 *) -(** 在本章中,我们会更加认真地看待如何用 Coq 来研究自身以外的有趣的东西。 +(** 在本章中,我们会更加认真地看待如何用 Coq 来研究其它东西。 我们的案例研究是一个名为 Imp 的_'简单的指令式编程语言'_, 它包含了传统主流语言(如 C 和 Java)的一小部分核心片段。下面是一个用 Imp 编写的常见数学函数: Z ::= X;; Y ::= 1;; - WHILE ! (Z = 0) DO + WHILE ~(Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 END @@ -19,12 +19,13 @@ _'霍尔逻辑(Hoare Logic)'_,它是一种广泛用于推理指令式程序的逻辑。 *) Set Warnings "-notation-overridden,-parsing". -Require Import Coq.Bool.Bool. -Require Import Coq.Init.Nat. -Require Import Coq.Arith.Arith. -Require Import Coq.Arith.EqNat. -Require Import Coq.omega.Omega. -Require Import Coq.Lists.List. +From Coq Require Import Bool.Bool. +From Coq Require Import Init.Nat. +From Coq Require Import Arith.Arith. +From Coq Require Import Arith.EqNat. +From Coq Require Import omega.Omega. +From Coq Require Import Lists.List. +From Coq Require Import Strings.String. Import ListNotations. From LF Require Import Maps. @@ -58,11 +59,11 @@ Inductive bexp : Type := | BAnd (b1 b2 : bexp). (** 在本章中,我们省略了大部分从程序员实际编写的具体语法到其抽象语法树的翻译 - -- 例如,它会将字符串 ["1+2*3"] 翻译成如下 AST: + -- 例如,它会将字符串 ["1 + 2 * 3"] 翻译成如下 AST: APlus (ANum 1) (AMult (ANum 2) (ANum 3)). - 可选的章节 [ImpParser] 中开发了一个简单的词法分析器和解析器的实现, + 可选的章节 [ImpParser] 中开发了一个简单的词法分析器和解析器, 它可以进行这种翻译。你_'无需'_通过理解该章来理解本章, 但如果你没有上过涵盖这些技术的课程(例如编译器课程),可能想要略读一下该章节。 *) @@ -77,26 +78,26 @@ Inductive bexp : Type := | false | a = a | a <= a - | not b - | b and b + | ~ b + | b && b *) (** 与前面的 Coq 版本相对比... - BNF 是非形式化的 -- 例如,它给出了表达式表面上的语法的建议 - (例如加法运算写作 [+] 且它是一个中缀符),而没有指定词法分析和解析的其它方面 + (例如加法运算符写作中缀的 [+]),而没有指定词法分析和解析的其它方面 (如 [+]、[-] 和 [*] 的相对优先级,用括号来明确子表达式的分组等)。 在实现编译器时,需要一些附加的信息(以及人类的智慧) 才能将此描述转换成形式化的定义。 Coq 版本则始终忽略了所有这些信息,只专注于抽象语法。 - - 另一方面 BNF 版本则更加清晰易读。它的非形式化使其更加灵活, + - 反之,BNF 版本则更加清晰易读。它的非形式化使其更加灵活, 在讨论和在黑板上书写时,它有很大的优势, 此时传达一般的概念要比精确定下所有细节更加重要。 确实,存在很多种类似 BNF 的记法,人们可以随意使用它们, - 而无需关心具体使用了哪种 BNF 的形式,因为没有必要: + 而无需关心具体使用了哪种 BNF,因为没有必要: 大致的理解是非常重要的。 适应这两种记法都很有必要:非形式化的用语人类之间的交流, @@ -110,9 +111,9 @@ Inductive bexp : Type := Fixpoint aeval (a : aexp) : nat := match a with | ANum n => n - | APlus a1 a2 => (aeval a1) + (aeval a2) - | AMinus a1 a2 => (aeval a1) - (aeval a2) - | AMult a1 a2 => (aeval a1) * (aeval a2) + | APlus a1 a2 => (aeval a1) + (aeval a2) + | AMinus a1 a2 => (aeval a1) - (aeval a2) + | AMult a1 a2 => (aeval a1) * (aeval a2) end. Example test_aeval1: @@ -136,20 +137,15 @@ Fixpoint beval (b : bexp) : bool := (** 我们尚未定义太多东西,不过从这些定义出发,已经能前进不少了。 假设我们定义了一个接收算术表达式并对它稍微进行化简的函数,即将所有的 - [0+e](如 [(APlus (ANum 0) e])化简为 [e]。 *) + [0 + e](如 [(APlus (ANum 0) e])化简为 [e]。 *) Fixpoint optimize_0plus (a:aexp) : aexp := match a with - | ANum n => - ANum n - | APlus (ANum 0) e2 => - optimize_0plus e2 - | APlus e1 e2 => - APlus (optimize_0plus e1) (optimize_0plus e2) - | AMinus e1 e2 => - AMinus (optimize_0plus e1) (optimize_0plus e2) - | AMult e1 e2 => - AMult (optimize_0plus e1) (optimize_0plus e2) + | ANum n => ANum n + | APlus (ANum 0) e2 => optimize_0plus e2 + | APlus e1 e2 => APlus (optimize_0plus e1) (optimize_0plus e2) + | AMinus e1 e2 => AMinus (optimize_0plus e1) (optimize_0plus e2) + | AMult e1 e2 => AMult (optimize_0plus e1) (optimize_0plus e2) end. (** 要保证我们的优化是正确的,可以在某些示例中测试它并观察其输出出否正确。 *) @@ -209,16 +205,16 @@ Proof. (** *** [try] 泛策略 *) (** 如果 [T] 是一个策略,那么 [try T] 是一个和 [T] 一样的策略,只是如果 - [T] 失败的话,[try T] 就会_'成功地'_什么也不做(而非失败)。 *) + [T] 失败的话,[try T] 就会_'成功地'_什么也不做(而非失败)。*) Theorem silly1 : forall ae, aeval ae = aeval ae. -Proof. try reflexivity. (* 它和 [reflexivity] 做的一样 *) Qed. +Proof. try reflexivity. (* 它和 [reflexivity] 做的一样。 *) Qed. Theorem silly2 : forall (P : Prop), P -> P. Proof. intros P HP. - try reflexivity. (* 和 [reflexivity] 失败时一样 *) - apply HP. (* 我们仍然可以换种方式来结束此证明 *) + try reflexivity. (* 和 [reflexivity] 失败时一样。 *) + apply HP. (* 我们仍然可以换种方式来结束此证明。 *) Qed. (** 我们并没有真正的理由在像这样的手动证明中使用 [try],不过在连同 @@ -235,7 +231,7 @@ Qed. Lemma foo : forall n, 0 <=? n = true. Proof. intros. - destruct n eqn:E. + destruct n. (* 会产生两个执行过程相同的子目标... *) - (* n=0 *) simpl. reflexivity. - (* n=Sn' *) simpl. reflexivity. @@ -370,11 +366,12 @@ Qed. 那么重复 [T] 会永远循环(例如 [repeat simpl] 会一直循环,因为 [simpl] 总是会成功)。虽然 Coq 的主语言 Gallina 中的求值保证会终止, 然而策略却不会!然而这并不会影响 Coq 的逻辑一致性,因为 [repeat] - 和其它策略的工作就是指导 Coq 去构造证明;如果构造过程发散(即不终止), + 和其它策略的工作就是指导 Coq 去构造证明;如果构造过程发散(即不停机), 那就意味着我们构造证明失败,而非构造出了错误的证明。 *) -(** **** 练习:3 星 (optimize_0plus_b_sound) *) -(** 由于 [optimize_0plus] 变换不会改变 [aexp] 的值, +(** **** 练习:3 星, standard (optimize_0plus_b_sound) + + 由于 [optimize_0plus] 变换不会改变 [aexp] 的值, 因此我们可以将它应用到所有出现在 [bexp] 中的 [aexp] 上而不改变 [bexp] 的值。请编写一个对 [bexp] 执行此变换的函数,并证明它的可靠性。 利用我们刚学过的泛策略来构造一个尽可能优雅的证明。 *) @@ -388,13 +385,15 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, optional (optimizer) *) -(** _'设计练习'_:[optimize_0plus] 函数只是众多算术和布尔表达式优化的方法之一。 +(** **** 练习:4 星, standard, optional (optimize) + + _'设计练习'_:[optimize_0plus] 函数只是众多算术和布尔表达式优化的方法之一。 请编写一个更加聪明的优化器并证明它的正确性。(最容易的方法就是从小处着手: 一开始只添加单个简单的优化并证明它的正确性,然后逐渐增加其它更有趣的优化。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ================================================================= *) (** ** 定义新的策略记法 *) @@ -449,7 +448,7 @@ Proof. intros. omega. Qed. -(** (注意本文件顶部 [Require Import Coq.omega.Omega.]。)*) +(** (注意本文件顶部 [From Coq Require Import omega.Omega.]。)*) (* ================================================================= *) (** ** 更多方便的策略 *) @@ -458,10 +457,10 @@ Qed. - [clear H]:从上下文中删除前提 [H]。 - - [subst x]:在上下文中查找假设 [x = e] 或 [e = x], + - [subst x]:对于变量 [x],在上下文中查找假设 [x = e] 或 [e = x], 将整个上下文和当前目标中的所有 [x] 替换为 [e] 并清除该假设。 - - [subst]:替换掉_'所有'_形如 [x = e] 或 [e = x] 的假设。 + - [subst]:替换掉_'所有'_形如 [x = e] 或 [e = x] 的假设(其中 [x] 为变量)。 - [rename... into...]:更改证明上下文中前提的名字。例如, 如果上下文中包含名为 [x] 的变量,那么 [rename x into y] @@ -477,7 +476,7 @@ Qed. 定义中查找可用于解决当前目标的构造子 [c]。如果找到了,那么其行为与 [apply c] 相同。 - 我们之后会看到它们的例子。 *) + 我们之后会看到所有它们的例子。 *) (* ################################################################# *) (** * 求值作为关系 *) @@ -505,6 +504,35 @@ Inductive aevalR : aexp -> nat -> Prop := aevalR e2 n2 -> aevalR (AMult e1 e2) (n1 * n2). +Module TooHardToRead. + +(* A small notational aside. We would previously have written the + definition of [aevalR] like this, with explicit names for the + hypotheses in each case: *) + +Inductive aevalR : aexp -> nat -> Prop := + | E_ANum n : + aevalR (ANum n) n + | E_APlus (e1 e2: aexp) (n1 n2: nat) + (H1 : aevalR e1 n1) + (H2 : aevalR e2 n2) : + aevalR (APlus e1 e2) (n1 + n2) + | E_AMinus (e1 e2: aexp) (n1 n2: nat) + (H1 : aevalR e1 n1) + (H2 : aevalR e2 n2) : + aevalR (AMinus e1 e2) (n1 - n2) + | E_AMult (e1 e2: aexp) (n1 n2: nat) + (H1 : aevalR e1 n1) + (H2 : aevalR e2 n2) : + aevalR (AMult e1 e2) (n1 * n2). + +(** Instead, we've chosen to leave the hypotheses anonymous, just + giving their types. This style gives us less control over the + names that Coq chooses during proofs involving [aevalR], but it + makes the definition itself quite a bit lighter. *) + +End TooHardToRead. + (** 如果 [aevalR] 有中缀记法的话会很方便。我们用 [e \\ n] 表示算术表达式 [e] 求值为 [n]。 *) @@ -521,16 +549,16 @@ End aevalR_first_try. 具体做法是,我们先“保留”该记法,然后在给出定义的同时声明它的意义。*) -Reserved Notation "e '\\' n" (at level 50, left associativity). +Reserved Notation "e '\\' n" (at level 90, left associativity). Inductive aevalR : aexp -> nat -> Prop := - | E_ANum n : + | E_ANum (n : nat) : (ANum n) \\ n - | E_APlus e1 e2 n1 n2 : + | E_APlus (e1 e2 : aexp) (n1 n2 : nat) : (e1 \\ n1) -> (e2 \\ n2) -> (APlus e1 e2) \\ (n1 + n2) - | E_AMinus e1 e2 n1 n2 : + | E_AMinus (e1 e2 : aexp) (n1 n2 : nat) : (e1 \\ n1) -> (e2 \\ n2) -> (AMinus e1 e2) \\ (n1 - n2) - | E_AMult e1 e2 n1 n2 : + | E_AMult (e1 e2 : aexp) (n1 n2 : nat) : (e1 \\ n1) -> (e2 \\ n2) -> (AMult e1 e2) \\ (n1 * n2) where "e '\\' n" := (aevalR e n) : type_scope. @@ -554,7 +582,7 @@ Inductive aevalR : aexp -> nat -> Prop := e1 \\ n1 e2 \\ n2 - -------------------- (E_APlus) + -------------------- (E_APlus) APlus e1 e2 \\ n1+n2 *) @@ -588,6 +616,27 @@ Inductive aevalR : aexp -> nat -> Prop := AMult e1 e2 \\ n1*n2 *) +(** **** 练习:1 星, standard, optional (beval_rules) + + 下面是 Coq 中 [beval] 函数的定义: + + Fixpoint beval (e : bexp) : bool := + match e with + | BTrue => true + | BFalse => false + | BEq a1 a2 => (aeval a1) =? (aeval a2) + | BLe a1 a2 => (aeval a1) <=? (aeval a2) + | BNot b1 => negb (beval b1) + | BAnd b1 b2 => andb (beval b1) (beval b2) + end. + + 请用推理规则记法将布尔求值的定义写成关系的形式。 *) +(* 请在此处解答 *) + +(* 请勿修改下面这一行: *) +Definition manual_grade_for_beval_rules : option (nat*string) := None. +(** [] *) + (* ================================================================= *) (** ** 定义的等价关系 *) @@ -643,8 +692,9 @@ Proof. try apply IHa1; try apply IHa2; reflexivity. Qed. -(** **** 练习:3 星 (bevalR) *) -(** 用和 [aevalR] 同样的方式写出关系 [bevalR],并证明它等价于 [beval]。 *) +(** **** 练习:3 星, standard (bevalR) + + 用和 [aevalR] 同样的方式写出关系 [bevalR],并证明它等价于 [beval]。 *) Inductive bevalR: bexp -> bool -> Prop := (* 请在此处解答 *) @@ -668,31 +718,31 @@ End AExp. Module aevalR_division. -(** 例如,假设我们想要用除法运算来扩展算术运算: *) +(** 例如,假设我们想要用除法来扩展算术运算: *) Inductive aexp : Type := | ANum (n : nat) | APlus (a1 a2 : aexp) | AMinus (a1 a2 : aexp) | AMult (a1 a2 : aexp) - | ADiv (a1 a2 : aexp). (* <--- 新增 *) + | ADiv (a1 a2 : aexp). (* <--- 新增 *) (** 扩展 [aeval] 的定义来处理此讯算并不是很直观(我们要返回什么作为 [ADiv (ANum 5) (ANum 0)] 的结果?)。然而扩展 [aevalR] 却很直观。*) Reserved Notation "e '\\' n" - (at level 50, left associativity). + (at level 90, left associativity). Inductive aevalR : aexp -> nat -> Prop := - | E_ANum : forall (n:nat), + | E_ANum (n : nat) : (ANum n) \\ n - | E_APlus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_APlus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (APlus a1 a2) \\ (n1 + n2) - | E_AMinus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMinus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMinus a1 a2) \\ (n1 - n2) - | E_AMult : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMult (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMult a1 a2) \\ (n1 * n2) - | E_ADiv : forall (a1 a2: aexp) (n1 n2 n3: nat), + | E_ADiv (a1 a2 : aexp) (n1 n2 n3 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (n2 > 0) -> (mult n2 n3 = n1) -> (ADiv a1 a2) \\ n3 @@ -702,15 +752,15 @@ End aevalR_division. Module aevalR_extended. -(** 假设,我们转而想要用非确定性的数值生成器 [any] 来扩展算术运算, +(** 假设我们想要用非确定性的数值生成器 [any] 来扩展算术运算, 该生成器会在求值时产生任何数。(注意,这不同于在所有可能的数值中作出 - _'概率上的'_选择 -- 我们没有为结果指定任何具体的分布,只是说了 + _'概率上的'_选择 -- 我们没有为结果指定任何具体的概率分布,只是说了 _'可能的结果'_。) *) -Reserved Notation "e '\\' n" (at level 50, left associativity). +Reserved Notation "e '\\' n" (at level 90, left associativity). Inductive aexp : Type := - | AAny (* <--- NEW *) + | AAny (* <--- NEW *) | ANum (n : nat) | APlus (a1 a2 : aexp) | AMinus (a1 a2 : aexp) @@ -720,15 +770,15 @@ Inductive aexp : Type := 而扩展 [aevalR] 则无此问题... *) Inductive aevalR : aexp -> nat -> Prop := - | E_Any : forall (n:nat), - AAny \\ n (* <--- new *) - | E_ANum : forall (n:nat), + | E_Any (n : nat) : + AAny \\ n (* <--- NEW *) + | E_ANum (n : nat) : (ANum n) \\ n - | E_APlus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_APlus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (APlus a1 a2) \\ (n1 + n2) - | E_AMinus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMinus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMinus a1 a2) \\ (n1 - n2) - | E_AMult : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMult (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMult a1 a2) \\ (n1 * n2) where "a '\\' n" := (aevalR a n) : type_scope. @@ -736,7 +786,7 @@ where "a '\\' n" := (aevalR a n) : type_scope. End aevalR_extended. (** 这时你可能会问:默认情况下应该使用哪种风格? - 上面的例子表明关系式定义从根本上要比函数式的更加强大。 + 我们刚看到的例子表明关系式的定义反而比函数式的更加有用。 对于这种定义的东西不太容易用函数表达,或者确实_'不是'_函数的情况来说, 明显别无选择。但如果两种风格均可行呢? @@ -749,7 +799,7 @@ End aevalR_extended. 我们需要这些性质时必须显式地证明它们。 - 有了函数,我们还可以利用 Coq 的计算机制在证明过程中简化表达式。 - 此外,函数还可以直“提取为”OCaml 或 Haskell 的可执行代码。 *) + 此外,函数还可以直接从 Gallina“提取”出 OCaml 或 Haskell 的可执行代码。 *) (** 最终,选择视具体情况而定,或者只是品味问题。确实,在大型的 Coq 开发中,经常可以看到一个定义同时给出了函数式和关系式_'两种'_风格, @@ -784,7 +834,7 @@ Definition state := total_map nat. Inductive aexp : Type := | ANum (n : nat) - | AId (x : string) (* <----- 新增 *) + | AId (x : string) (* <--- 新增 *) | APlus (a1 a2 : aexp) | AMinus (a1 a2 : aexp) | AMult (a1 a2 : aexp). @@ -811,35 +861,53 @@ Inductive bexp : Type := | BAnd (b1 b2 : bexp). (* ================================================================= *) -(** ** 记法 *) -(** 要让 Imp 程序更易读写,我们引入了一些记法和隐式转换(Coercion)。 +(** ** 记法 + + 要让 Imp 程序更易读写,我们引入了一些记法和隐式转换(Coercion)。 - 在本章中你无需理解以下声明具体做了些什么。简言而之,Coq 中的 [Coercion] + 你无需理解以下声明具体做了些什么。简言而之,Coq 中的 [Coercion] 声明规定了一个函数(或构造子)可以被类型系统隐式地用于将一个输入类型的值 转换成输出类型的值。例如,[AId] 的转换声明在需要一个 [aexp] 时直接使用普通的字符串,该字符串会被隐式地用 [AId] 来包装。 *) (** 下列记法在具体的_'记法作用域'_中声明,以避免与其它符号相同的解释相冲突。 - 同样,你也暂时无需理解其中的细节。 *) + 同样,你暂时也无需理解其中的细节,但要意识到到我们为 [+]、[-]、[*]、[=]、[<=] + 等运算符定义了_'新的'_解释十分重要。 *) Coercion AId : string >-> aexp. Coercion ANum : nat >-> aexp. -Definition bool_to_bexp (b: bool) : bexp := + +Definition bool_to_bexp (b : bool) : bexp := if b then BTrue else BFalse. Coercion bool_to_bexp : bool >-> bexp. -Bind Scope aexp_scope with aexp. -Infix "+" := APlus : aexp_scope. -Infix "-" := AMinus : aexp_scope. -Infix "*" := AMult : aexp_scope. -Bind Scope bexp_scope with bexp. -Infix "<=" := BLe : bexp_scope. -Infix "=" := BEq : bexp_scope. -Infix "&&" := BAnd : bexp_scope. -Notation "'!' b" := (BNot b) (at level 60) : bexp_scope. +Bind Scope imp_scope with aexp. +Bind Scope imp_scope with bexp. +Delimit Scope imp_scope with imp. + +Notation "x + y" := (APlus x y) (at level 50, left associativity) : imp_scope. +Notation "x - y" := (AMinus x y) (at level 50, left associativity) : imp_scope. +Notation "x * y" := (AMult x y) (at level 40, left associativity) : imp_scope. +Notation "x <= y" := (BLe x y) (at level 70, no associativity) : imp_scope. +Notation "x = y" := (BEq x y) (at level 70, no associativity) : imp_scope. +Notation "x && y" := (BAnd x y) (at level 40, left associativity) : imp_scope. +Notation "'~' b" := (BNot b) (at level 75, right associativity) : imp_scope. (** 现在我们可以用 [3 + (X * 2)] 来代替 [APlus 3 (AMult X 2)] 了,同样可以用 - [true && !(X <= 4)] 来代替 [BAnd true (BNot (BLe X 4))] *) + [true && !(X <= 4)] 来代替 [BAnd true (BNot (BLe X 4))]。 *) + +Definition example_aexp := (3 + (X * 2))%imp : aexp. +Definition example_bexp := (true && ~(X <= 4))%imp : bexp. + +(** 强制转换有一点不便之处,即它会略微提高人类推导表达式类型的难度。 + 如果你感到有点困惑,请用 [Set Printing Coercions] 来查看具体发生了什么。 *) + +Set Printing Coercions. + +Print example_bexp. +(* ===> example_bexp = bool_to_bexp true && ~ (AId X <= ANum 4) *) + +Unset Printing Coercions. (* ================================================================= *) (** ** 求值 *) @@ -850,7 +918,7 @@ Notation "'!' b" := (BNot b) (at level 60) : bexp_scope. Fixpoint aeval (st : state) (a : aexp) : nat := match a with | ANum n => n - | AId x => st x (* <----- 新增 *) + | AId x => st x (* <--- 新增 *) | APlus a1 a2 => (aeval st a1) + (aeval st a2) | AMinus a1 a2 => (aeval st a1) - (aeval st a2) | AMult a1 a2 => (aeval st a1) * (aeval st a2) @@ -866,28 +934,21 @@ Fixpoint beval (st : state) (b : bexp) : bool := | BAnd b1 b2 => andb (beval st b1) (beval st b2) end. -(** 我们为具体状态的全映射声明具体的记法,即使用 [{ --> 0 }] 作为空状态。 *) - -Notation "{ a --> x }" := - (t_update { --> 0 } a x) (at level 0). -Notation "{ a --> x ; b --> y }" := - (t_update ({ a --> x }) b y) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z }" := - (t_update ({ a --> x ; b --> y }) c z) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z ; d --> t }" := - (t_update ({ a --> x ; b --> y ; c --> z }) d t) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }" := - (t_update ({ a --> x ; b --> y ; c --> z ; d --> t }) e u) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }" := - (t_update ({ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }) f v) (at level 0). +(** 我们为具体状态的全映射声明具体的记法,即使用 [(_ !-> 0)] 作为空状态。 *) + +Definition empty_st := (_ !-> 0). + +(** 现在我们可以为“单例状态(singleton state)”添加新的记法了, + 即只有一个绑定到值的变量。 *) +Notation "a '!->' x" := (t_update empty_st a x) (at level 100). Example aexp1 : - aeval { X --> 5 } (3 + (X * 2)) + aeval (X !-> 5) (3 + (X * 2))%imp = 13. Proof. reflexivity. Qed. Example bexp1 : - beval { X --> 5 } (true && !(X <= 4)) + beval (X !-> 5) (true && ~(X <= 4))%imp = true. Proof. reflexivity. Qed. @@ -900,19 +961,18 @@ Proof. reflexivity. Qed. (* ================================================================= *) (** ** 语法 *) -(** 指令 [c] 可以用以下 BNF 文法非形式化地描述。(为了能够使用 Coq - 的记法机制来定义 Imp 语法,我们选择了这种略尴尬的具体语法。具体来说, - 我们使用了 [IFB] 来避免与表中库中的 [if] 记法相冲突。) +(** 指令 [c] 可以用以下 BNF 文法非形式化地描述。 - c ::= SKIP | x ::= a | c ;; c | IFB b THEN c ELSE c FI + c ::= SKIP | x ::= a | c ;; c | TEST b THEN c ELSE c FI | WHILE b DO c END -*) -(** + + (为了能够使用 Coq 的记法机制来定义 Imp 语法,我们选择了这种略尴尬的具体语法。 + 具体来说,我们使用了 [TEST] 来避免与表中库中的 [if] 记法相冲突。) 例如,下面是用 Imp 编写的阶乘: Z ::= X;; Y ::= 1;; - WHILE ! (Z = 0) DO + WHILE ~(Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 END @@ -930,30 +990,102 @@ Inductive com : Type := (** 至于表达式,我们可以用一些 [Notation] 声明来让 Imp 程序的读写更加方便。 *) -Bind Scope com_scope with com. +Bind Scope imp_scope with com. Notation "'SKIP'" := - CSkip : com_scope. + CSkip : imp_scope. Notation "x '::=' a" := - (CAss x a) (at level 60) : com_scope. + (CAss x a) (at level 60) : imp_scope. Notation "c1 ;; c2" := - (CSeq c1 c2) (at level 80, right associativity) : com_scope. + (CSeq c1 c2) (at level 80, right associativity) : imp_scope. Notation "'WHILE' b 'DO' c 'END'" := - (CWhile b c) (at level 80, right associativity) : com_scope. -Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" := - (CIf c1 c2 c3) (at level 80, right associativity) : com_scope. - -(** 以下声明可以让这些记法在模式匹配中使用。 *) -Open Scope com_scope. + (CWhile b c) (at level 80, right associativity) : imp_scope. +Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" := + (CIf c1 c2 c3) (at level 80, right associativity) : imp_scope. (** 例如,下面是个阶乘函数,写成 Coq 的形式化定义: *) Definition fact_in_coq : com := - Z ::= X;; + (Z ::= X;; Y ::= 1;; - WHILE ! (Z = 0) DO + WHILE ~(Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 - END. + END)%imp. + +(* ================================================================= *) +(** ** 脱糖记法 *) + +(** Coq 为管理日益复杂的工作对象提供了丰富的特性,例如隐式转换和记法。 + 然而,过度使用它们会产生繁杂的语法。为了教学,我们通常会用以下命令来 + “关闭”这些特性以获得对事物更加本质的描述: + + - [Unset Printing Notations](用 [Set Printing Notations] 撤销) + - [Set Printing Coercions](用 [Unset Printing Coercions] 撤销) + - [Set Printing All](用 [Unset Printing All] 撤销) + + 这些命令也可在证明过程中详述当前目标和上下文。 *) + +Unset Printing Notations. +Print fact_in_coq. +(* ===> + fact_in_coq = + CSeq (CAss Z X) + (CSeq (CAss Y (S O)) + (CWhile (BNot (BEq Z O)) + (CSeq (CAss Y (AMult Y Z)) + (CAss Z (AMinus Z (S O)))))) + : com *) +Set Printing Notations. + +Set Printing Coercions. +Print fact_in_coq. +(* ===> + fact_in_coq = + (Z ::= AId X;; + Y ::= ANum 1;; + WHILE ~ (AId Z = ANum 0) DO + Y ::= AId Y * AId Z;; + Z ::= AId Z - ANum 1 + END)%imp + : com *) +Unset Printing Coercions. + +(* ================================================================= *) +(** ** [Locate] 命令 *) + +(* ----------------------------------------------------------------- *) +(** *** 查询记法 *) + +(** 当遇到未知记法时,可使用 [Locate] 后跟一个包含其符号的_'字符串'_ + 来查看其可能的解释。 *) +Locate "&&". +(* ===> + Notation "x && y" := andb x y : bool_scope (default interpretation) *) + +Locate ";;". +(* ===> + Notation "c1 ;; c2" := CSeq c1 c2 : imp_scope (default interpretation) *) + +Locate "WHILE". +(* ===> + Notation "'WHILE' b 'DO' c 'END'" := CWhile b c : imp_scope + (default interpretation) *) + +(* ----------------------------------------------------------------- *) +(** *** 查询标识符 *) + +(** 当以标示符使用 [Locate] 时,它会打印作用域中同名的所有值的完成路径。 + 它很适合解决由变量覆盖所引起的问题。 *) +Locate aexp. +(* ===> + Inductive Top.aexp + Inductive Top.AExp.aexp + (shorter name to refer to it in current context is AExp.aexp) + Inductive Top.aevalR_division.aexp + (shorter name to refer to it in current context is aevalR_division.aexp) + Inductive Top.aevalR_extended.aexp + (shorter name to refer to it in current context is aevalR_extended.aexp) +*) (* ================================================================= *) (** ** 更多示例 *) @@ -971,12 +1103,12 @@ Definition subtract_slowly_body : com := X ::= X - 1. (* ----------------------------------------------------------------- *) -(** *** Loops *) +(** *** 循环 *) Definition subtract_slowly : com := - WHILE ! (X = 0) DO + (WHILE ~(X = 0) DO subtract_slowly_body - END. + END)%imp. Definition subtract_3_from_5_slowly : com := X ::= 3 ;; @@ -984,7 +1116,7 @@ Definition subtract_3_from_5_slowly : com := subtract_slowly. (* ----------------------------------------------------------------- *) -(** *** An infinite loop: *) +(** *** 无限循环: *) Definition loop : com := WHILE true DO @@ -1002,23 +1134,26 @@ Definition loop : com := (** 下面是一次为指令定义求值函数的尝试,我们忽略了 [WHILE] 的情况。 *) +(** 为了在模式匹配中使用记法,我们需要以下声明。 *) +Open Scope imp_scope. Fixpoint ceval_fun_no_while (st : state) (c : com) : state := match c with | SKIP => st | x ::= a1 => - st & { x --> (aeval st a1) } + (x !-> (aeval st a1) ; st) | c1 ;; c2 => let st' := ceval_fun_no_while st c1 in ceval_fun_no_while st' c2 - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => if (beval st b) then ceval_fun_no_while st c1 else ceval_fun_no_while st c2 | WHILE b DO c END => st (* 假装能用 *) end. +Close Scope imp_scope. (** 在 OCaml 或 Haskell 这类传统的函数式编程语言中,我们可以像下面这样添加 [WHILE] 的情况: @@ -1028,7 +1163,7 @@ Fixpoint ceval_fun_no_while (st : state) (c : com) ... | WHILE b DO c END => if (beval st b) - then ceval_fun st (c;; WHILE b DO c END) + then ceval_fun st (c ;; WHILE b DO c END) else st end. @@ -1059,7 +1194,7 @@ Fixpoint ceval_fun_no_while (st : state) (c : com) [any] 这样非确定性的特性,我们需要让求值的定义也是非确定性的 -- 即,它不仅会有不完全性,甚至还可以不是个函数! *) -(** 我们将使用记法 [c / st \\ st'] 来表示 [ceval] 这种关系:[c / st \\ st'] +(** 我们将使用记法 [st =[ c ]=> st'] 来表示 [ceval] 这种关系:[st =[ c ]=> st'] 表示在开始状态 [st] 下启动程序并在结束状态 [st'] 下产生结果。它可以读作: “[c] 将状态 [st] 变成 [st']”。 *) @@ -1068,111 +1203,116 @@ Fixpoint ceval_fun_no_while (st : state) (c : com) (** 下面是求值的非形式化定义,为了可读性表示成推理规则: - ---------------- (E_Skip) - SKIP / st \\ st + ----------------- (E_Skip) + st =[ SKIP ]=> st aeval st a1 = n - -------------------------------- (E_Ass) - x := a1 / st \\ st & { x --> n } + -------------------------------- (E_Ass) + st =[ x := a1 ]=> (x !-> n ; st) - c1 / st \\ st' - c2 / st' \\ st'' - ------------------- (E_Seq) - c1;;c2 / st \\ st'' + st =[ c1 ]=> st' + st' =[ c2 ]=> st'' + --------------------- (E_Seq) + st =[ c1;;c2 ]=> st'' beval st b1 = true - c1 / st \\ st' - ------------------------------------- (E_IfTrue) - IF b1 THEN c1 ELSE c2 FI / st \\ st' + st =[ c1 ]=> st' + --------------------------------------- (E_IfTrue) + st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st' beval st b1 = false - c2 / st \\ st' - ------------------------------------- (E_IfFalse) - IF b1 THEN c1 ELSE c2 FI / st \\ st' + st =[ c2 ]=> st' + --------------------------------------- (E_IfFalse) + st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st' beval st b = false - ------------------------------ (E_WhileFalse) - WHILE b DO c END / st \\ st + ----------------------------- (E_WhileFalse) + st =[ WHILE b DO c END ]=> st beval st b = true - c / st \\ st' - WHILE b DO c END / st' \\ st'' - --------------------------------- (E_WhileTrue) - WHILE b DO c END / st \\ st'' + st =[ c ]=> st' + st' =[ WHILE b DO c END ]=> st'' + -------------------------------- (E_WhileTrue) + st =[ WHILE b DO c END ]=> st'' *) (** 下面是它的形式化定义。请确保你理解了它是如何与以上推理规则相对应的。 *) -Reserved Notation "c1 '/' st '\\' st'" - (at level 40, st at level 39). +Reserved Notation "st '=[' c ']=>' st'" + (at level 40). Inductive ceval : com -> state -> state -> Prop := | E_Skip : forall st, - SKIP / st \\ st + st =[ SKIP ]=> st | E_Ass : forall st a1 n x, aeval st a1 = n -> - (x ::= a1) / st \\ st & { x --> n } + st =[ x ::= a1 ]=> (x !-> n ; st) | E_Seq : forall c1 c2 st st' st'', - c1 / st \\ st' -> - c2 / st' \\ st'' -> - (c1 ;; c2) / st \\ st'' + st =[ c1 ]=> st' -> + st' =[ c2 ]=> st'' -> + st =[ c1 ;; c2 ]=> st'' | E_IfTrue : forall st st' b c1 c2, beval st b = true -> - c1 / st \\ st' -> - (IFB b THEN c1 ELSE c2 FI) / st \\ st' + st =[ c1 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' | E_IfFalse : forall st st' b c1 c2, beval st b = false -> - c2 / st \\ st' -> - (IFB b THEN c1 ELSE c2 FI) / st \\ st' + st =[ c2 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' | E_WhileFalse : forall b st c, beval st b = false -> - (WHILE b DO c END) / st \\ st + st =[ WHILE b DO c END ]=> st | E_WhileTrue : forall st st' st'' b c, beval st b = true -> - c / st \\ st' -> - (WHILE b DO c END) / st' \\ st'' -> - (WHILE b DO c END) / st \\ st'' + st =[ c ]=> st' -> + st' =[ WHILE b DO c END ]=> st'' -> + st =[ WHILE b DO c END ]=> st'' - where "c1 '/' st '\\' st'" := (ceval c1 st st'). + where "st =[ c ]=> st'" := (ceval c st st'). (** 将求值定义成关系而非函数的代价是,我们需要自己为某个程序求值成某种结束状态_'构造证明'_, 而不能只是交给 Coq 的计算机制去做了。 *) Example ceval_example1: - (X ::= 2;; - IFB X <= 1 + empty_st =[ + X ::= 2;; + TEST X <= 1 THEN Y ::= 3 ELSE Z ::= 4 - FI) - / { --> 0 } \\ { X --> 2 ; Z --> 4 }. + FI + ]=> (Z !-> 4 ; X !-> 2). Proof. (* 我们必须提供中间状态 *) - apply E_Seq with { X --> 2 }. + apply E_Seq with (X !-> 2). - (* 赋值指令 *) apply E_Ass. reflexivity. - (* if 指令 *) apply E_IfFalse. - reflexivity. - apply E_Ass. reflexivity. Qed. + reflexivity. + apply E_Ass. reflexivity. +Qed. -(** **** 练习:2 星 (ceval_example2) *) +(** **** 练习:2 星, standard (ceval_example2) *) Example ceval_example2: - (X ::= 0;; Y ::= 1;; Z ::= 2) / { --> 0 } \\ - { X --> 0 ; Y --> 1 ; Z --> 2 }. + empty_st =[ + X ::= 0;; Y ::= 1;; Z ::= 2 + ]=> (Z !-> 2 ; Y !-> 1 ; X !-> 0). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (pup_to_n) *) -(** 写一个 Imp 程序对从 [1] 到 [X] 进行求值(包括:将 [1 + 2 + ... + X]) 赋予变量 [Y]。 +(** **** 练习:3 星, standard, optional (pup_to_n) + + 写一个 Imp 程序对从 [1] 到 [X] 进行求值(包括:将 [1 + 2 + ... + X]) 赋予变量 [Y]。 证明此程序对于 [X] = [2] 会按预期执行(这可能比你预想的还要棘手)。 *) Definition pup_to_n : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Theorem pup_to_2_ceval : - pup_to_n / { X --> 2 } - \\ { X --> 2 ; Y --> 0 ; Y --> 2 ; X --> 1 ; Y --> 3 ; X --> 0 }. + (X !-> 2) =[ + pup_to_n + ]=> (X !-> 0 ; Y !-> 3 ; X !-> 1 ; Y !-> 2 ; Y !-> 0 ; X !-> 2). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -1189,8 +1329,8 @@ Proof. 实际上这不可能发生,因为 [ceval] _'确实'_是一个偏函数: *) Theorem ceval_deterministic: forall c st st1 st2, - c / st \\ st1 -> - c / st \\ st2 -> + st =[ c ]=> st1 -> + st =[ c ]=> st2 -> st1 = st2. Proof. intros c st st1 st2 E1 E2. @@ -1232,8 +1372,8 @@ Proof. Theorem plus2_spec : forall st n st', st X = n -> - plus2 / st \\ st' -> - st' X = (n + 2). + st =[ plus2 ]=> st' -> + st' X = n + 2. Proof. intros st n st' HX Heval. @@ -1244,8 +1384,9 @@ Proof. inversion Heval. subst. clear Heval. simpl. apply t_update_eq. Qed. -(** **** 练习:3 星, recommended (XtimesYinZ_spec) *) -(** 叙述并证明 [XtimesYinZ] 的规范(Specification)。 *) +(** **** 练习:3 星, standard, recommended (XtimesYinZ_spec) + + 叙述并证明 [XtimesYinZ] 的规范(Specification)。 *) (* 请在此处解答 *) @@ -1253,12 +1394,12 @@ Proof. Definition manual_grade_for_XtimesYinZ_spec : option (nat*string) := None. (** [] *) -(** **** 练习:3 星, recommended (loop_never_stops) *) +(** **** 练习:3 星, standard, recommended (loop_never_stops) *) Theorem loop_never_stops : forall st st', - ~(loop / st \\ st'). + ~(st =[ loop ]=> st'). Proof. intros st st' contra. unfold loop in contra. - remember (WHILE true DO SKIP END) as loopdef + remember (WHILE true DO SKIP END)%imp as loopdef eqn:Heqloopdef. (** 归纳讨论假设“[loopdef] 会终止”之构造,其中多数情形的矛盾显而易见, @@ -1267,9 +1408,11 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (no_whiles_eqv) *) -(** 考虑以下函数: *) +(** **** 练习:3 星, standard (no_whiles_eqv) + + 考虑以下函数: *) +Open Scope imp_scope. Fixpoint no_whiles (c : com) : bool := match c with | SKIP => @@ -1278,11 +1421,12 @@ Fixpoint no_whiles (c : com) : bool := true | c1 ;; c2 => andb (no_whiles c1) (no_whiles c2) - | IFB _ THEN ct ELSE cf FI => + | TEST _ THEN ct ELSE cf FI => andb (no_whiles ct) (no_whiles cf) | WHILE _ DO _ END => false end. +Close Scope imp_scope. (** 此断言只对没有 [WHILE] 循环的程序产生 [true]。请用 [Inductive] 写出一个性质 [no_whilesR] 使得 [no_whilesR c] 仅当 [c] 是个没有 @@ -1298,10 +1442,12 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星 (no_whiles_terminating) *) -(** 不涉及 [WHILE] 循环的 Imp 程序一定会终止。请陈述并证明定理 - [no_whiles_terminating] 来说明这一点。 *) -(** 按照你的偏好使用 [no_whiles] 或 [no_whilesR]。 *) +(** **** 练习:4 星, standard (no_whiles_terminating) + + 不涉及 [WHILE] 循环的 Imp 程序一定会终止。请陈述并证明定理 + [no_whiles_terminating] 来说明这一点。 + + 按照你的偏好使用 [no_whiles] 或 [no_whilesR]。 *) (* 请在此处解答 *) @@ -1312,8 +1458,9 @@ Definition manual_grade_for_no_whiles_terminating : option (nat*string) := None. (* ################################################################# *) (** * 附加练习 *) -(** **** 练习:3 星 (stack_compiler) *) -(** 旧式惠普计算器的编程语言类似于 Forth 和 Postscript,而其抽象机器类似于 +(** **** 练习:3 星, standard (stack_compiler) + + 旧式惠普计算器的编程语言类似于 Forth 和 Postscript,而其抽象机器类似于 Java 虚拟机,即所有对算术表达式的求值都使用_'栈'_来进行。例如,表达式 (2*3)+(3*(4-2)) @@ -1364,13 +1511,13 @@ Fixpoint s_execute (st : state) (stack : list nat) (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Example s_execute1 : - s_execute { --> 0 } [] + s_execute empty_st [] [SPush 5; SPush 3; SPush 1; SMinus] = [2; 5]. (* 请在此处解答 *) Admitted. Example s_execute2 : - s_execute { X --> 3 } [3;4] + s_execute (X !-> 3) [3;4] [SPush 4; SLoad X; SMult; SPlus] = [15; 4]. (* 请在此处解答 *) Admitted. @@ -1384,13 +1531,14 @@ Fixpoint s_compile (e : aexp) : list sinstr (** 在定义完 [s_compile] 之后,请证明以下示例来测试它是否起作用。 *) Example s_compile1 : - s_compile (X - (2 * Y)) + s_compile (X - (2 * Y))%imp = [SLoad X; SPush 2; SLoad Y; SMult; SMinus]. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced (stack_compiler_correct) *) -(** 现在我们将证明在之前练习中实现的编译器的正确性。记住当栈中的元素少于两个时, +(** **** 练习:4 星, advanced (stack_compiler_correct) + + 现在我们将证明在之前练习中实现的编译器的正确性。记住当栈中的元素少于两个时, 规范并未指定 [SPlus]、[SMinus] 或 [SMult] 指令的行为。 (为了让正确性证明更加容易,你可能需要返回去修改你的实现!) @@ -1403,8 +1551,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (short_circuit) *) -(** 大部分现代编程语言对布尔 [and] 运算提供了“短路求值”的方法:要对 +(** **** 练习:3 星, standard, optional (short_circuit) + + 大部分现代编程语言对布尔 [and] 运算提供了“短路求值”的方法:要对 [BAnd b1 b2] 进行求值,首先对 [b1] 求值。如果结果为 [false],那么整个 [BAnd] 表达式的求值就是 [false],而无需对 [b2] 求值。否则,[b2] 的求值结果就决定了 [BAnd] 表达式的值。 @@ -1414,17 +1563,19 @@ Proof. 在更大的语言中该表达式可能会发散,此时短路求值的 [BAnd] _'并不'_ 等价于原始版本,因为它能让更多程序终止。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) Module BreakImp. -(** **** 练习:4 星, advanced (break_imp) *) -(** 像 C 和 Java 这样的指令式语言通常会包含 [break] 或类似地语句来中断循环的执行。 +(** **** 练习:4 星, advanced (break_imp) + + 像 C 和 Java 这样的指令式语言通常会包含 [break] 或类似地语句来中断循环的执行。 在本练习中,我们考虑如何为 Imp 加上 [break]。首先,我们需要丰富语言的指令。 *) Inductive com : Type := | CSkip - | CBreak (* <-- 新增 *) + | CBreak (* <--- 新增 *) | CAss (x : string) (a : aexp) | CSeq (c1 c2 : com) | CIf (b : bexp) (c1 c2 : com) @@ -1440,7 +1591,7 @@ Notation "c1 ;; c2" := (CSeq c1 c2) (at level 80, right associativity). Notation "'WHILE' b 'DO' c 'END'" := (CWhile b c) (at level 80, right associativity). -Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" := +Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" := (CIf c1 c2 c3) (at level 80, right associativity). (** 接着,我们需要定义 [BREAK] 的行为。非形式化地说,只要 [BREAK] @@ -1453,8 +1604,8 @@ Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" := X ::= 0;; Y ::= 1;; - WHILE 0 <> Y DO - WHILE TRUE DO + WHILE ~(0 = Y) DO + WHILE true DO BREAK END;; X ::= 1;; @@ -1470,15 +1621,15 @@ Inductive result : Type := | SContinue | SBreak. -Reserved Notation "c1 '/' st '\\' s '/' st'" - (at level 40, st, s at level 39). +Reserved Notation "st '=[' c ']=>' st' '/' s" + (at level 40, st' at next level). -(** 直觉上说,[c / st \\ s / st'] 表示如果 [c] 在 [st] 状况下开始, +(** 直觉上说,[st =[ c ]=> st' / s] 表示如果 [c] 在 [st] 状况下开始, 它会在 [st'] 状态下终止,围绕它的最内层循环(或整个程序) 要么收到立即退出的信号([s = SBreak]),要么继续正常执行([s = SContinue])。 - “[c / st \\ s / st']”关系的定义非常类似于之前我们为一般求值关系 - ([c / st \\ st'])给出的定义 -- 我们只需要恰当地处理终止信号。 + “[st =[ c ]=> st' / s]”关系的定义非常类似于之前我们为一般求值关系 + ([st =[ c ]=> st'])给出的定义 -- 我们只需要恰当地处理终止信号。 - 若指令为 [SKIP],则状态不变,任何围绕它的循环继续正常执行。 @@ -1486,7 +1637,7 @@ Reserved Notation "c1 '/' st '\\' s '/' st'" - 若指令为赋值,则根据状态更新该变量绑定的值,并发出继续正常执行的信号。 - - 若指令为 [IFB b THEN c1 ELSE c2 FI] 的形式,则按照 Imp 的原始语义更新状态, + - 若指令为 [TEST b THEN c1 ELSE c2 FI] 的形式,则按照 Imp 的原始语义更新状态, 除此之外我们还要从被选择执行的分支中传播信号。 - 若指令为一系列 [c1 ;; c2],我们首先执行 [c1]。如果它产生了 @@ -1504,46 +1655,46 @@ Reserved Notation "c1 '/' st '\\' s '/' st'" Inductive ceval : com -> state -> result -> state -> Prop := | E_Skip : forall st, - CSkip / st \\ SContinue / st + st =[ CSkip ]=> st / SContinue (* 请在此处解答 *) - where "c1 '/' st '\\' s '/' st'" := (ceval c1 st s st'). + where "st '=[' c ']=>' st' '/' s" := (ceval c st s st'). (** 现在证明你定义的 [ceval] 的如下性质: *) Theorem break_ignore : forall c st st' s, - (BREAK;; c) / st \\ s / st' -> + st =[ BREAK;; c ]=> st' / s -> st = st'. Proof. (* 请在此处解答 *) Admitted. Theorem while_continue : forall b c st st' s, - (WHILE b DO c END) / st \\ s / st' -> + st =[ WHILE b DO c END ]=> st' / s -> s = SContinue. Proof. (* 请在此处解答 *) Admitted. Theorem while_stops_on_break : forall b c st st', beval st b = true -> - c / st \\ SBreak / st' -> - (WHILE b DO c END) / st \\ SContinue / st'. + st =[ c ]=> st' / SBreak -> + st =[ WHILE b DO c END ]=> st' / SContinue. Proof. (* 请在此处解答 *) Admitted. (** [] *) (** **** 练习:3 星, advanced, optional (while_break_true) *) Theorem while_break_true : forall b c st st', - (WHILE b DO c END) / st \\ SContinue / st' -> + st =[ WHILE b DO c END ]=> st' / SContinue -> beval st' b = true -> - exists st'', c / st'' \\ SBreak / st'. + exists st'', st'' =[ c ]=> st' / SBreak. Proof. (* 请在此处解答 *) Admitted. (** [] *) (** **** 练习:4 星, advanced, optional (ceval_deterministic) *) Theorem ceval_deterministic: forall (c:com) st st1 st2 s1 s2, - c / st \\ s1 / st1 -> - c / st \\ s2 / st2 -> + st =[ c ]=> st1 / s1 -> + st =[ c ]=> st2 / s2 -> st1 = st2 /\ s1 = s2. Proof. (* 请在此处解答 *) Admitted. @@ -1551,8 +1702,9 @@ Proof. (** [] *) End BreakImp. -(** **** 练习:4 星, optional (add_for_loop) *) -(** 为该语言添加 C 风格的 [for] 循环指令,更新 [ceval] 的定义来定义 +(** **** 练习:4 星, standard, optional (add_for_loop) + + 为该语言添加 C 风格的 [for] 循环指令,更新 [ceval] 的定义来定义 [for] 循环,按需添加 [for] 循环的情况使得本文件中的所有证明都被 Coq 所接受。 @@ -1561,7 +1713,9 @@ End BreakImp. (c) 一个在循环的每次迭代最后执行的语句,以及 (d) 一个创建循环体的语句 (你不必关心为 [for] 构造一个具体的记法,不过如果你喜欢,可以随意去做。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/ImpCEvalFun.html b/lf-current/ImpCEvalFun.html index 70cf52b8..13b13c6f 100644 --- a/lf-current/ImpCEvalFun.html +++ b/lf-current/ImpCEvalFun.html @@ -42,14 +42,14 @@- “c / st \\ s / st'”关系的定义非常类似于之前我们为一般求值关系 - (c / st \\ st')给出的定义 — 我们只需要恰当地处理终止信号。 + “st =[ c ]⇒ st' / s”关系的定义非常类似于之前我们为一般求值关系 + (st =[ c ]⇒ st')给出的定义 — 我们只需要恰当地处理终止信号。@@ -2259,7 +2431,7 @@Imp简单的指令式程序 -
若指令为 IFB b THEN c1 ELSE c2 FI 的形式,则按照 Imp 的原始语义更新状态, + 若指令为 TEST b THEN c1 ELSE c2 FI 的形式,则按照 Imp 的原始语义更新状态, 除此之外我们还要从被选择执行的分支中传播信号。 @@ -2290,11 +2462,11 @@Imp简单的指令式程序
Inductive ceval : com → state → result → state → Prop :=
- | E_Skip : ∀ st,
- CSkip / st \\ SContinue / st
+ | E_Skip : ∀st,
+ st =[ CSkip ]⇒ st / SContinue
(* 请在此处解答 *)
- where "c1 '/' st '\\' s '/' st'" := (ceval c1 st s st').
+ where "st '=[' c ']⇒' st' '/' s" := (ceval c st s st').
@@ -2302,20 +2474,20 @@Imp简单的指令式程序
-Theorem break_ignore : ∀ c st st' s,@@ -2324,14 +2496,14 @@
- (BREAK;; c) / st \\ s / st' →
+Theorem break_ignore : ∀c st st' s,
+ st =[ BREAK;; c ]⇒ st' / s →
st = st'.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem while_continue : ∀ b c st st' s,
- (WHILE b DO c END) / st \\ s / st' →
+Theorem while_continue : ∀b c st st' s,
+ st =[ WHILE b DO c END ]⇒ st' / s →
s = SContinue.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem while_stops_on_break : ∀ b c st st',
+Theorem while_stops_on_break : ∀b c st st',
beval st b = true →
- c / st \\ SBreak / st' →
- (WHILE b DO c END) / st \\ SContinue / st'.
+ st =[ c ]⇒ st' / SBreak →
+ st =[ WHILE b DO c END ]⇒ st' / SContinue.
Proof.
(* 请在此处解答 *) Admitted.
Imp简单的指令式程序
-Theorem while_break_true : ∀ b c st st',@@ -2340,13 +2512,13 @@
- (WHILE b DO c END) / st \\ SContinue / st' →
+Theorem while_break_true : ∀b c st st',
+ st =[ WHILE b DO c END ]⇒ st' / SContinue →
beval st' b = true →
- ∃ st'', c / st'' \\ SBreak / st'.
+ ∃st'', st'' =[ c ]⇒ st' / SBreak.
Proof.
(* 请在此处解答 *) Admitted.
Imp简单的指令式程序
-Theorem ceval_deterministic: ∀ (c:com) st st1 st2 s1 s2,
- c / st \\ s1 / st1 →
- c / st \\ s2 / st2 →
+Theorem ceval_deterministic: ∀(c:com) st st1 st2 s1 s2,
+ st =[ c ]⇒ st1 / s1 →
+ st =[ c ]⇒ st2 / s2 →
st1 = st2 ∧ s1 = s2.
Proof.
(* 请在此处解答 *) Admitted.
@@ -2358,7 +2530,7 @@Imp简单的指令式程序
-☐ +练习:4 星, optional (add_for_loop)
+练习:4 星, standard, optional (add_for_loop)
为该语言添加 C 风格的 for 循环指令,更新 ceval 的定义来定义 for 循环,按需添加 for 循环的情况使得本文件中的所有证明都被 Coq 所接受。 @@ -2376,6 +2548,10 @@Imp简单的指令式程序
+ +(* Sat Jan 26 15:14:46 UTC 2019 *)
+ImpCEvalFunImp 的求值函数
@@ -58,30 +58,34 @@
-Require Import Coq.omega.Omega.
-Require Import Coq.Arith.Arith.
+From Coq Require Import omega.Omega.
+From Coq Require Import Arith.Arith.
From LF Require Import Imp Maps.
ImpCEvalFunImp 的求值函数
+Open Scope imp_scope.
Fixpoint ceval_step1 (st : state) (c : com) : state :=
match c with
| SKIP ⇒
st
| l ::= a1 ⇒
- st & { l --> (aeval st a1)}
+ (l !-> aeval st a1 ; st)
| c1 ;; c2 ⇒
let st' := ceval_step1 st c1 in
ceval_step1 st' c2
- | IFB b THEN c1 ELSE c2 FI ⇒
+ | TEST b THEN c1 ELSE c2 FI ⇒
if (beval st b)
then ceval_step1 st c1
else ceval_step1 st c2
| WHILE b1 DO c1 END ⇒
st (* bogus *)
end.
+Close Scope imp_scope.
如Imp一章中所言,在 ML 或 Haskell 这类传统的函数式语言中, 我们可以这样处理 WHILE 指令:- | WHILE b1 DO c1 END => if (beval st b1) then ceval_step1 st (c1;; - WHILE b1 DO c1 END) else st + | WHILE b1 DO c1 END => + if (beval st b1) then + ceval_step1 st (c1;; WHILE b1 DO c1 END) + else stCoq 不会接受此定义(它会提示出现错误 Error: Cannot guess decreasing argument of fix),因为我们想要定义的函数无需保证一定停机。 @@ -102,7 +106,7 @@ImpCEvalFunImp 的求值函数
-一个计步的求值器
+一个计步的求值器
@@ -115,19 +119,20 @@ImpCEvalFunImp 的求值函数
+Open Scope imp_scope.
Fixpoint ceval_step2 (st : state) (c : com) (i : nat) : state :=
match i with
- | O ⇒ { --> 0 }
+ | O ⇒ empty_st
| S i' ⇒
match c with
| SKIP ⇒
st
| l ::= a1 ⇒
- st & { l --> (aeval st a1) }
+ (l !-> aeval st a1 ; st)
| c1 ;; c2 ⇒
let st' := ceval_step2 st c1 i' in
ceval_step2 st' c2 i'
- | IFB b THEN c1 ELSE c2 FI ⇒
+ | TEST b THEN c1 ELSE c2 FI ⇒
if (beval st b)
then ceval_step2 st c1 i'
else ceval_step2 st c2 i'
@@ -138,6 +143,7 @@ImpCEvalFunImp 的求值函数else st
end
end.
+Close Scope imp_scope.
@@ -154,6 +160,7 @@通过命名这个表达式,我们可以让归纳证明更加明确。比如,除了陈述定理 - mult_0_r 为 “∀n, n * 0 = 0”,我们还可以写成 - “∀n, P_m0r n”,其中 O_m0r 定义为…… + mult_0_r 为 “∀ n, n * 0 = 0”,我们还可以写成 + “∀ n, P_m0r n”,其中 O_m0r 定义为……ImpCEvalFunImp 的求值函数
+Open Scope imp_scope.
Fixpoint ceval_step3 (st : state) (c : com) (i : nat)
: option state :=
match i with
@@ -163,13 +170,13 @@ImpCEvalFunImp 的求值函数SKIP ⇒
Some st
| l ::= a1 ⇒
- Some (st & { l --> (aeval st a1) })
+ Some (l !-> aeval st a1 ; st)
| c1 ;; c2 ⇒
match (ceval_step3 st c1 i') with
| Some st' ⇒ ceval_step3 st' c2 i'
| None ⇒ None
end
- | IFB b THEN c1 ELSE c2 FI ⇒
+ | TEST b THEN c1 ELSE c2 FI ⇒
if (beval st b)
then ceval_step3 st c1 i'
else ceval_step3 st c2 i'
@@ -182,6 +189,7 @@ImpCEvalFunImp 的求值函数else Some st
end
end.
+Close Scope imp_scope.
@@ -196,6 +204,7 @@@@ -270,7 +280,7 @@ImpCEvalFunImp 的求值函数None ⇒ None
end)
(right associativity, at level 60).
+Open Scope imp_scope.
Fixpoint ceval_step (st : state) (c : com) (i : nat)
: option state :=
match i with
@@ -205,11 +214,11 @@ImpCEvalFunImp 的求值函数SKIP ⇒
Some st
| l ::= a1 ⇒
- Some (st & { l --> (aeval st a1)})
+ Some (l !-> aeval st a1 ; st)
| c1 ;; c2 ⇒
LETOPT st' <== ceval_step st c1 i' IN
ceval_step st' c2 i'
- | IFB b THEN c1 ELSE c2 FI ⇒
+ | TEST b THEN c1 ELSE c2 FI ⇒
if (beval st b)
then ceval_step st c1 i'
else ceval_step st c2 i'
@@ -219,16 +228,17 @@ImpCEvalFunImp 的求值函数ceval_step st' c i'
else Some st
end
- end.
+ end.
+Close Scope imp_scope.
Definition test_ceval (st:state) (c:com) :=
match ceval_step st c 500 with
| None ⇒ None
| Some st ⇒ Some (st X, st Y, st Z)
end.
(* Compute
- (test_ceval { --> 0 }
+ (test_ceval empty_st
(X ::= 2;;
- IFB (X <= 1)
+ TEST (X <= 1)
THEN Y ::= 3
ELSE Z ::= 4
FI)).
@@ -237,7 +247,7 @@ImpCEvalFunImp 的求值函数
-@@ -248,7 +258,7 @@练习:2 星, recommended (pup_to_n)
+练习:2 星, standard, recommended (pup_to_n)
编写一个 Imp 程序对 1 到 X 求和(即 1 + 2 + ... + X)并赋值给 Y。 确保你的解答能满足之后的测试。ImpCEvalFunImp 的求值函数(*
Example pup_to_n_1 :
- test_ceval {X --> 5} pup_to_n
+ test_ceval (X !-> 5) pup_to_n
= Some (0, 15, 0).
Proof. reflexivity. Qed.
*)
@@ -258,7 +268,7 @@ImpCEvalFunImp 的求值函数
-练习:2 星, optional (peven)
+练习:2 星, standard, optional (peven)
编写一个 Imp 程序:该程序在 X 为偶数时将 Z 置为 0, 否则将 Z 置为 1。使用 test_ceval 测试你的程序。ImpCEvalFunImp 的求值函数☐
-关系求值 vs. 计步求值
+关系求值 vs. 计步求值
@@ -279,9 +289,9 @@ImpCEvalFunImp 的求值函数
-Theorem ceval_step__ceval: ∀ c st st',@@ -313,7 +313,7 @@
- (∃ i, ceval_step st c i = Some st') →
- c / st \\ st'.
+Theorem ceval_step__ceval: ∀c st st',
+ (∃i, ceval_step st c i = Some st') →
+ st =[ c ]⇒ st'.
Proof.@@ -247,17 +247,17 @@
@@ -308,7 +318,7 @@ImpCEvalFunImp 的求值函数apply IHi'. simpl in H1. assumption.
* (* Otherwise -- contradiction *)
discriminate H1.
- + (* IFB *)
+ + (* TEST *)
destruct (beval st b) eqn:Heqr.
* (* r = true *)
apply E_IfTrue. rewrite Heqr. reflexivity.
@@ -332,7 +342,7 @@ImpCEvalFunImp 的求值函数
-练习:4 星 (ceval_step__ceval_inf)
+练习:4 星, standard (ceval_step__ceval_inf)
按照通常的模版写出 ceval_step__ceval 的非形式化证明, (对归纳定义的值进行分类讨论的模版,除了没有归纳假设外, 应当看起来与归纳证明相同。)不要简单地翻译形式化证明的步骤, @@ -348,7 +358,7 @@ImpCEvalFunImp 的求值函数☐
-Theorem ceval_step_more: ∀ i1 i2 st st' c,
+Theorem ceval_step_more: ∀i1 i2 st st' c,
i1 ≤ i2 →
ceval_step st c i1 = Some st' →
ceval_step st c i2 = Some st'.
@@ -375,7 +385,7 @@ImpCEvalFunImp 的求值函数apply (IHi1' i2') in Hceval; try assumption.
* (* st1'o = None *)
discriminate Hceval.
- + (* IFB *)
+ + (* TEST *)
simpl in Hceval. simpl.
destruct (beval st b); apply (IHi1' i2') in Hceval;
assumption.
@@ -392,15 +402,15 @@ImpCEvalFunImp 的求值函数
-练习:3 星, recommended (ceval__ceval_step)
+练习:3 星, standard, recommended (ceval__ceval_step)
请完成以下证明。你会在某些地方用到 ceval_step_more 以及一些关于 ≤ 和 plus 的基本事实。-Theorem ceval__ceval_step: ∀ c st st',diff --git a/lf-current/ImpParser.v b/lf-current/ImpParser.v index a5e981c4..4d000d29 100644 --- a/lf-current/ImpParser.v +++ b/lf-current/ImpParser.v @@ -12,12 +12,12 @@ 但是大部分的读者大概只会粗略看一眼,然后跳到末尾的“例子”一节。 *) Set Warnings "-notation-overridden,-parsing". -Require Import Coq.Strings.String. -Require Import Coq.Strings.Ascii. -Require Import Coq.Arith.Arith. -Require Import Coq.Init.Nat. -Require Import Coq.Arith.EqNat. -Require Import Coq.Lists.List. +From Coq Require Import Strings.String. +From Coq Require Import Strings.Ascii. +From Coq Require Import Arith.Arith. +From Coq Require Import Init.Nat. +From Coq Require Import Arith.EqNat. +From Coq Require Import Lists.List. Import ListNotations. From LF Require Import Maps Imp. @@ -124,19 +124,20 @@ Arguments NoneE {X}. (** 加一些语法糖以便于编写嵌套的对 [optionE] 的匹配表达式。 *) -Notation "'DO' ( x , y ) <== e1 ; e2" +Notation "' p <- e1 ;; e2" := (match e1 with - | SomeE (x,y) => e2 - | NoneE err => NoneE err + | SomeE p => e2 + | NoneE err => NoneE err end) - (right associativity, at level 60). + (right associativity, p pattern, at level 60, e1 at next level). -Notation "'DO' ( x , y ) <-- e1 ; e2 'OR' e3" +Notation "'TRY' ' p <- e1 ;; e2 'OR' e3" := (match e1 with - | SomeE (x,y) => e2 - | NoneE err => e3 + | SomeE p => e2 + | NoneE _ => e3 end) - (right associativity, at level 60, e2 at next level). + (right associativity, p pattern, + at level 60, e1 at next level, e2 at next level). (* ----------------------------------------------------------------- *) (** *** 用于构建语法分析器的通用组合子 *) @@ -153,7 +154,7 @@ Fixpoint many_helper {T} (p : parser T) acc steps xs := | _, NoneE _ => SomeE ((rev acc), xs) | S steps', SomeE (t, xs') => - many_helper p (t::acc) steps' xs' + many_helper p (t :: acc) steps' xs' end. (** 一个要求符合 [p] 零到多次的、指定步数的词法分析器: *) @@ -177,7 +178,7 @@ Definition firstExpect {T} (t : token) (p : parser T) (** 一个要求某个特定词法标记的语法分析器: *) Definition expect (t : token) : parser unit := - firstExpect t (fun xs => SomeE(tt, xs)). + firstExpect t (fun xs => SomeE (tt, xs)). (* ----------------------------------------------------------------- *) (** *** 一个 Imp 的递归下降语法分析器 *) @@ -222,14 +223,15 @@ Fixpoint parsePrimaryExp (steps:nat) match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (i, rest) <-- parseIdentifier xs ; + TRY ' (i, rest) <- parseIdentifier xs ;; SomeE (AId i, rest) - OR DO (n, rest) <-- parseNumber xs ; + OR + TRY ' (n, rest) <- parseNumber xs ;; SomeE (ANum n, rest) - OR (DO (e, rest) <== firstExpect "(" - (parseSumExp steps') xs; - DO (u, rest') <== expect ")" rest ; - SomeE(e,rest')) + OR + ' (e, rest) <- firstExpect "(" (parseSumExp steps') xs ;; + ' (u, rest') <- expect ")" rest ;; + SomeE (e,rest') end with parseProductExp (steps:nat) @@ -237,11 +239,9 @@ with parseProductExp (steps:nat) match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (e, rest) <== - parsePrimaryExp steps' xs ; - DO (es, rest') <== - many (firstExpect "*" (parsePrimaryExp steps')) - steps' rest; + ' (e, rest) <- parsePrimaryExp steps' xs ;; + ' (es, rest') <- many (firstExpect "*" (parsePrimaryExp steps')) + steps' rest ;; SomeE (fold_left AMult es e, rest') end @@ -249,22 +249,22 @@ with parseSumExp (steps:nat) (xs : list token) := match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (e, rest) <== - parseProductExp steps' xs ; - DO (es, rest') <== - many (fun xs => - DO (e,rest') <-- - firstExpect "+" - (parseProductExp steps') xs; - SomeE ( (true, e), rest') - OR DO (e,rest') <== - firstExpect "-" - (parseProductExp steps') xs; - SomeE ( (false, e), rest')) - steps' rest; + ' (e, rest) <- parseProductExp steps' xs ;; + ' (es, rest') <- + many (fun xs => + TRY ' (e,rest') <- + firstExpect "+" + (parseProductExp steps') xs ;; + SomeE ( (true, e), rest') + OR + ' (e, rest') <- + firstExpect "-" + (parseProductExp steps') xs ;; + SomeE ( (false, e), rest')) + steps' rest ;; SomeE (fold_left (fun e0 term => match term with - (true, e) => APlus e0 e + | (true, e) => APlus e0 e | (false, e) => AMinus e0 e end) es e, @@ -280,32 +280,33 @@ Fixpoint parseAtomicExp (steps:nat) match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (u,rest) <-- expect "true" xs; + TRY ' (u,rest) <- expect "true" xs ;; SomeE (BTrue,rest) - OR DO (u,rest) <-- expect "false" xs; + OR + TRY ' (u,rest) <- expect "false" xs ;; SomeE (BFalse,rest) - OR DO (e,rest) <-- - firstExpect "!" - (parseAtomicExp steps') - xs; + OR + TRY ' (e,rest) <- firstExpect "~" + (parseAtomicExp steps') + xs ;; SomeE (BNot e, rest) - OR DO (e,rest) <-- - firstExpect "(" - (parseConjunctionExp steps') xs; - (DO (u,rest') <== expect ")" rest; - SomeE (e, rest')) - OR DO (e, rest) <== parseProductExp steps' xs; - (DO (e', rest') <-- - firstExpect "=" - (parseAExp steps') rest; - SomeE (BEq e e', rest') - OR DO (e', rest') <-- - firstExpect "<=" - (parseAExp steps') rest; - SomeE (BLe e e', rest') - OR - NoneE - "Expected '=' or '<=' after arithmetic expression") + OR + TRY ' (e,rest) <- firstExpect "(" + (parseConjunctionExp steps') + xs ;; + ' (u,rest') <- expect ")" rest ;; + SomeE (e, rest') + OR + ' (e, rest) <- parseProductExp steps' xs ;; + TRY ' (e', rest') <- firstExpect "=" + (parseAExp steps') rest ;; + SomeE (BEq e e', rest') + OR + TRY ' (e', rest') <- firstExpect "<=" + (parseAExp steps') rest ;; + SomeE (BLe e e', rest') + OR + NoneE "Expected '=' or '<=' after arithmetic expression" end with parseConjunctionExp (steps:nat) @@ -313,12 +314,10 @@ with parseConjunctionExp (steps:nat) match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (e, rest) <== - parseAtomicExp steps' xs ; - DO (es, rest') <== - many (firstExpect "&&" + ' (e, rest) <- parseAtomicExp steps' xs ;; + ' (es, rest') <- many (firstExpect "&&" (parseAtomicExp steps')) - steps' rest; + steps' rest ;; SomeE (fold_left BAnd es e, rest') end. @@ -336,10 +335,10 @@ Definition testParsing {X : Type} (* Eval compute in - testParsing parseProductExp "x*y*(x*x)*x". + testParsing parseProductExp "x.y.(x.x).x". Eval compute in - testParsing parseConjunctionExp "not((x=x||x*x<=(x*x)*x)&&x=x". + testParsing parseConjunctionExp "~(x=x&&x*x<=(x*x)*x)&&x=x". *) (** 解析指令: *) @@ -349,74 +348,110 @@ Fixpoint parseSimpleCommand (steps:nat) match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (u, rest) <-- expect "SKIP" xs; - SomeE (SKIP, rest) - OR DO (e,rest) <-- - firstExpect "IFB" (parseBExp steps') xs; - DO (c,rest') <== - firstExpect "THEN" - (parseSequencedCommand steps') rest; - DO (c',rest'') <== - firstExpect "ELSE" - (parseSequencedCommand steps') rest'; - DO (u,rest''') <== - expect "END" rest''; - SomeE(IFB e THEN c ELSE c' FI, rest''') - OR DO (e,rest) <-- - firstExpect "WHILE" - (parseBExp steps') xs; - DO (c,rest') <== - firstExpect "DO" - (parseSequencedCommand steps') rest; - DO (u,rest'') <== - expect "END" rest'; - SomeE(WHILE e DO c END, rest'') - OR DO (i, rest) <== - parseIdentifier xs; - DO (e, rest') <== - firstExpect ":=" (parseAExp steps') rest; - SomeE(i ::= e, rest') - end + TRY ' (u, rest) <- expect "SKIP" xs ;; + SomeE (SKIP%imp, rest) + OR + TRY ' (e,rest) <- + firstExpect "TEST" + (parseBExp steps') xs ;; + ' (c,rest') <- + firstExpect "THEN" + (parseSequencedCommand steps') rest ;; + ' (c',rest'') <- + firstExpect "ELSE" + (parseSequencedCommand steps') rest' ;; + ' (tt,rest''') <- + expect "END" rest'' ;; + SomeE(TEST e THEN c ELSE c' FI%imp, rest''') + OR + TRY ' (e,rest) <- + firstExpect "WHILE" + (parseBExp steps') xs ;; + ' (c,rest') <- + firstExpect "DO" + (parseSequencedCommand steps') rest ;; + ' (u,rest'') <- + expect "END" rest' ;; + SomeE(WHILE e DO c END%imp, rest'') + OR + TRY ' (i, rest) <- parseIdentifier xs ;; + ' (e, rest') <- firstExpect "::=" (parseAExp steps') rest ;; + SomeE ((i ::= e)%imp, rest') + OR + NoneE "Expecting a command" +end with parseSequencedCommand (steps:nat) (xs : list token) := match steps with | 0 => NoneE "Too many recursive calls" | S steps' => - DO (c, rest) <== - parseSimpleCommand steps' xs; - DO (c', rest') <-- - firstExpect ";;" - (parseSequencedCommand steps') rest; - SomeE(c ;; c', rest') - OR - SomeE(c, rest) + ' (c, rest) <- parseSimpleCommand steps' xs ;; + TRY ' (c', rest') <- + firstExpect ";;" + (parseSequencedCommand steps') rest ;; + SomeE ((c ;; c')%imp, rest') + OR + SomeE (c, rest) end. Definition bignumber := 1000. -Definition parse (str : string) : optionE (com * list token) := +Definition parse (str : string) : optionE com := let tokens := tokenize str in - parseSequencedCommand bignumber tokens. + match parseSequencedCommand bignumber tokens with + | SomeE (c, []) => SomeE c + | SomeE (_, t::_) => NoneE ("Trailing tokens remaining: " ++ t) + | NoneE err => NoneE err + end. (* ################################################################# *) (** * 示例 *) Example eg1 : parse " - IFB x = y + 1 + 2 - y * 6 + 3 THEN - x := x * 1;; - y := 0 + TEST x = y + 1 + 2 - y * 6 + 3 THEN + x ::= x * 1;; + y ::= 0 ELSE SKIP END " = SomeE ( - IFB "x" = "y" + 1 + 2 - "y" * 6 + 3 THEN - "x" ::= "x" * 1;; - "y" ::= 0 - ELSE - SKIP - FI, - []). -Proof. reflexivity. Qed. - + TEST "x" = "y" + 1 + 2 - "y" * 6 + 3 THEN + "x" ::= "x" * 1;; + "y" ::= 0 + ELSE + SKIP + FI)%imp. +Proof. cbv. reflexivity. Qed. + +Example eg2 : parse " + SKIP;; + z::=x*y*(x*x);; + WHILE x=x DO + TEST (z <= z*z) && ~(x = 2) THEN + x ::= z;; + y ::= z + ELSE + SKIP + END;; + SKIP + END;; + x::=z " += + SomeE ( + SKIP;; + "z" ::= "x" * "y" * ("x" * "x");; + WHILE "x" = "x" DO + TEST ("z" <= "z" * "z") && ~("x" = 2) THEN + "x" ::= "z";; + "y" ::= "z" + ELSE + SKIP + FI;; + SKIP + END;; + "x" ::= "z")%imp. +Proof. cbv. reflexivity. Qed. + +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/ImpParserTest.v b/lf-current/ImpParserTest.v index eed03e56..78c77b70 100644 --- a/lf-current/ImpParserTest.v +++ b/lf-current/ImpParserTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:15:01 UTC 2019 *) diff --git a/lf-current/ImpTest.v b/lf-current/ImpTest.v index 93a74520..29fd96b8 100644 --- a/lf-current/ImpTest.v +++ b/lf-current/ImpTest.v @@ -64,8 +64,8 @@ idtac " ". idtac "#> ceval_example2". idtac "Possible points: 2". check_type @ceval_example2 ( -((X ::= 0;; Y ::= 1;; Z ::= 2) / @Maps.t_empty nat 0 \\ - {X --> 0; Y --> 1; Z --> 2})). +(empty_st =[ X ::= 0;; Y ::= 1;; Z ::= 2 + ]=> @Maps.t_update nat (@Maps.t_update nat (X !-> 0) Y 1) Z 2)). idtac "Assumptions:". Abort. Print Assumptions ceval_example2. @@ -85,7 +85,7 @@ idtac " ". idtac "#> loop_never_stops". idtac "Possible points: 3". -check_type @loop_never_stops ((forall st st' : state, ~ loop / st \\ st')). +check_type @loop_never_stops ((forall st st' : state, ~ st =[ loop ]=> st')). idtac "Assumptions:". Abort. Print Assumptions loop_never_stops. @@ -118,7 +118,7 @@ idtac " ". idtac "#> s_execute1". idtac "Possible points: 0.5". check_type @s_execute1 ( -(s_execute (@Maps.t_empty nat 0) (@nil nat) +(s_execute empty_st (@nil nat) (SPush 5 :: (SPush 3 :: SPush 1 :: SMinus :: @nil sinstr)%list) = (2 :: 5 :: @nil nat)%list)). idtac "Assumptions:". @@ -130,7 +130,7 @@ idtac " ". idtac "#> s_execute2". idtac "Possible points: 0.5". check_type @s_execute2 ( -(s_execute {X --> 3} (3 :: (4 :: @nil nat)%list) +(s_execute (X !-> 3) (3 :: (4 :: @nil nat)%list) (SPush 4 :: (SLoad X :: SMult :: SPlus :: @nil sinstr)%list) = (15 :: 4 :: @nil nat)%list)). idtac "Assumptions:". @@ -245,3 +245,5 @@ Print Assumptions BreakImp.while_continue. idtac "---------- BreakImp.while_stops_on_break ---------". Print Assumptions BreakImp.while_stops_on_break. Abort. + +(* Sat Jan 26 15:15:00 UTC 2019 *) diff --git a/lf-current/IndPrinciples.html b/lf-current/IndPrinciples.html index 2c6aafa8..8af31c0d 100644 --- a/lf-current/IndPrinciples.html +++ b/lf-current/IndPrinciples.html @@ -45,7 +45,7 @@
- c / st \\ st' →
- ∃ i, ceval_step st c i = Some st'.
+Theorem ceval__ceval_step: ∀c st st',
+ st =[ c ]⇒ st' →
+ ∃i, ceval_step st c i = Some st'.
Proof.
intros c st st' Hce.
induction Hce.
@@ -410,9 +420,9 @@ImpCEvalFunImp 的求值函数☐
-Theorem ceval_and_ceval_step_coincide: ∀ c st st',
- c / st \\ st'
- ↔ ∃ i, ceval_step st c i = Some st'.
+Theorem ceval_and_ceval_step_coincide: ∀c st st',
+ st =[ c ]⇒ st'
+ ↔ ∃i, ceval_step st c i = Some st'.
Proof.
intros c st st'.
split. apply ceval__ceval_step. apply ceval_step__ceval.
@@ -420,7 +430,7 @@ImpCEvalFunImp 的求值函数
-diff --git a/lf-current/ImpCEvalFun.v b/lf-current/ImpCEvalFun.v index 10e69417..424b0501 100644 --- a/lf-current/ImpCEvalFun.v +++ b/lf-current/ImpCEvalFun.v @@ -7,34 +7,38 @@ (* ################################################################# *) (** * 一个无法完成的求值器 *) -Require Import Coq.omega.Omega. -Require Import Coq.Arith.Arith. +From Coq Require Import omega.Omega. +From Coq Require Import Arith.Arith. From LF Require Import Imp Maps. (** 在初次为指令编写求值函数时,我们写出了如下忽略了 [WHILE] 的代码: *) +Open Scope imp_scope. Fixpoint ceval_step1 (st : state) (c : com) : state := match c with | SKIP => st | l ::= a1 => - st & { l --> (aeval st a1)} + (l !-> aeval st a1 ; st) | c1 ;; c2 => let st' := ceval_step1 st c1 in ceval_step1 st' c2 - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => if (beval st b) then ceval_step1 st c1 else ceval_step1 st c2 | WHILE b1 DO c1 END => st (* bogus *) end. +Close Scope imp_scope. (** 如[Imp]一章中所言,在 ML 或 Haskell 这类传统的函数式语言中, 我们可以这样处理 [WHILE] 指令: - | WHILE b1 DO c1 END => if (beval st b1) then ceval_step1 st (c1;; - WHILE b1 DO c1 END) else st + | WHILE b1 DO c1 END => + if (beval st b1) then + ceval_step1 st (c1;; WHILE b1 DO c1 END) + else st Coq 不会接受此定义(它会提示出现错误 [Error: Cannot guess decreasing argument of fix]),因为我们想要定义的函数无需保证一定停机。 @@ -61,19 +65,20 @@ Fixpoint ceval_step1 (st : state) (c : com) : state := (我们也可以说当前的状态为求值器耗尽了汽油 -- 这无关紧要, 因为无论在哪种情况下结果都是错误的!) *) +Open Scope imp_scope. Fixpoint ceval_step2 (st : state) (c : com) (i : nat) : state := match i with - | O => { --> 0 } + | O => empty_st | S i' => match c with | SKIP => st | l ::= a1 => - st & { l --> (aeval st a1) } + (l !-> aeval st a1 ; st) | c1 ;; c2 => let st' := ceval_step2 st c1 i' in ceval_step2 st' c2 i' - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => if (beval st b) then ceval_step2 st c1 i' else ceval_step2 st c2 i' @@ -84,6 +89,7 @@ Fixpoint ceval_step2 (st : state) (c : com) (i : nat) : state := else st end end. +Close Scope imp_scope. (** _'注意'_:很容易想到这里的索引 [i] 是用来计算“求值的步数”的。 然而我们仔细研究就会发现实际并非如此。例如,在串连的规则中,同一个 @@ -94,6 +100,7 @@ Fixpoint ceval_step2 (st : state) (c : com) (i : nat) : state := 因为程序可能是正常停机,也可能是耗尽了汽油。我们的下下一个版本会返回一个 [option state] 而非只是一个 [state],这样我们就能区分正常和异常的停机了。 *) +Open Scope imp_scope. Fixpoint ceval_step3 (st : state) (c : com) (i : nat) : option state := match i with @@ -103,13 +110,13 @@ Fixpoint ceval_step3 (st : state) (c : com) (i : nat) | SKIP => Some st | l ::= a1 => - Some (st & { l --> (aeval st a1) }) + Some (l !-> aeval st a1 ; st) | c1 ;; c2 => match (ceval_step3 st c1 i') with | Some st' => ceval_step3 st' c2 i' | None => None end - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => if (beval st b) then ceval_step3 st c1 i' else ceval_step3 st c2 i' @@ -122,6 +129,7 @@ Fixpoint ceval_step3 (st : state) (c : com) (i : nat) else Some st end end. +Close Scope imp_scope. (** 我们可以引入一些辅助记法来隐藏对可选状态进行重复匹配的复杂工作, 从而提高此版本的可读性。 *) @@ -133,6 +141,7 @@ Notation "'LETOPT' x <== e1 'IN' e2" end) (right associativity, at level 60). +Open Scope imp_scope. Fixpoint ceval_step (st : state) (c : com) (i : nat) : option state := match i with @@ -142,11 +151,11 @@ Fixpoint ceval_step (st : state) (c : com) (i : nat) | SKIP => Some st | l ::= a1 => - Some (st & { l --> (aeval st a1)}) + Some (l !-> aeval st a1 ; st) | c1 ;; c2 => LETOPT st' <== ceval_step st c1 i' IN ceval_step st' c2 i' - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => if (beval st b) then ceval_step st c1 i' else ceval_step st c2 i' @@ -157,6 +166,7 @@ Fixpoint ceval_step (st : state) (c : com) (i : nat) else Some st end end. +Close Scope imp_scope. Definition test_ceval (st:state) (c:com) := match ceval_step st c 500 with @@ -165,17 +175,18 @@ Definition test_ceval (st:state) (c:com) := end. (* Compute - (test_ceval { --> 0 } + (test_ceval empty_st (X ::= 2;; - IFB (X <= 1) + TEST (X <= 1) THEN Y ::= 3 ELSE Z ::= 4 FI)). ====> Some (2, 0, 4) *) -(** **** 练习:2 星, recommended (pup_to_n) *) -(** 编写一个 Imp 程序对 [1] 到 [X] 求和(即 [1 + 2 + ... + X])并赋值给 [Y]。 +(** **** 练习:2 星, standard, recommended (pup_to_n) + + 编写一个 Imp 程序对 [1] 到 [X] 求和(即 [1 + 2 + ... + X])并赋值给 [Y]。 确保你的解答能满足之后的测试。 *) Definition pup_to_n : com @@ -184,18 +195,20 @@ Definition pup_to_n : com (* Example pup_to_n_1 : - test_ceval {X --> 5} pup_to_n + test_ceval (X !-> 5) pup_to_n = Some (0, 15, 0). Proof. reflexivity. Qed. -*) -(** [] *) -(** **** 练习:2 星, optional (peven) *) -(** 编写一个 [Imp] 程序:该程序在 [X] 为偶数时将 [Z] 置为 [0], + [] *) + +(** **** 练习:2 星, standard, optional (peven) + + 编写一个 [Imp] 程序:该程序在 [X] 为偶数时将 [Z] 置为 [0], 否则将 [Z] 置为 [1]。使用 [test_ceval] 测试你的程序。 *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * 关系求值 vs. 计步求值 *) @@ -205,7 +218,7 @@ Proof. reflexivity. Qed. Theorem ceval_step__ceval: forall c st st', (exists i, ceval_step st c i = Some st') -> - c / st \\ st'. + st =[ c ]=> st'. Proof. intros c st st' H. inversion H as [i E]. @@ -234,7 +247,7 @@ Proof. * (* Otherwise -- contradiction *) discriminate H1. - + (* IFB *) + + (* TEST *) destruct (beval st b) eqn:Heqr. * (* r = true *) apply E_IfTrue. rewrite Heqr. reflexivity. @@ -256,9 +269,9 @@ Proof. injection H1. intros H2. rewrite <- H2. apply E_WhileFalse. apply Heqr. Qed. +(** **** 练习:4 星, standard (ceval_step__ceval_inf) -(** **** 练习:4 星 (ceval_step__ceval_inf) *) -(** 按照通常的模版写出 [ceval_step__ceval] 的非形式化证明, + 按照通常的模版写出 [ceval_step__ceval] 的非形式化证明, (对归纳定义的值进行分类讨论的模版,除了没有归纳假设外, 应当看起来与归纳证明相同。)不要简单地翻译形式化证明的步骤, 请让你的证明能够将主要想法传达给读者。 *) @@ -297,7 +310,7 @@ induction i1 as [|i1']; intros i2 st st' c Hle Hceval. * (* st1'o = None *) discriminate Hceval. - + (* IFB *) + + (* TEST *) simpl in Hceval. simpl. destruct (beval st b); apply (IHi1' i2') in Hceval; assumption. @@ -313,12 +326,13 @@ induction i1 as [|i1']; intros i2 st st' c Hle Hceval. * (* i1'o = None *) simpl in Hceval. discriminate Hceval. Qed. -(** **** 练习:3 星, recommended (ceval__ceval_step) *) -(** 请完成以下证明。你会在某些地方用到 [ceval_step_more] 以及一些关于 +(** **** 练习:3 星, standard, recommended (ceval__ceval_step) + + 请完成以下证明。你会在某些地方用到 [ceval_step_more] 以及一些关于 [<=] 和 [plus] 的基本事实。 *) Theorem ceval__ceval_step: forall c st st', - c / st \\ st' -> + st =[ c ]=> st' -> exists i, ceval_step st c i = Some st'. Proof. intros c st st' Hce. @@ -327,7 +341,7 @@ Proof. (** [] *) Theorem ceval_and_ceval_step_coincide: forall c st st', - c / st \\ st' + st =[ c ]=> st' <-> exists i, ceval_step st c i = Some st'. Proof. intros c st st'. @@ -341,8 +355,8 @@ Qed. 我们可以给出一种取巧的方式来证明求值_'关系'_是确定性的。 *) Theorem ceval_deterministic' : forall c st st1 st2, - c / st \\ st1 -> - c / st \\ st2 -> + st =[ c ]=> st1 -> + st =[ c ]=> st2 -> st1 = st2. Proof. intros c st st1 st2 He1 He2. @@ -355,3 +369,4 @@ Proof. rewrite E1 in E2. inversion E2. reflexivity. omega. omega. Qed. +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/ImpCEvalFunTest.v b/lf-current/ImpCEvalFunTest.v index a265f01c..449d22d5 100644 --- a/lf-current/ImpCEvalFunTest.v +++ b/lf-current/ImpCEvalFunTest.v @@ -84,3 +84,5 @@ Print Assumptions ceval__ceval_step. idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:15:02 UTC 2019 *) diff --git a/lf-current/ImpParser.html b/lf-current/ImpParser.html index 147f08d4..beb55ef9 100644 --- a/lf-current/ImpParser.html +++ b/lf-current/ImpParser.html @@ -51,18 +51,18 @@再论求值的确定性
+再论求值的确定性
@@ -429,9 +439,9 @@ImpCEvalFunImp 的求值函数
-Theorem ceval_deterministic' : ∀ c st st1 st2,
- c / st \\ st1 →
- c / st \\ st2 →
+Theorem ceval_deterministic' : ∀c st st1 st2,
+ st =[ c ]⇒ st1 →
+ st =[ c ]⇒ st2 →
st1 = st2.
@@ -446,6 +456,9 @@+ +ImpCEvalFunImp 的求值函数rewrite E1 in E2. inversion E2. reflexivity.
omega. omega. Qed.
+(* Sat Jan 26 15:14:46 UTC 2019 *)
ImpParser用 Coq 实现词法分析
Set Warnings "-notation-overridden,-parsing".
-Require Import Coq.Strings.String.
-Require Import Coq.Strings.Ascii.
-Require Import Coq.Arith.Arith.
-Require Import Coq.Init.Nat.
-Require Import Coq.Arith.EqNat.
-Require Import Coq.Lists.List.
+From Coq Require Import Strings.String.
+From Coq Require Import Strings.Ascii.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Init.Nat.
+From Coq Require Import Arith.EqNat.
+From Coq Require Import Lists.List.
Import ListNotations.
From LF Require Import Maps Imp.
@@ -71,7 +71,7 @@ImpParser用 Coq 实现词法分析
@@ -150,11 +150,11 @@ImpParser用 Coq 实现词法分析
-Notation "'DO' ( x , y ) <== e1 ; e2"
+Notation "' p <- e1 ;; e2"
:= (match e1 with
- | SomeE (x,y) ⇒ e2
- | NoneE err ⇒ NoneE err
+ | SomeE p ⇒ e2
+ | NoneE err ⇒ NoneE err
end)
- (right associativity, at level 60).
-Notation "'DO' ( x , y ) <-- e1 ; e2 'OR' e3"
+ (right associativity, p pattern, at level 60, e1 at next level).
+Notation "'TRY' ' p <- e1 ;; e2 'OR' e3"
:= (match e1 with
- | SomeE (x,y) ⇒ e2
- | NoneE err ⇒ e3
+ | SomeE p ⇒ e2
+ | NoneE _ ⇒ e3
end)
- (right associativity, at level 60, e2 at next level).
+ (right associativity, p pattern,
+ at level 60, e1 at next level, e2 at next level).
@@ -205,7 +206,7 @@@@ -241,11 +242,11 @@ImpParser用 Coq 实现词法分析 | _, NoneE _ ⇒
SomeE ((rev acc), xs)
| S steps', SomeE (t, xs') ⇒
- many_helper p (t::acc) steps' xs'
+ many_helper p (t :: acc) steps' xs'
end.
ImpParser用 Coq 实现词法分析
Definition expect (t : token) : parser unit :=
- firstExpect t (fun xs ⇒ SomeE(tt, xs)).
+ firstExpect t (fun xs ⇒ SomeE (tt, xs)).
-@@ -429,79 +428,114 @@一个 Imp 的递归下降语法分析器
+一个 Imp 的递归下降语法分析器
@@ -299,14 +300,15 @@ImpParser用 Coq 实现词法分析 match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (i, rest) <-- parseIdentifier xs ;
+ TRY ' (i, rest) <- parseIdentifier xs ;;
SomeE (AId i, rest)
- OR DO (n, rest) <-- parseNumber xs ;
+ OR
+ TRY ' (n, rest) <- parseNumber xs ;;
SomeE (ANum n, rest)
- OR (DO (e, rest) <== firstExpect "("
- (parseSumExp steps') xs;
- DO (u, rest') <== expect ")" rest ;
- SomeE(e,rest'))
+ OR
+ ' (e, rest) <- firstExpect "(" (parseSumExp steps') xs ;;
+ ' (u, rest') <- expect ")" rest ;;
+ SomeE (e,rest')
end
with parseProductExp (steps:nat)
@@ -314,11 +316,9 @@ImpParser用 Coq 实现词法分析 match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (e, rest) <==
- parsePrimaryExp steps' xs ;
- DO (es, rest') <==
- many (firstExpect "*" (parsePrimaryExp steps'))
- steps' rest;
+ ' (e, rest) <- parsePrimaryExp steps' xs ;;
+ ' (es, rest') <- many (firstExpect "*" (parsePrimaryExp steps'))
+ steps' rest ;;
SomeE (fold_left AMult es e, rest')
end
@@ -326,22 +326,22 @@ImpParser用 Coq 实现词法分析 match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (e, rest) <==
- parseProductExp steps' xs ;
- DO (es, rest') <==
- many (fun xs ⇒
- DO (e,rest') <--
- firstExpect "+"
- (parseProductExp steps') xs;
- SomeE ( (true, e), rest')
- OR DO (e,rest') <==
- firstExpect "-"
- (parseProductExp steps') xs;
- SomeE ( (false, e), rest'))
- steps' rest;
+ ' (e, rest) <- parseProductExp steps' xs ;;
+ ' (es, rest') <-
+ many (fun xs ⇒
+ TRY ' (e,rest') <-
+ firstExpect "+"
+ (parseProductExp steps') xs ;;
+ SomeE ( (true, e), rest')
+ OR
+ ' (e, rest') <-
+ firstExpect "-"
+ (parseProductExp steps') xs ;;
+ SomeE ( (false, e), rest'))
+ steps' rest ;;
SomeE (fold_left (fun e0 term ⇒
match term with
- (true, e) ⇒ APlus e0 e
+ | (true, e) ⇒ APlus e0 e
| (false, e) ⇒ AMinus e0 e
end)
es e,
@@ -360,32 +360,33 @@ImpParser用 Coq 实现词法分析 match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (u,rest) <-- expect "true" xs;
+ TRY ' (u,rest) <- expect "true" xs ;;
SomeE (BTrue,rest)
- OR DO (u,rest) <-- expect "false" xs;
+ OR
+ TRY ' (u,rest) <- expect "false" xs ;;
SomeE (BFalse,rest)
- OR DO (e,rest) <--
- firstExpect "!"
- (parseAtomicExp steps')
- xs;
+ OR
+ TRY ' (e,rest) <- firstExpect "¬"
+ (parseAtomicExp steps')
+ xs ;;
SomeE (BNot e, rest)
- OR DO (e,rest) <--
- firstExpect "("
- (parseConjunctionExp steps') xs;
- (DO (u,rest') <== expect ")" rest;
- SomeE (e, rest'))
- OR DO (e, rest) <== parseProductExp steps' xs;
- (DO (e', rest') <--
- firstExpect "="
- (parseAExp steps') rest;
- SomeE (BEq e e', rest')
- OR DO (e', rest') <--
- firstExpect "≤"
- (parseAExp steps') rest;
- SomeE (BLe e e', rest')
- OR
- NoneE
- "Expected '=' or '≤' after arithmetic expression")
+ OR
+ TRY ' (e,rest) <- firstExpect "("
+ (parseConjunctionExp steps')
+ xs ;;
+ ' (u,rest') <- expect ")" rest ;;
+ SomeE (e, rest')
+ OR
+ ' (e, rest) <- parseProductExp steps' xs ;;
+ TRY ' (e', rest') <- firstExpect "="
+ (parseAExp steps') rest ;;
+ SomeE (BEq e e', rest')
+ OR
+ TRY ' (e', rest') <- firstExpect "≤"
+ (parseAExp steps') rest ;;
+ SomeE (BLe e e', rest')
+ OR
+ NoneE "Expected '=' or '≤' after arithmetic expression"
end
with parseConjunctionExp (steps:nat)
@@ -393,12 +394,10 @@ImpParser用 Coq 实现词法分析 match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (e, rest) <==
- parseAtomicExp steps' xs ;
- DO (es, rest') <==
- many (firstExpect "&&"
+ ' (e, rest) <- parseAtomicExp steps' xs ;;
+ ' (es, rest') <- many (firstExpect "&&"
(parseAtomicExp steps'))
- steps' rest;
+ steps' rest ;;
SomeE (fold_left BAnd es e, rest')
end.
Definition parseBExp := parseConjunctionExp.
@@ -412,10 +411,10 @@ImpParser用 Coq 实现词法分析 p 100 t.
(*
Eval compute in
- testParsing parseProductExp "x*y*(x*x)*x".
+ testParsing parseProductExp "x.y.(x.x).x".
Eval compute in
- testParsing parseConjunctionExp "not((x=x||x*x<=(x*x)*x)&&x=x".
+ testParsing parseConjunctionExp "~(x=x&&x*x<=(x*x)*x)&&x=x".
*)
ImpParser用 Coq 实现词法分析 match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (u, rest) <-- expect "SKIP" xs;
- SomeE (SKIP, rest)
- OR DO (e,rest) <--
- firstExpect "IFB" (parseBExp steps') xs;
- DO (c,rest') <==
- firstExpect "THEN"
- (parseSequencedCommand steps') rest;
- DO (c',rest'') <==
- firstExpect "ELSE"
- (parseSequencedCommand steps') rest';
- DO (u,rest''') <==
- expect "END" rest'';
- SomeE(IFB e THEN c ELSE c' FI, rest''')
- OR DO (e,rest) <--
- firstExpect "WHILE"
- (parseBExp steps') xs;
- DO (c,rest') <==
- firstExpect "DO"
- (parseSequencedCommand steps') rest;
- DO (u,rest'') <==
- expect "END" rest';
- SomeE(WHILE e DO c END, rest'')
- OR DO (i, rest) <==
- parseIdentifier xs;
- DO (e, rest') <==
- firstExpect ":=" (parseAExp steps') rest;
- SomeE(i ::= e, rest')
- end
+ TRY ' (u, rest) <- expect "SKIP" xs ;;
+ SomeE (SKIP%imp, rest)
+ OR
+ TRY ' (e,rest) <-
+ firstExpect "TEST"
+ (parseBExp steps') xs ;;
+ ' (c,rest') <-
+ firstExpect "THEN"
+ (parseSequencedCommand steps') rest ;;
+ ' (c',rest'') <-
+ firstExpect "ELSE"
+ (parseSequencedCommand steps') rest' ;;
+ ' (tt,rest''') <-
+ expect "END" rest'' ;;
+ SomeE(TEST e THEN c ELSE c' FI%imp, rest''')
+ OR
+ TRY ' (e,rest) <-
+ firstExpect "WHILE"
+ (parseBExp steps') xs ;;
+ ' (c,rest') <-
+ firstExpect "DO"
+ (parseSequencedCommand steps') rest ;;
+ ' (u,rest'') <-
+ expect "END" rest' ;;
+ SomeE(WHILE e DO c END%imp, rest'')
+ OR
+ TRY ' (i, rest) <- parseIdentifier xs ;;
+ ' (e, rest') <- firstExpect "::=" (parseAExp steps') rest ;;
+ SomeE ((i ::= e)%imp, rest')
+ OR
+ NoneE "Expecting a command"
+end
with parseSequencedCommand (steps:nat)
(xs : list token) :=
match steps with
| 0 ⇒ NoneE "Too many recursive calls"
| S steps' ⇒
- DO (c, rest) <==
- parseSimpleCommand steps' xs;
- DO (c', rest') <--
- firstExpect ";;"
- (parseSequencedCommand steps') rest;
- SomeE(c ;; c', rest')
- OR
- SomeE(c, rest)
+ ' (c, rest) <- parseSimpleCommand steps' xs ;;
+ TRY ' (c', rest') <-
+ firstExpect ";;"
+ (parseSequencedCommand steps') rest ;;
+ SomeE ((c ;; c')%imp, rest')
+ OR
+ SomeE (c, rest)
end.
Definition bignumber := 1000.
-Definition parse (str : string) : optionE (com * list token) :=
+Definition parse (str : string) : optionE com :=
let tokens := tokenize str in
- parseSequencedCommand bignumber tokens.
+ match parseSequencedCommand bignumber tokens with
+ | SomeE (c, []) ⇒ SomeE c
+ | SomeE (_, t::_) ⇒ NoneE ("Trailing tokens remaining: " ++ t)
+ | NoneE err ⇒ NoneE err
+ end.
Example eg1 : parse "
- IFB x = y + 1 + 2 - y * 6 + 3 THEN
- x := x * 1;;
- y := 0
+ TEST x = y + 1 + 2 - y * 6 + 3 THEN
+ x ::= x * 1;;
+ y ::= 0
ELSE
SKIP
END "
=
SomeE (
- IFB "x" = "y" + 1 + 2 - "y" * 6 + 3 THEN
- "x" ::= "x" * 1;;
- "y" ::= 0
- ELSE
- SKIP
- FI,
- []).
-Proof. reflexivity. Qed.
+ TEST "x" = "y" + 1 + 2 - "y" * 6 + 3 THEN
+ "x" ::= "x" * 1;;
+ "y" ::= 0
+ ELSE
+ SKIP
+ FI)%imp.
+Proof. cbv. reflexivity. Qed.
+Example eg2 : parse "
+ SKIP;;
+ z::=x*y*(x*x);;
+ WHILE x=x DO
+ TEST (z ≤ z*z) && ~(x = 2) THEN
+ x ::= z;;
+ y ::= z
+ ELSE
+ SKIP
+ END;;
+ SKIP
+ END;;
+ x::=z "
+=
+ SomeE (
+ SKIP;;
+ "z" ::= "x" * "y" * ("x" * "x");;
+ WHILE "x" = "x" DO
+ TEST ("z" ≤ "z" * "z") && ~("x" = 2) THEN
+ "x" ::= "z";;
+ "y" ::= "z"
+ ELSE
+ SKIP
+ FI;;
+ SKIP
+ END;;
+ "x" ::= "z")%imp.
+Proof. cbv. reflexivity. Qed.
+(* Sat Jan 26 15:14:46 UTC 2019 *)
IndPrinciples归纳原理
-@@ -71,7 +71,7 @@基础
+基础
@@ -57,9 +57,9 @@IndPrinciples归纳原理
Check nat_ind.
(* ===> nat_ind :
- forall P : nat -> Prop,
- P 0 ->
- (forall n : nat, P n -> P (S n)) ->
+ forall P : nat -> Prop,
+ P 0 ->
+ (forall n : nat, P n -> P (S n)) ->
forall n : nat, P n *)
IndPrinciples归纳原理
-Theorem mult_0_r' : ∀ n:nat,
+Theorem mult_0_r' : ∀n:nat,
n * 0 = 0.
Proof.
apply nat_ind.
@@ -100,12 +100,12 @@IndPrinciples归纳原理
nat_ind。-练习:2 星, optional (plus_one_r')
+练习:2 星, standard, optional (plus_one_r')
请不使用 induction 策略来完成这个证明。-Theorem plus_one_r' : ∀ n:nat,
+Theorem plus_one_r' : ∀n:nat,
n + 1 = S n.
Proof.
(* 请在此处解答 *) Admitted.
@@ -127,11 +127,11 @@IndPrinciples归纳原理
- t_ind : ∀ P : t → Prop,@@ -144,14 +144,14 @@
+ t_ind : ∀P : t → Prop,
... case for c1 ... →
... case for c2 ... → ...
... case for cn ... →
- ∀ n : t, P n + ∀n : t, P nIndPrinciples归纳原理
yes
| no.
Check yesno_ind.
-(* ===> yesno_ind : forall P : yesno -> Prop,
- P yes ->
- P no ->
+(* ===> yesno_ind : forall P : yesno -> Prop,
+ P yes ->
+ P no ->
forall y : yesno, P y *)
-@@ -178,15 +178,15 @@练习:1 星, optional (rgb)
+练习:1 星, standard, optional (rgb)
请写出对这个数据类型 Coq 将会生成的归纳原理。在纸上或注释中写下你的答案, 然后同 Coq 打印的结果比较。IndPrinciples归纳原理
Check natlist_ind.
(* ===> (除了一些变量被重命名了)
natlist_ind :
- forall P : natlist -> Prop,
- P nnil ->
+ forall P : natlist -> Prop,
+ P nnil ->
(forall (n : nat) (l : natlist),
- P l -> P (ncons n l)) ->
+ P l -> P (ncons n l)) ->
forall n : natlist, P n *)
@@ -231,7 +231,7 @@-IndPrinciples归纳原理
练习:1 星, optional (byntree_ind)
+练习:1 星, standard, optional (byntree_ind)
请写出对这个数据类型 Coq 将会生成的归纳原理。(与之前一样,在纸上或注释中写下你的答案, 然后同 Coq 打印的结果比较。)IndPrinciples归纳原理
-练习:1 星, optional (ex_set)
+练习:1 星, standard, optional (ex_set)
这是对一个归纳定义的集合的归纳原理。ExSet_ind :@@ -274,7 +274,7 @@
- ∀ P : ExSet → Prop,
- (∀ b : bool, P (con1 b)) →
- (∀ (n : nat) (e : ExSet), P e → P (con2 n e)) →
- ∀ e : ExSet, P e + ∀P : ExSet → Prop,
+ (∀b : bool, P (con1 b)) →
+ (∀(n : nat) (e : ExSet), P e → P (con2 n e)) →
+ ∀e : ExSet, P eIndPrinciples归纳原理
-多态
+多态
@@ -302,10 +302,10 @@IndPrinciples归纳原理
list_ind :
- ∀ (X : Type) (P : list X → Prop),
+ ∀(X : Type) (P : list X → Prop),
P [] →
- (∀ (x : X) (l : list X), P l → P (x :: l)) →
- ∀ l : list X, P l + (∀(x : X) (l : list X), P l → P (x :: l)) →
+ ∀l : list X, P lIndPrinciples归纳原理
X 时,返回特化在类型 list X 上的归纳原理。-练习:1 星, optional (tree)
+练习:1 星, standard, optional (tree)
请写出对这个数据类型 Coq 将会生成的归纳原理。同 Coq 打印的结果比较你的答案。@@ -328,45 +328,45 @@IndPrinciples归纳原理
-练习:1 星, optional (mytype)
+练习:1 星, standard, optional (mytype)
请找到对应于以下归纳原理的归纳定义:mytype_ind :☐
- ∀ (X : Type) (P : mytype X → Prop),
- (∀ x : X, P (constr1 X x)) →
- (∀ n : nat, P (constr2 X n)) →
- (∀ m : mytype X, P m →
- ∀ n : nat, P (constr3 X m n)) →
- ∀ m : mytype X, P m + ∀(X : Type) (P : mytype X → Prop),
+ (∀x : X, P (constr1 X x)) →
+ (∀n : nat, P (constr2 X n)) →
+ (∀m : mytype X, P m →
+ ∀n : nat, P (constr3 X m n)) →
+ ∀m : mytype X, P m-练习:1 星, optional (foo)
+练习:1 星, standard, optional (foo)
请找到对应于以下归纳原理的归纳定义:foo_ind :☐
- ∀ (X Y : Type) (P : foo X Y → Prop),
- (∀ x : X, P (bar X Y x)) →
- (∀ y : Y, P (baz X Y y)) →
- (∀ f1 : nat → foo X Y,
- (∀ n : nat, P (f1 n)) → P (quux X Y f1)) →
- ∀ f2 : foo X Y, P f2 + ∀(X Y : Type) (P : foo X Y → Prop),
+ (∀x : X, P (bar X Y x)) →
+ (∀y : Y, P (baz X Y y)) →
+ (∀f1 : nat → foo X Y,
+ (∀n : nat, P (f1 n)) → P (quux X Y f1)) →
+ ∀f2 : foo X Y, P f2-练习:1 星, optional (foo')
+练习:1 星, standard, optional (foo')
请考虑以下归纳定义:@@ -383,12 +383,12 @@@@ -399,7 +399,7 @@IndPrinciples归纳原理
foo'_ind :
- ∀ (X : Type) (P : foo' X → Prop),
- (∀ (l : list X) (f : foo' X),
+ ∀(X : Type) (P : foo' X → Prop),
+ (∀(l : list X) (f : foo' X),
_______________________ →
_______________________ ) →
___________________________________________ →
- ∀ f : foo' X, ________________________ + ∀f : foo' X, ________________________IndPrinciples归纳原理
- ∀ P : nat → Prop,@@ -426,8 +426,8 @@
+ ∀P : nat → Prop,
P 0 →
- (∀ n : nat, P n → P (S n)) →
- ∀ n : nat, P n + (∀n : nat, P n → P (S n)) →
+ ∀n : nat, P nIndPrinciples归纳原理
@@ -449,7 +449,7 @@IndPrinciples归纳原理
-Theorem mult_0_r'' : ∀ n:nat,
+Theorem mult_0_r'' : ∀n:nat,
P_m0r n.
Proof.
apply nat_ind.
@@ -463,16 +463,16 @@IndPrinciples归纳原理
这一步额外的命名步骤并不是我们在证明中通常会做的,但对一两个例子显式地 做这件事是由好处的,帮助我们清晰地看到哪个是归纳假设。 - 如果对 n 归纳来证明 ∀n, P_m0r n(使用 induction + 如果对 n 归纳来证明 ∀ n, P_m0r n(使用 induction 或 apply nat_ind),可以看到第一个子目标要求我们证明 P_m0r 0 - (“P 对零成立”),而第二个子目标要求我们证明 ∀n', P_m0r n' → P_m0r (S n') + (“P 对零成立”),而第二个子目标要求我们证明 ∀ n', P_m0r n' → P_m0r (S n') (也即,“P 对 S n' 成立如果其对 n' 成立”,或者说,“P 被 S 保持”)。 归纳假设是后一个蕴含式中的前提——假设 P 对 n' 成立,这是我们在证明 P 对 S n' 的过程中允许使用的。-diff --git a/lf-current/IndPrinciples.v b/lf-current/IndPrinciples.v index de0c5fed..df6f49b5 100644 --- a/lf-current/IndPrinciples.v +++ b/lf-current/IndPrinciples.v @@ -44,8 +44,9 @@ Proof. 相比于直接使用 [nat_ind] 这样的归纳原理,在实践中使用 [induction] 更加方便。 但重要的是认识到除了这一点变量名的管理工作,我们在做的其实就是应用 [nat_ind]。 *) -(** **** 练习:2 星, optional (plus_one_r') *) -(** 请不使用 [induction] 策略来完成这个证明。 *) +(** **** 练习:2 星, standard, optional (plus_one_r') + + 请不使用 [induction] 策略来完成这个证明。 *) Theorem plus_one_r' : forall n:nat, n + 1 = S n. @@ -79,8 +80,9 @@ Check yesno_ind. P no -> forall y : yesno, P y *) -(** **** 练习:1 星, optional (rgb) *) -(** 请写出对这个数据类型 Coq 将会生成的归纳原理。在纸上或注释中写下你的答案, +(** **** 练习:1 星, standard, optional (rgb) + + 请写出对这个数据类型 Coq 将会生成的归纳原理。在纸上或注释中写下你的答案, 然后同 Coq 打印的结果比较。 *) Inductive rgb : Type := @@ -105,15 +107,17 @@ Check natlist_ind. P l -> P (ncons n l)) -> forall n : natlist, P n *) -(** **** 练习:1 星, optional (natlist1) *) -(** 假设我们写下的定义和上面的有一些区别: *) +(** **** 练习:1 星, standard, optional (natlist1) + + 假设我们写下的定义和上面的有一些区别: *) Inductive natlist1 : Type := | nnil1 | nsnoc1 (l : natlist1) (n : nat). -(** 现在归纳原理会是什么呢? *) -(** [] *) +(** 现在归纳原理会是什么呢? + + [] *) (** 对于这些例子,我们可以总结出一般的规则: @@ -127,8 +131,9 @@ Inductive natlist1 : Type := 成立”。 *) -(** **** 练习:1 星, optional (byntree_ind) *) -(** 请写出对这个数据类型 Coq 将会生成的归纳原理。(与之前一样,在纸上或注释中写下你的答案, +(** **** 练习:1 星, standard, optional (byntree_ind) + + 请写出对这个数据类型 Coq 将会生成的归纳原理。(与之前一样,在纸上或注释中写下你的答案, 然后同 Coq 打印的结果比较。) *) Inductive byntree : Type := @@ -137,8 +142,9 @@ Inductive byntree : Type := | nbranch (yn : yesno) (t1 t2 : byntree). (** [] *) -(** **** 练习:1 星, optional (ex_set) *) -(** 这是对一个归纳定义的集合的归纳原理。 +(** **** 练习:1 星, standard, optional (ex_set) + + 这是对一个归纳定义的集合的归纳原理。 ExSet_ind : forall P : ExSet -> Prop, @@ -178,8 +184,9 @@ Inductive ExSet : Type := 请注意_'全部的'_归纳原理都被 [X] 所参数化。也即,[list_ind] 可认为是一个 多态函数,当被应用类型 [X] 时,返回特化在类型 [list X] 上的归纳原理。 *) -(** **** 练习:1 星, optional (tree) *) -(** 请写出对这个数据类型 Coq 将会生成的归纳原理。同 Coq 打印的结果比较你的答案。*) +(** **** 练习:1 星, standard, optional (tree) + + 请写出对这个数据类型 Coq 将会生成的归纳原理。同 Coq 打印的结果比较你的答案。*) Inductive tree (X:Type) : Type := | leaf (x : X) @@ -187,8 +194,9 @@ Inductive tree (X:Type) : Type := Check tree_ind. (** [] *) -(** **** 练习:1 星, optional (mytype) *) -(** 请找到对应于以下归纳原理的归纳定义: +(** **** 练习:1 星, standard, optional (mytype) + + 请找到对应于以下归纳原理的归纳定义: mytype_ind : forall (X : Type) (P : mytype X -> Prop), @@ -200,8 +208,9 @@ Check tree_ind. *) (** [] *) -(** **** 练习:1 星, optional (foo) *) -(** 请找到对应于以下归纳原理的归纳定义: +(** **** 练习:1 星, standard, optional (foo) + + 请找到对应于以下归纳原理的归纳定义: foo_ind : forall (X Y : Type) (P : foo X Y -> Prop), @@ -213,8 +222,9 @@ Check tree_ind. *) (** [] *) -(** **** 练习:1 星, optional (foo') *) -(** 请考虑以下归纳定义: *) +(** **** 练习:1 星, standard, optional (foo') + + 请考虑以下归纳定义: *) Inductive foo' (X:Type) : Type := | C1 (l : list X) (f : foo' X) @@ -343,47 +353,49 @@ Proof. - (* m = S m' *) simpl. rewrite <- IHm'. rewrite <- plus_n_Sm. reflexivity. Qed. -(** **** 练习:1 星, optional (plus_explicit_prop) *) -(** 以上面 [mult_0_r''] 的方式来重写 [plus_assoc'],[plus_comm'] 和它们的证明—— +(** **** 练习:1 星, standard, optional (plus_explicit_prop) + + 以上面 [mult_0_r''] 的方式来重写 [plus_assoc'],[plus_comm'] 和它们的证明—— 也即,对于每个定理,给出一个明确的命题的 [Definition],陈述定理并用归纳法证明这个 定义的命题。 *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * [Prop] 中的归纳原理 *) -(** 之前,我们仔细学习了 Coq 为归纳定义的_'集合'_生成的归纳原理。 像 [ev] +(** 之前,我们仔细学习了 Coq 为归纳定义的_'集合'_生成的归纳原理。 像 [even] 这样的归纳定义_'命题'_的归纳原理会复杂一点点。就全部归纳原理来说,我们想要 - 通过使用 [ev] 的归纳原理并归纳地考虑 [ev] 中所有可能的形式来证明一些东西。 + 通过使用 [even] 的归纳原理并归纳地考虑 [even] 中所有可能的形式来证明一些东西。 然而,直观地讲,我们想要证明的东西并不是关于_'证据'_的陈述,而是关于 _'数字'_的陈述:因此,我们想要让归纳原理允许通过对证据进行归纳来 证明关于数字的性质。 - 比如,根据我们前面所讲,你可能会期待这样归纳定义的 [ev]…… + 比如,根据我们前面所讲,你可能会期待这样归纳定义的 [even]…… - Inductive ev : nat -> Prop := - | ev_0 : ev 0 - | ev_SS : forall n : nat, ev n -> ev (S (S n)). + Inductive even : nat -> Prop := + | ev_0 : even 0 + | ev_SS : forall n : nat, even n -> even (S (S n)). ……并给我们下面这样的归纳原理…… - ev_ind_max : forall P : (forall n : nat, ev n -> Prop), + ev_ind_max : forall P : (forall n : nat, even n -> Prop), P O ev_0 -> - (forall (m : nat) (E : ev m), + (forall (m : nat) (E : even m), P m E -> P (S (S m)) (ev_SS m E)) -> - forall (n : nat) (E : ev n), + forall (n : nat) (E : even n), P n E ……因为: - - 因为 [ev] 被数字 [n] 所索引(任何 [ev] 的对象 [E] 都是某个数字 [n] + - 因为 [even] 被数字 [n] 所索引(任何 [even] 的对象 [E] 都是某个数字 [n] 是偶数的证据),命题 [P] 同时被 [n] 和 [E] 所参数化——也即,被用于证明断言的 归纳原理涉同时及到数字和这个数字是偶数的证据。 - - 由于有两种方法来给出偶数性质的证据(因为 [ev] 有两个构造子),应用归纳原理生成 + - 由于有两种方法来给出偶数性质的证据(因为 [even] 有两个构造子),应用归纳原理生成 了两个子目标: - 我们必须证明 [P] 对 [0] 和 [ev_0] 成立。 @@ -404,15 +416,15 @@ Proof. forall n : nat, even n -> P n - 出于这样的原因,Coq 实际上为 [ev] 生成了简化过的归纳原理: *) + 出于这样的原因,Coq 实际上为 [even] 生成了简化过的归纳原理: *) -Check ev_ind. +Check even_ind. (* ===> ev_ind : forall P : nat -> Prop, P 0 -> - (forall n : nat, ev n -> P n -> P (S (S n))) -> + (forall n : nat, even n -> P n -> P (S (S n))) -> forall n : nat, - ev n -> P n *) + even n -> P n *) (** 请特别注意,Coq 丢弃了命题 [P] 参数中的证据项 [E]。 *) @@ -426,17 +438,17 @@ Check ev_ind. - 对任意 [n],如果 [n] 是偶数且 [P] 对 [n] 成立,那么 [P] 对 [S (S n)] 成立。 *) (** 正如期待的那样,我们可以不使用 [induction] 而直接应用 [ev_ind]。 - 比如,我们可以使用它来证明 [ev'](那个在 [IndProp] 一章的练习中有点笨拙的偶数性质的定义) - 等价于更简洁的归纳定义 [ev]: *) -Theorem ev_ev' : forall n, ev n -> ev' n. + 比如,我们可以使用它来证明 [even'](那个在 [IndProp] 一章的练习中有点笨拙的偶数性质的定义) + 等价于更简洁的归纳定义 [even]: *) +Theorem ev_ev' : forall n, even n -> even' n. Proof. - apply ev_ind. + apply even_ind. - (* ev_0 *) - apply ev'_0. + apply even'_0. - (* ev_SS *) intros m Hm IH. - apply (ev'_sum 2 m). - + apply ev'_2. + apply (even'_sum 2 m). + + apply even'_2. + apply IH. Qed. @@ -580,3 +592,4 @@ Check le_ind. 因此,根据 [le_S],[n <= S o']。 [] *) +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/IndPrinciplesTest.v b/lf-current/IndPrinciplesTest.v index 7cb19cb2..ac8abd2d 100644 --- a/lf-current/IndPrinciplesTest.v +++ b/lf-current/IndPrinciplesTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:14:57 UTC 2019 *) diff --git a/lf-current/IndProp.html b/lf-current/IndProp.html index 6fc20778..40bf6110 100644 --- a/lf-current/IndProp.html +++ b/lf-current/IndProp.html @@ -40,17 +40,27 @@深入 induction 策略
+深入 induction 策略
@@ -512,7 +512,7 @@IndPrinciples归纳原理
-Theorem plus_assoc' : ∀ n m p : nat,+
+Theorem plus_assoc' : ∀n m p : nat,
n + (m + p) = (n + m) + p.
Proof.
(* ……我们首先引入全部3个变量到上下文中,或者说是
@@ -536,7 +536,7 @@IndPrinciples归纳原理
-Theorem plus_comm' : ∀ n m : nat,
+Theorem plus_comm' : ∀n m : nat,
n + m = m + n.
Proof.
induction n as [| n'].
@@ -547,7 +547,7 @@IndPrinciples归纳原理
请注意 induction 留下 m 仍然绑定在目标中——也即,我们在归纳证明的陈述 - 仍然是以 ∀m 开始的。 + 仍然是以 ∀ m 开始的。@@ -556,7 +556,7 @@IndPrinciples归纳原理
-Theorem plus_comm'' : ∀ n m : nat,
+Theorem plus_comm'' : ∀n m : nat,
n + m = m + n.
Proof.
(* 这次让我们对 m 而非 n 进行归纳…… *)
@@ -567,7 +567,7 @@IndPrinciples归纳原理
-练习:1 星, optional (plus_explicit_prop)
+练习:1 星, standard, optional (plus_explicit_prop)
以上面 mult_0_r'' 的方式来重写 plus_assoc',plus_comm' 和它们的证明—— 也即,对于每个定理,给出一个明确的命题的 Definition,陈述定理并用归纳法证明这个 定义的命题。 @@ -580,27 +580,27 @@IndPrinciples归纳原理
☐-Prop 中的归纳原理
+Prop 中的归纳原理
- 之前,我们仔细学习了 Coq 为归纳定义的集合生成的归纳原理。 像 ev + 之前,我们仔细学习了 Coq 为归纳定义的集合生成的归纳原理。 像 even 这样的归纳定义命题的归纳原理会复杂一点点。就全部归纳原理来说,我们想要 - 通过使用 ev 的归纳原理并归纳地考虑 ev 中所有可能的形式来证明一些东西。 + 通过使用 even 的归纳原理并归纳地考虑 even 中所有可能的形式来证明一些东西。 然而,直观地讲,我们想要证明的东西并不是关于证据的陈述,而是关于 数字的陈述:因此,我们想要让归纳原理允许通过对证据进行归纳来 证明关于数字的性质。- 比如,根据我们前面所讲,你可能会期待这样归纳定义的 ev…… + 比如,根据我们前面所讲,你可能会期待这样归纳定义的 even……- Inductive ev : nat → Prop :=@@ -609,12 +609,12 @@
- | ev_0 : ev 0
- | ev_SS : ∀ n : nat, ev n → ev (S (S n)). + Inductive even : nat → Prop :=
+ | ev_0 : even 0
+ | ev_SS : ∀n : nat, even n → even (S (S n)).IndPrinciples归纳原理
- ev_ind_max : ∀ P : (∀ n : nat, ev n → Prop),
+ ev_ind_max : ∀P : (∀n : nat, even n → Prop),
P O ev_0 →
- (∀ (m : nat) (E : ev m),
+ (∀(m : nat) (E : even m),
P m E →
P (S (S m)) (ev_SS m E)) →
- ∀ (n : nat) (E : ev n),
+ ∀(n : nat) (E : even n),
P n E@@ -624,7 +624,7 @@IndPrinciples归纳原理
-
- 因为 ev 被数字 n 所索引(任何 ev 的对象 E 都是某个数字 n +
- 因为 even 被数字 n 所索引(任何 even 的对象 E 都是某个数字 n 是偶数的证据),命题 P 同时被 n 和 E 所参数化——也即,被用于证明断言的 归纳原理涉同时及到数字和这个数字是偶数的证据。 @@ -632,7 +632,7 @@
IndPrinciples归纳原理
-- 由于有两种方法来给出偶数性质的证据(因为 ev 有两个构造子),应用归纳原理生成 +
- 由于有两种方法来给出偶数性质的证据(因为 even 有两个构造子),应用归纳原理生成 了两个子目标:
@@ -670,24 +670,24 @@IndPrinciples归纳原理
- ∀ P : nat → Prop,- 出于这样的原因,Coq 实际上为 ev 生成了简化过的归纳原理: + 出于这样的原因,Coq 实际上为 even 生成了简化过的归纳原理:
+ ∀P : nat → Prop,
... →
- ∀ n : nat,
+ ∀n : nat,
even n → P n-Check ev_ind.
+Check even_ind.
(* ===> ev_ind
- : forall P : nat -> Prop,
- P 0 ->
- (forall n : nat, ev n -> P n -> P (S (S n))) ->
+ : forall P : nat -> Prop,
+ P 0 ->
+ (forall n : nat, even n -> P n -> P (S (S n))) ->
forall n : nat,
- ev n -> P n *)
+ even n -> P n *)
@@ -721,19 +721,19 @@正如期待的那样,我们可以不使用 induction 而直接应用 ev_ind。 - 比如,我们可以使用它来证明 ev'(那个在 IndProp 一章的练习中有点笨拙的偶数性质的定义) - 等价于更简洁的归纳定义 ev: + 比如,我们可以使用它来证明 even'(那个在 IndProp 一章的练习中有点笨拙的偶数性质的定义) + 等价于更简洁的归纳定义 even:IndPrinciples归纳原理
-Theorem ev_ev' : ∀ n, ev n → ev' n.@@ -747,9 +747,9 @@
+Theorem ev_ev' : ∀n, even n → even' n.
Proof.
- apply ev_ind.
+ apply even_ind.
- (* ev_0 *)
- apply ev'_0.
+ apply even'_0.
- (* ev_SS *)
intros m Hm IH.
- apply (ev'_sum 2 m).
- + apply ev'_2.
+ apply (even'_sum 2 m).
+ + apply even'_2.
+ apply IH.
Qed.
IndPrinciples归纳原理
-(* Inductive le : nat -> nat -> Prop :=
+(* Inductive le : nat -> nat -> Prop :=
| le_n : forall n, le n n
- | le_S : forall n m, (le n m) -> (le n (S m)). *)
+ | le_S : forall n m, (le n m) -> (le n (S m)). *)
@@ -770,14 +770,14 @@IndPrinciples归纳原理
Check le_ind.
-(* ===> forall (n : nat) (P : nat -> Prop),
- P n ->
- (forall m : nat, n <= m -> P m -> P (S m)) ->
- forall n0 : nat, n <= n0 -> P n0 *)
+(* ===> forall (n : nat) (P : nat -> Prop),
+ P n ->
+ (forall m : nat, n <= m -> P m -> P (S m)) ->
+ forall n0 : nat, n <= n0 -> P n0 *)
--形式化 vs. 非形式化的归纳证明
+形式化 vs. 非形式化的归纳证明
@@ -826,7 +826,7 @@IndPrinciples归纳原理
证据(也即,Prop 中归纳定义的东西)。-对归纳定义的集合进行归纳
+对归纳定义的集合进行归纳
@@ -929,7 +929,7 @@IndPrinciples归纳原理
对归纳定义的命题进行归纳
+对归纳定义的命题进行归纳
@@ -1012,6 +1012,10 @@IndPrinciples归纳原理
++ +(* Sat Jan 26 15:14:46 UTC 2019 *)
IndProp归纳定义的命题<
-归纳定义的命题
+归纳定义的命题
- 在 Logic 一章中,我们学习了多种方式来书写命题,包括合取、析取和量词。 - 在本章中,我们引入新的方式:归纳定义的命题(Inductive Definitions)。 + 在 Logic 一章中,我们学习了多种方式来书写命题,包括合取、析取和存在量词。 + 在本章中,我们引入另一种新的方式:归纳定义(Inductive Definitions)。- 请回想一下我们已经学过的两种方法来表达 n 是偶数: - (1) evenb n = true,以及 (2) ∃k, n = double k 。 - 然而另一种可能是通过如下规则来建立 n 的偶数性质: + 在前面的章节中,我们已经见过两种表述 n 为偶数的方式了: + ++ + (1) evenb n = true,以及 + ++ + (2) ∃ k, n = double k。 + ++ + 然而还有一种方式是通过如下规则来建立 n 的偶数性质:@@ -58,20 +68,20 @@IndProp归纳定义的命题<
规则 ev_0: 0 是偶数。 -规则 ev_SS: 如果 n 是偶数, 那么 S (S n) 是偶数。 + 规则 ev_SS: 如果 n 是偶数, 那么 S (S n) 也是偶数。 - 为了理解这样的偶数性质定义如何工作,我们可想象如何证明 4 是偶数。 + 为了理解这个新的偶数性质定义如何工作,我们可想象如何证明 4 是偶数。 根据规则 ev_SS,需要证明 2 是偶数。这时,只要证明 0 是偶数, 我们可继续通过规则 ev_SS 确保它成立。而使用规则 ev_0 可直接证明 0 是偶数。接下来的课程中,我们会看到很多类似方式定义的命题。 在非形式化的讨论中,使用轻量化的记法有助于阅读和书写。 -'推断规则(Inference Rules)是其中的一种: + 推断规则(Inference Rules)是其中的一种:@@ -84,12 +94,12 @@
IndProp归纳定义的命题<
- ev 0 +even 0 @@ -108,7 +118,7 @@
- @@ -97,7 +107,7 @@ev n +even n (ev_SS) IndProp归纳定义的命题<
- ev (S (S n)) +even (S (S n)) IndProp归纳定义的命题< 若将前文所述的规则重新排版成推断规则,我们可以这样阅读它,如果线上方的 前提(premises)成立,那么线下方的结论(conclusion)成立。 - 比如,规则 ev_SS 读做如果 n 满足 ev,那么 S (S n) 也满足。 + 比如,规则 ev_SS 读做如果 n 满足 even,那么 S (S n) 也满足。 如果一条规则在线上方没有前提,则结论直接成立。
@@ -120,12 +130,12 @@IndProp归纳定义的命题<
- ------ (ev_0)@@ -135,25 +145,26 @@
- ev 0
- ------ (ev_SS)
- ev 2
- ------ (ev_SS)
- ev 4 + -------- (ev_0)
+ even 0
+ -------- (ev_SS)
+ even 2
+ -------- (ev_SS)
+ even 4IndProp归纳定义的命题<
- 为什么我们把这样的证明称之为“树”(而非其他,比如“栈”)? - 因为一般来说推断规则可以有多个前提。我们会在后面看到一些例子。 + (为什么我们把这样的证明称之为“树”(而非其他,比如“栈”)? + 因为一般来说推断规则可以有多个前提。我们很快就会看到一些例子。+偶数性的归纳定义
基于上述,可将偶数性质的定义翻译为在 Coq 中使用 Inductive 声明的定义, 声明中每一个构造子对应一个推断规则:-Inductive ev : nat → Prop :=
-| ev_0 : ev 0
-| ev_SS (n : nat) (H : ev n) : ev (S (S n)).
+Inductive even : nat → Prop :=
+| ev_0 : even 0
+| ev_SS (n : nat) (H : even n) : even (S (S n)).
这个定义同之前其他 Inductive 的使用有一个重要的区别: - 它的结果并不是一个 Type ,而是一个将 nat 映射到 Prop 的函数——即关于数的性质。 - 注意我们曾见过结果也为函数的归纳定义,比如 list,其类型是 Type → Type 。 - 值得注意的是,由于 ev 中出现在冒号右侧的 nat 参数是 未命名 的, + 我们所定义的并不是一个 Type,而是一个将 nat 映射到 Prop 的函数——即关于数的性质。 + 我们曾见过结果也是函数的归纳定义,比如 list,其类型是 Type → Type 。 + 真正要关注的是,由于 even 中出现在冒号右侧的 nat 参数是 未命名 的, 这允许在不同的构造子类型中使用不同的值:例如 ev_0 类型中的 0 以及 ev_SS 类型中的 S (S n)。 @@ -161,33 +172,54 @@IndProp归纳定义的命题< 相反,list 的定义以全局方式命名了冒号左侧的参数 X, 强迫 nil 和 cons 的结果为同一个类型(list X)。 - 如果在定义 ev 时我们将 nat 置于冒号左侧,会得到如下错误: + 如果在定义 even 时我们将 nat 置于冒号左侧,会得到如下错误:
Fail Inductive wrong_ev (n : nat) : Prop :=
| wrong_ev_0 : wrong_ev 0
-| wrong_ev_SS : ∀ n, wrong_ev n → wrong_ev (S (S n)).
-(* ===> Error: A parameter of an inductive type n is not
- allowed to be used as a bound variable in the type
- of its constructor. *)
+| wrong_ev_SS : wrong_ev n → wrong_ev (S (S n)).
+(* ===> Error: Last occurrence of "wrong_ev" must have "n"
+ as 1st argument in "wrong_ev 0". *)
-(“parameter” 是 Coq 中的一个术语来表示 Inductive 定义中冒号左侧的参数; - “index” 则指冒号右侧的参数。) +在 Inductive 定义中,类型构造子的冒号左侧的参数叫做形参(Parameter), + 而右侧的叫做索引(Index)。 + ++ + 例如,在 Inductive list (X : Type) := ... 中,X 是一个形参;而在 + Inductive even : nat → Prop := ... 中,未命名的 nat 参数是一个索引。 ++ + 在 Coq 中,我们可以认为 even 定义了一个性质 ev : nat → Prop,其包括原语定理 + ev_0 : even 0 和 ev_SS : ∀ n, even n → even (S (S n))。 ++ + 该定义也可写作如下形式... + ++ ++ Inductive even : nat → Prop :=+
+ | ev_0 : even 0
+ | ev_SS : ∀n, even n → even (S (S n)). ++ +- 在 Coq 中,我们可以认为 ev 定义了一个性质 ev : nat → Prop,其包括公理(primitive theorems) - ev_0 : ev 0 和 ev_SS : ∀n, ev n → ev (S (S n))。 + ... 以便让 ev_SS 的类型更加直白。这些 “定理构造子” 等同于已经证明过的定理。 - 具体来说,我们可以使用 Coq 中的 apply 策略和规则名称来证明某个数的 ev 性质…… + 具体来说,我们可以使用 Coq 中的 apply 策略和规则名称来证明某个数的 even 性质……-Theorem ev_4 : ev 4.@@ -196,16 +228,16 @@
+Theorem ev_4 : even 4.
Proof. apply ev_SS. apply ev_SS. apply ev_0. Qed.
IndProp归纳定义的命题<
-Theorem ev_4' : ev 4.
+Theorem ev_4' : even 4.
Proof. apply (ev_SS 2 (ev_SS 0 ev_0)). Qed.
-我们同样可以对前提中使用到 ev 的定理进行证明。 +我们同样可以对前提中使用到 even 的定理进行证明。-Theorem ev_plus4 : ∀ n, ev n → ev (4 + n).
+Theorem ev_plus4 : ∀n, even n → even (4 + n).
Proof.
intros n. simpl. intros Hn.
apply ev_SS. apply ev_SS. apply Hn.
@@ -216,12 +248,12 @@IndProp归纳定义的命题< 更一般地,我们可以证明以任意数乘 2 是偶数:
-练习:1 星 (ev_double)
+练习:1 星, standard (ev_double)
-Theorem ev_double : ∀ n,@@ -229,7 +261,7 @@
- ev (double n).
+Theorem ev_double : ∀n,
+ even (double n).
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题< ☐
-在证明中使用证据
+在证明中使用证据
@@ -237,12 +269,12 @@IndProp归纳定义的命题<
- 对 ev 而言,使用 Inductive 声明来引入 ev 不仅仅表示在 Coq + 对 even 而言,使用 Inductive 声明来引入 even 不仅仅表示在 Coq 中 ev_0 和 ev_SS 这样的构造子是合法的方式来构造偶数证明的证据, 他们也是仅有的方式。- 换句话说,如果某人展示了对于 ev n 的证据 E,那么我们知道 E + 换句话说,如果某人展示了对于 even n 的证据 E,那么我们知道 E 必是二者其一:@@ -252,39 +284,42 @@IndProp归纳定义的命题<
E 是 ev_SS n' E'(且 n 为 S (S n'), E' 为 - ev n' 的证据). + even n' 的证据). - 这样的形式暗示着,我们可以像分析归纳定义的数据结构一样分析形如 ev n + 这样的形式暗示着,我们可以像分析归纳定义的数据结构一样分析形如 even n 的假设;特别地,对于这类证据使用归纳(induction)和分类讨论(case analysis)来进行论证也是可行的。让我们通过一些例子来学习实践中如何使用他们。-对证据进行反演
+对证据进行反演
- Suppose we are proving some fact involving a number n, and we - are given ev n as a hypothesis. We already know how to perform - case analysis on n using destruct or induction, generating - separate subgoals for the case where n = O and the case where n - = S n' for some n'. But for some proofs we may instead want to - analyze the evidence that ev n _directly_. As a tool, we can - prove our characterization of evidence for ev n, using destruct. + Suppose we are proving some fact involving a number n, and + we are given even n as a hypothesis. We already know how to + perform case analysis on n using destruct or induction, + generating separate subgoals for the case where n = O and the + case where n = S n' for some n'. But for some proofs we may + instead want to analyze the evidence that even n _directly_. As + a tool, we can prove our characterization of evidence for + even n, using destruct.Theorem ev_inversion :@@ -293,13 +328,14 @@
- ∀ (n : nat), ev n →
- (n = 0) ∨ (∃ m, n = S (S m) ∧ ev m).
+ ∀(n : nat), even n →
+ (n = 0) ∨ (∃n', n = S (S n') ∧ even n').
Proof.
- intros n Hev.
- destruct Hev as [ | m Hm].
- - left. reflexivity.
- - right. ∃ m. split. reflexivity. apply Hm.
+ intros n E.
+ destruct E as [ | n' E'].
+ - (* E = ev_0 : even 0 *)
+ left. reflexivity.
+ - (* E = ev_SS n' E' : even (S (S n')) *)
+ right. ∃n'. split. reflexivity. apply E'.
Qed.
IndProp归纳定义的命题<
-Theorem ev_minus2 : ∀ n,
- ev n → ev (pred (pred n)).
+Theorem ev_minus2 : ∀n,
+ even n → even (pred (pred n)).
Proof.
intros n E.
destruct E as [| n' E'].
- (* E = ev_0 *) simpl. apply ev_0.
- - (* E = ev_SS n' E' *) simpl. apply E'. Qed.
+ - (* E = ev_SS n' E' *) simpl. apply E'.
+Qed.
@@ -307,8 +343,8 @@IndProp归纳定义的命题<
-Theorem evSS_ev : ∀ n,
- ev (S (S n)) → ev n.
+Theorem evSS_ev : ∀n,
+ even (S (S n)) → even n.
@@ -333,15 +369,15 @@IndProp归纳定义的命题< 然而,这对于 evSS_ev 并没有帮助,因为被替换掉的 S (S n) 并没有在其他地方被使用。
- We can patch this proof by replacing the goal ev n, which - does not mention the replaced term S (S n), by the equivalent - goal ev (pred (pred (S (S n)))), which does mention this - term, after which destruct can make progress. But it is + We could patch this proof by replacing the goal even n, + which does not mention the replaced term S (S n), by the + equivalent goal even (pred (pred (S (S n)))), which does mention + this term, after which destruct can make progress. But it is more straightforward to use our inversion lemma.-Theorem evSS_ev : ∀ n, ev (S (S n)) → ev n.
+Theorem evSS_ev : ∀n, even (S (S n)) → even n.
Proof. intros n H. apply ev_inversion in H. destruct H.
- discriminate H.
- destruct H as [n' [Hnm Hev]]. injection Hnm.
@@ -350,20 +386,20 @@IndProp归纳定义的命题<
-Coq provides the inversion tactic, which does the work - of our inversion lemma and more besides. +Coq provides a tactic called inversion, which does the work of + our inversion lemma and more besides.The inversion tactic can detect (1) that the first case (n = 0) does not apply and (2) that the n' that appears in the - ev_SS case must be the same as n. It has an "as" - variant similar to destruct, allowing us to assign names - rather than have Coq choose them. + ev_SS case must be the same as n. It has an "as" variant + similar to destruct, allowing us to assign names rather than + have Coq choose them.-Theorem evSS_ev' : ∀ n,
- ev (S (S n)) → ev n.
+Theorem evSS_ev' : ∀n,
+ even (S (S n)) → even n.
Proof.
intros n E.
inversion E as [| n' E'].
@@ -379,25 +415,25 @@IndProp归纳定义的命题< inversion lemma. For example:
-Theorem one_not_even : ¬ ev 1.
+Theorem one_not_even : ¬even 1.
Proof.
intros H. apply ev_inversion in H.
destruct H as [ | [m [Hm _]]].
- discriminate H.
- discriminate Hm.
Qed.
-Theorem one_not_even' : ¬ ev 1.
+Theorem one_not_even' : ¬even 1.
intros H. inversion H. Qed.
-练习:1 星 (inversion_practice)
+练习:1 星, standard (inversion_practice)
利用 inversion 策略证明以下结论。如想进一步练习,请使用反演定理证明之。-Theorem SSSSev__even : ∀ n,@@ -406,13 +442,13 @@
- ev (S (S (S (S n)))) → ev n.
+Theorem SSSSev__even : ∀n,
+ even (S (S (S (S n)))) → even n.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
Theorem even5_nonsense :@@ -421,22 +457,22 @@
- ev 5 → 2 + 2 = 9.
+ even 5 → 2 + 2 = 9.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
- The inversion tactic is complex. When applied to equalities, as a - special case, it does the work of both discriminate and - injection. In addition, it carries out the intros and - rewrites that are typically necessary in the case of - injection. It can also be applied, more generally, - to analyzing evidence for inductively defined propositions. - As examples, we'll use it to reprove some theorems from Tactics.v. + The inversion tactic does quite a bit of work. When + applied to equalities, as a special case, it does the work of both + discriminate and injection. In addition, it carries out the + intros and rewrites that are typically necessary in the case + of injection. It can also be applied, more generally, to analyze + evidence for inductively defined propositions. As examples, we'll + use it to reprove some theorems from Tactics.v.-Theorem inversion_ex1 : ∀ (n m o : nat),
+Theorem inversion_ex1 : ∀(n m o : nat),
[n; m] = [o; o] →
[n] = [m].
Proof.
intros n m o H. inversion H. reflexivity. Qed.
-Theorem inversion_ex2 : ∀ (n : nat),
+Theorem inversion_ex2 : ∀(n : nat),
S n = O →
2 + 2 = 5.
Proof.
@@ -444,10 +480,10 @@IndProp归纳定义的命题<
-inversion 的工作原理大致如下:假设 I 指代上下文中的假设 P, - 且 P 由 Inductive 归纳定义,则对于 P 每一种可能的构造,inversion I +inversion 的工作原理大致如下:假设 H 指代上下文中的假设 P, + 且 P 由 Inductive 归纳定义,则对于 P 每一种可能的构造,inversion H 各为其生成子目标。子目标中自相矛盾者被忽略,证明其余子命题即可得证原命题。 - 在证明子目标时,上下文中的 I 会替换为 P 的构造条件, + 在证明子目标时,上下文中的 H 会替换为 P 的构造条件, 即其构造子所需参数以及必要的等式关系。例如:倘若 ev n 由 evSS 构造, 上下文中会引入参数 n'、ev n',以及等式 S (S n') = n。@@ -459,36 +495,36 @@IndProp归纳定义的命题<
-Lemma ev_even_firsttry : ∀ n,
- ev n → ∃ k, n = double k.
+Lemma ev_even_firsttry : ∀n,
+ even n → ∃k, n = double k.
Proof.
(* 课上已完成 *)
我们可以尝试使用分类讨论或对 n 进行归纳。 - 但由于 ev 在前提中出现,如同之前章节的一些例子,这种策略或许无法行得通。 - 如此我们似乎可以首先尝试对 ev 的证据进行反演。 + 但由于 even 在前提中出现,如同之前章节的一些例子,这种策略或许无法行得通。 + 如此我们似乎可以首先尝试对 even 的证据进行反演。 确实,第一个分类可以被平凡地证明。intros n E. inversion E as [| n' E'].
- (* E = ev_0 *)
- ∃ 0. reflexivity.
+ ∃0. reflexivity.
- (* E = ev_SS n' E' *) simpl.
-不幸地是,第二个分类要困难一些。我们需要证明 ∃k, S (S n') = double k, - 但唯一可用的假设是 E',也即 ev n' 成立。但这对证明并没有帮助, +不幸地是,第二个分类要困难一些。我们需要证明 ∃ k, S (S n') = double k, + 但唯一可用的假设是 E',也即 even n' 成立。但这对证明并没有帮助, 我们似乎被卡住了,而对 E 进行分类讨论是徒劳的。如果仔细观察第二个(子)目标,我们可以发现一些有意思的事情: 对 E 进行分类讨论,我们可以把要证明的原始目标归约到另一个上, - 其涉及到另一个 ev 的证据: E'。 + 其涉及到另一个 even 的证据: E'。 形式化地说,我们可以通过展示如下证据来完成证明:@@ -497,7 +533,7 @@IndProp归纳定义的命题<
- ∃ k', n' = double k', + ∃k', n' = double k',@@ -509,15 +545,15 @@IndProp归纳定义的命题<
- assert (I : (∃ k', n' = double k') →
- (∃ k, S (S n') = double k)).
- { intros [k' Hk']. rewrite Hk'. ∃ (S k'). reflexivity. }
+ assert (I : (∃k', n' = double k') →
+ (∃k, S (S n') = double k)).
+ { intros [k' Hk']. rewrite Hk'. ∃(S k'). reflexivity. }
apply I. (* 将原始目标归约到新目标上 *)
Abort.
-对证据进行归纳
+对证据进行归纳
@@ -531,38 +567,38 @@IndProp归纳定义的命题<
- To prove a property of n holds for all number for which ev n - holds, we can use induction on ev n. This requires us to prove - two things, corresponding to the two cases of how ev n could - have been constructed. If it was constructed by ev_0, then n=0, - and the property must hold of 0. If it was constructed by ev_SS, - then the evidence of ev n is of the form ev_SS n' E', where - n = S (S n') and E' is evidence for ev n'. In this case, - the inductive hypothesis says that the property we are trying to prove - holds for n'. + To prove a property of n holds for all numbers for which even + n holds, we can use induction on even n. This requires us to + prove two things, corresponding to the two ways in which even n + could have been constructed. If it was constructed by ev_0, then + n=0, and the property must hold of 0. If it was constructed by + ev_SS, then the evidence of even n is of the form ev_SS n' + E', where n = S (S n') and E' is evidence for even n'. In + this case, the inductive hypothesis says that the property we are + trying to prove holds for n'.让我们再次尝试证明这个引理:-Lemma ev_even : ∀ n,
- ev n → ∃ k, n = double k.
+Lemma ev_even : ∀n,
+ even n → ∃k, n = double k.
Proof.
intros n E.
induction E as [|n' E' IH].
- (* E = ev_0 *)
- ∃ 0. reflexivity.
+ ∃0. reflexivity.
- (* E = ev_SS n' E'
同时 IH : exists k', n' = double k' *)
destruct IH as [k' Hk'].
- rewrite Hk'. ∃ (S k'). reflexivity.
+ rewrite Hk'. ∃(S k'). reflexivity.
Qed.
这里我们看到 Coq 对 E' 产生了 IH,而 E' 是唯一递归出现的 - ev 命题。 由于 E' 中涉及到 n',这个归纳假设是关于 n' 的, + even 命题。 由于 E' 中涉及到 n',这个归纳假设是关于 n' 的, 而非关于 n 或其他数字的。@@ -570,11 +606,11 @@IndProp归纳定义的命题<
-Theorem ev_even_iff : ∀ n,@@ -587,11 +623,11 @@
- ev n ↔ ∃ k, n = double k.
+Theorem ev_even_iff : ∀n,
+ even n ↔ ∃k, n = double k.
Proof.
intros n. split.
- - (* -> *) apply ev_even.
+ - (* -> *) apply ev_even.
- (* <- *) intros [k Hk]. rewrite Hk. apply ev_double.
Qed.
IndProp归纳定义的命题< 下面的练习提供了一些简单的例子,来帮助你熟悉这项技术。
-练习:2 星 (ev_sum)
+练习:2 星, standard (ev_sum)
-Theorem ev_sum : ∀ n m, ev n → ev m → ev (n + m).@@ -600,15 +636,16 @@
+Theorem ev_sum : ∀n m, even n → even m → even (n + m).
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-练习:4 星, advanced, optional (evev)
- 一般来说,有很多种方式来归纳地定义一个性质。比如说,下面是关于 ev 的另一种(蹩脚的)定义: +练习:4 星, advanced, optional (evenev)
+ 一般来说,有很多种方式来归纳地定义一个性质。比如说,下面是关于 + even 的另一种(蹩脚的)定义:-Inductive ev' : nat → Prop :=
-| ev'_0 : ev' 0
-| ev'_2 : ev' 2
-| ev'_sum n m (Hn : ev' n) (Hm : ev' m) : ev' (n + m).
+Inductive even' : nat → Prop :=
+| even'_0 : even' 0
+| even'_2 : even' 2
+| even'_sum n m (Hn : even' n) (Hm : even' m) : even' (n + m).
@@ -616,7 +653,7 @@IndProp归纳定义的命题<
-Theorem ev'_ev : ∀ n, ev' n ↔ ev n.@@ -625,13 +662,13 @@
+Theorem even'_ev : ∀n, even' n ↔ even n.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-练习:3 星, advanced, recommended (ev_ev__ev)
+练习:3 星, advanced, recommended (ev_ev__ev)
在本题中找到适合进行归纳的项需要一点技巧:-Theorem ev_ev__ev : ∀ n m,@@ -640,13 +677,13 @@
- ev (n+m) → ev n → ev m.
+Theorem ev_ev__ev : ∀n m,
+ even (n+m) → even n → even m.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-练习:3 星, optional (ev_plus_plus)
+练习:3 星, standard, optional (ev_plus_plus)
这个练习仅仅需要使用前述引理,而不需要使用归纳或分类讨论,尽管一些重写可能会比较乏味。-Theorem ev_plus_plus : ∀ n m p,@@ -654,11 +691,11 @@
- ev (n+m) → ev (n+p) → ev (m+p).
+Theorem ev_plus_plus : ∀n m p,
+ even (n+m) → even (n+p) → even (m+p).
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题< ☐
-归纳关系
+归纳关系
- 我们可以认为被一个数所参数化的命题(比如 ev)是一个性质,也即, + 我们可以认为被一个数所参数化的命题(比如 even)是一个性质,也即, 它定义了 nat 的一个子集,其中的数可以被证明满足此命题。 以同样的方式,我们可认为有两个参数的命题是一个关系,也即,它定义了一个 可满足此命题的序对集合。 @@ -684,7 +721,7 @@IndProp归纳定义的命题<
-类似于证明 ev 这样的性质,使用 le_n 和 le_S 构造子来证明关于 ≤ +类似于证明 even 这样的性质,使用 le_n 和 le_S 构造子来证明关于 ≤ 的事实遵循了同样的模式。我们可以对构造子使用 apply 策略来证明 ≤ 目标 (比如证明 3≤3 或 3≤6),也可以使用 inversion 策略来从上下文中 ≤ 的假设里抽取信息(比如证明 (2≤1) → 2+2=5)。 @@ -733,12 +770,12 @@IndProp归纳定义的命题< Inductive next_nat : nat → nat → Prop :=
| nn n : next_nat n (S n).
Inductive next_even : nat → nat → Prop :=
- | ne_1 n : ev (S n) → next_even n (S n)
- | ne_2 n (H : ev (S (S n))) : next_even n (S (S n)).
+ | ne_1 n : even (S n) → next_even n (S n)
+ | ne_2 n (H : even (S (S n))) : next_even n (S (S n)).
-练习:2 星, optional (total_relation)
+练习:2 星, standard, optional (total_relation)
请定一个二元归纳关系 total_relation 对每一个自然数的序对成立。@@ -750,7 +787,7 @@IndProp归纳定义的命题<
-练习:2 星, optional (empty_relation)
+练习:2 星, standard, optional (empty_relation)
请定一个二元归纳关系 empty_relation 对自然数永远为假。@@ -770,48 +807,48 @@IndProp归纳定义的命题< In the second case, e2 = S n' for some n' for which le e1 n' holds, and it will replace instances of e2 with S n'. Doing inversion H will remove impossible cases and add generated - equalities to the context for further use. Doing induction H will, - in the second case, add the inductive hypothesis that the goal holds - when e2 is replaced with n'. + equalities to the context for further use. Doing induction H + will, in the second case, add the induction hypothesis that the + goal holds when e2 is replaced with n'.
-练习:3 星, optional (le_exercises)
+练习:3 星, standard, optional (le_exercises)
这里展示一些 ≤ 和 < 关系的事实,我们在接下来的课程中将会用到他们。 证明他们将会是非常有益的练习。-Lemma le_trans : ∀ m n o, m ≤ n → n ≤ o → m ≤ o.
+Lemma le_trans : ∀m n o, m ≤ n → n ≤ o → m ≤ o.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem O_le_n : ∀ n,
+Theorem O_le_n : ∀n,
0 ≤ n.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem n_le_m__Sn_le_Sm : ∀ n m,
+Theorem n_le_m__Sn_le_Sm : ∀n m,
n ≤ m → S n ≤ S m.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem Sn_le_Sm__n_le_m : ∀ n m,
+Theorem Sn_le_Sm__n_le_m : ∀n m,
S n ≤ S m → n ≤ m.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem le_plus_l : ∀ a b,
+Theorem le_plus_l : ∀a b,
a ≤ a + b.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem plus_lt : ∀ n1 n2 m,
+Theorem plus_lt : ∀n1 n2 m,
n1 + n2 < m →
n1 < m ∧ n2 < m.
Proof.
unfold lt.
(* 请在此处解答 *) Admitted.
-Theorem lt_S : ∀ n m,
+Theorem lt_S : ∀n m,
n < m →
n < S m.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem leb_complete : ∀ n m,
+Theorem leb_complete : ∀n m,
n <=? m = true → n ≤ m.
Proof.
(* 请在此处解答 *) Admitted.
@@ -822,7 +859,7 @@IndProp归纳定义的命题<
-Theorem leb_correct : ∀ n m,
+Theorem leb_correct : ∀n m,
n ≤ m →
n <=? m = true.
Proof.
@@ -834,7 +871,7 @@IndProp归纳定义的命题<
-Theorem leb_true_trans : ∀ n m o,
+Theorem leb_true_trans : ∀n m o,
n <=? m = true → m <=? o = true → n <=? o = true.
Proof.
(* 请在此处解答 *) Admitted.
@@ -844,11 +881,11 @@IndProp归纳定义的命题<
-Theorem leb_iff : ∀ n m,
+Theorem leb_iff : ∀n m,
n <=? m = true ↔ n ≤ m.
Proof.
(* 请在此处解答 *) Admitted.
@@ -861,7 +898,7 @@IndProp归纳定义的命题<
-练习:3 星, recommended (R_provability)
+练习:3 星, standard, recommended (R_provability)
通过同样的方式,我们可以定义三元关系、四元关系等。例如,考虑以下定义在自然数上的三元关系:@@ -924,14 +961,14 @@IndProp归纳定义的命题<
-练习:3 星, optional (R_fact)
+练习:3 星, standard, optional (R_fact)
关系 R 其实编码了一个熟悉的函数。请找出这个函数,定义它并在 Coq 中证明他们等价。Definition fR : nat → nat → nat@@ -943,7 +980,7 @@
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem R_equiv_fR : ∀ m n o, R m n o ↔ fR m n = o.
+Theorem R_equiv_fR : ∀m n o, R m n o ↔ fR m n = o.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-练习:4 星, advanced (subsequence)
+练习:2 星, advanced (subsequence)
如果一个列表的所有元素以相同的顺序出现在另一个列表之中(但允许其中出现其他额外的元素), 我们把第一个列表称作第二个列表的子序列。 例如: @@ -1010,16 +1047,30 @@IndProp归纳定义的命题<
-(* 请在此处解答 *)☐
-(* 请勿修改下面这一行: *)
-Definition manual_grade_for_subsequence : option (nat*string) := None.
+Inductive subseq : list nat → list nat → Prop :=
+(* 请在此处解答 *)
+.
+Theorem subseq_refl : ∀(l : list nat), subseq l l.
+Proof.
+ (* 请在此处解答 *) Admitted.
+Theorem subseq_app : ∀(l1 l2 l3 : list nat),
+ subseq l1 l2 →
+ subseq l1 (l2 ++ l3).
+Proof.
+ (* 请在此处解答 *) Admitted.
+Theorem subseq_trans : ∀(l1 l2 l3 : list nat),
+ subseq l1 l2 →
+ subseq l2 l3 →
+ subseq l1 l3.
+Proof.
+ (* 请在此处解答 *) Admitted.
-练习:2 星, optional (R_provability2)
+练习:2 星, standard, optional (R_provability2)
假设我们在 Coq 中有如下定义:@@ -1027,8 +1078,8 @@IndProp归纳定义的命题<
Inductive R : nat → list nat → Prop :=@@ -1056,17 +1107,17 @@
| c1 : R 0 []
- | c2 : ∀ n l, R n l → R (S n) (n :: l)
- | c3 : ∀ n l, R (S n) l → R n l. + | c2 : ∀n l, R n l → R (S n) (n :: l)
+ | c3 : ∀n l, R (S n) l → R n l.IndProp归纳定义的命题< ☐
-案例学习:正则表达式
+案例学习:正则表达式
- 性质 ev 提供了一个简单的例子来展示归纳定义和其基础的推理技巧, - 但这还不是什么激动人心的东西——毕竟,ev 等价于我们之前见过的两个非归纳的定义, + 性质 even 提供了一个简单的例子来展示归纳定义和其基础的推理技巧, + 但这还不是什么激动人心的东西——毕竟,even 等价于我们之前见过的两个非归纳的定义, 而看起来归纳定义并没有提供什么好处。为了更好地展示归纳定义的表达能力, 我们继续使用它来建模计算机科学中的一个经典概念——正则表达式。- 正则表达式是用来描述字符串的一种简单语言,定义如下: + 正则表达式是用来描述字符串集合的一种简单语言,定义如下:@@ -1314,7 +1365,7 @@IndProp归纳定义的命题<
-Example reg_exp_ex3 : ¬ ([1; 2] =~ Char 1).
+Example reg_exp_ex3 : ¬([1; 2] =~ Char 1).
Proof.
@@ -1356,7 +1407,7 @@IndProp归纳定义的命题<
Lemma MStar1 :
- ∀ T s (re : @reg_exp T) ,
+ ∀T s (re : @reg_exp T) ,
s =~ re →
s =~ Star re.
@@ -1375,16 +1426,16 @@IndProp归纳定义的命题< (请注意对 app_nil_r 的使用改变了目标,以此可匹配 MStarApp 所需要的形式。)
-练习:3 星 (exp_match_ex1)
+练习:3 星, standard (exp_match_ex1)
下面的引理显示从形式化的归纳定义中可以得到本章开始的非形式化匹配规则。-Lemma empty_is_empty : ∀ T (s : list T),
- ¬ (s =~ EmptySet).
+Lemma empty_is_empty : ∀T (s : list T),
+ ¬(s =~ EmptySet).
Proof.
(* 请在此处解答 *) Admitted.
-Lemma MUnion' : ∀ T (s : list T) (re1 re2 : @reg_exp T),
+Lemma MUnion' : ∀T (s : list T) (re1 re2 : @reg_exp T),
s =~ re1 ∨ s =~ re2 →
s =~ Union re1 re2.
Proof.
@@ -1398,8 +1449,8 @@IndProp归纳定义的命题<
-Lemma MStar' : ∀ T (ss : list (list T)) (re : reg_exp),@@ -1525,17 +1577,17 @@
- (∀ s, In s ss → s =~ re) →
+Lemma MStar' : ∀T (ss : list (list T)) (re : reg_exp),
+ (∀s, In s ss → s =~ re) →
fold app ss [] =~ Star re.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1409,12 +1460,12 @@IndProp归纳定义的命题<
-练习:4 星, optional (reg_exp_of_list_spec)
+练习:4 星, standard, optional (reg_exp_of_list_spec)
请证明 reg_exp_of_list 满足以下规范:-Lemma reg_exp_of_list_spec : ∀ T (s1 s2 : list T),
+Lemma reg_exp_of_list_spec : ∀T (s1 s2 : list T),
s1 =~ reg_exp_of_list s2 ↔ s1 = s2.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1446,7 +1497,8 @@IndProp归纳定义的命题< | App re1 re2 ⇒ re_chars re1 ++ re_chars re2
| Union re1 re2 ⇒ re_chars re1 ++ re_chars re2
| Star re ⇒ re_chars re
- end.
+ end.
+(* /HIDEFROMHTML *)
@@ -1454,7 +1506,7 @@IndProp归纳定义的命题<
-Theorem in_re_match : ∀ T (s : list T) (re : reg_exp) (x : T),
+Theorem in_re_match : ∀T (s : list T) (re : reg_exp) (x : T),
s =~ re →
In x s →
In x (re_chars re).
@@ -1507,7 +1559,7 @@IndProp归纳定义的命题<
-@@ -1515,8 +1567,8 @@练习:4 星 (re_not_empty)
+练习:4 星, standard (re_not_empty)
请编写一个递归函数 re_not_empty 用来测试某个正则表达式是否会匹配一些字符串。 并证明你的函数是正确的。IndProp归纳定义的命题< Fixpoint re_not_empty {T : Type} (re : @reg_exp T) : bool
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Lemma re_not_empty_correct : ∀ T (re : @reg_exp T),
- (∃ s, s =~ re) ↔ re_not_empty re = true.
+Lemma re_not_empty_correct : ∀T (re : @reg_exp T),
+ (∃s, s =~ re) ↔ re_not_empty re = true.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-remember 策略
+remember 策略
- induction 策略让人困惑的一个特点是它会欣然接受任意一个项并尝试归纳, - 即使这个项不够一般(general)。其副作用是会丢失掉一些信息(类似 destruct), - 并且使你无法完成证明。比如: + induction 策略让人困惑的一个特点是它会接受任意一个项并尝试归纳, + 即使这个项不够一般(general)。其副作用是会丢失掉一些信息(类似没有 eqn: + 从句的 destruct),并且使你无法完成证明。比如:-Lemma star_app: ∀ T (s1 s2 : list T) (re : @reg_exp T),
+Lemma star_app: ∀T (s1 s2 : list T) (re : @reg_exp T),
s1 =~ Star re →
s2 =~ Star re →
s1 ++ s2 =~ Star re.
@@ -1592,15 +1644,17 @@IndProp归纳定义的命题<
- (由此,对证据使用 induction 的行为更像是 destruct 而非 inversion。) + (由此,对证据使用 induction 的行为更像是没有 eqn: 的 destruct + 而非 inversion。)- 通过显式地添加一个等式来一般化这个有问题的表达式,我们便可以解决这个问题: + 解决此问题的一种直接的方式是“手动推广”这个有问题的表达式, + 即为此引理添加一个显式的等式:-Lemma star_app: ∀ T (s1 s2 : list T) (re re' : reg_exp),
+Lemma star_app: ∀T (s1 s2 : list T) (re re' : reg_exp),
re' = Star re →
s1 =~ re' →
s2 =~ Star re →
@@ -1622,13 +1676,13 @@IndProp归纳定义的命题<
-在 Coq 中使用 remember e as x 策略会(1)替换所有表达式 e 为变量 x, +在 Coq 中调用 remember e as x 策略会(1)替换所有表达式 e 为变量 x, (2)在当前上下文中添加一个等式 x = e。我们可以这样使用 remember 来证明上面的结果:-Lemma star_app: ∀ T (s1 s2 : list T) (re : reg_exp),
+Lemma star_app: ∀T (s1 s2 : list T) (re : reg_exp),
s1 =~ Star re →
s2 =~ Star re →
s1 ++ s2 =~ Star re.
@@ -1682,20 +1736,20 @@IndProp归纳定义的命题<
-练习:4 星, optional (exp_match_ex2)
+练习:4 星, standard, optional (exp_match_ex2)
- 下面的引理 MStar''(以及它的逆,之前的练习题中的 MStar')显示 + 下面的引理 MStar''(以及它的逆,之前的练习题中的 MStar')显示 exp_match 中 Star 的定义等价于前面给出的非形式化定义。-Lemma MStar'' : ∀ T (s : list T) (re : reg_exp),@@ -1704,7 +1758,7 @@
+Lemma MStar'' : ∀T (s : list T) (re : reg_exp),
s =~ Star re →
- ∃ ss : list (list T),
+ ∃ss : list (list T),
s = fold app ss []
- ∧ ∀ s', In s' ss → s' =~ re.
+ ∧ ∀s', In s' ss → s' =~ re.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-练习:5 星, advanced (pumping)
+练习:5 星, advanced (pumping)
正则表达式中一个非常有趣的定理叫做泵引理(Pumping Lemma), 非形式化地来讲,它陈述了任意某个足够长的字符串 s 若匹配一个正则表达式 re, 则可以被抽取(pumped)——将 s 的某个中间部分重复任意次产生的新字符串 @@ -1741,7 +1795,7 @@IndProp归纳定义的命题< | 0 ⇒ []
| S n' ⇒ l ++ napp n' l
end.
-Lemma napp_plus: ∀ T (n m : nat) (l : list T),
+Lemma napp_plus: ∀T (n m : nat) (l : list T),
napp (n + m) l = napp n l ++ napp m l.
Proof.
intros T n m l.
@@ -1759,13 +1813,13 @@IndProp归纳定义的命题<
-Lemma pumping : ∀ T (re : @reg_exp T) s,
+Lemma pumping : ∀T (re : @reg_exp T) s,
s =~ re →
pumping_constant re ≤ length s →
- ∃ s1 s2 s3,
+ ∃s1 s2 s3,
s = s1 ++ s2 ++ s3 ∧
s2 ≠ [] ∧
- ∀ m, s1 ++ napp m s2 ++ s3 =~ re.
+ ∀m, s1 ++ napp m s2 ++ s3 =~ re.
@@ -1792,7 +1846,7 @@IndProp归纳定义的命题< ☐
-Theorem filter_not_empty_In : ∀ n l,
+Theorem filter_not_empty_In : ∀n l,
filter (fun x ⇒ n =? x) l ≠ [] →
In n l.
Proof.
@@ -1827,32 +1881,33 @@IndProp归纳定义的命题< 为了简化这样的证明,我们可定义一个归纳命题,用于对 n =? m 产生更好的分类讨论原理。 - 它不会生成类似 n =? m = true 这样的等式,因为一般来说对证明并不直接有用, + 它不会生成类似 (n =? m) = true这样的等式,因为一般来说对证明并不直接有用, 其生成的分类讨论原理正是我们所需要的假设: n = m。
Inductive reflect (P : Prop) : bool → Prop :=
| ReflectT (H : P) : reflect P true
-| ReflectF (H : ¬ P) : reflect P false.
+| ReflectF (H : ¬P) : reflect P false.
性质 reflect 接受两个参数:一个命题 P 和一个布尔值 b。 直观地讲,它陈述了性质 P 在布尔值 b 中所映现(也即,等价): 换句话说,P 成立当且仅当 b = true。为了理解这一点,请注意定义, - 我们能够产生 reflect P true 的证据的唯一方式是证明 P 为真且使用 + 我们能够产生 reflect P true 的证据的唯一方式是证明 P 为真并使用 ReflectT 构造子。如果我们反转这个陈述,意味着从 reflect P true - 的证明中抽取出 P 的证据也是可能的。相反地,展示 reflect P false + 的证明中抽取出 P 的证据也是可能的。与此类似,证明 reflect P false 的唯一方式是合并 ¬ P 的证据和 ReflectF 构造子。- 形式化这种直觉并证明两个表述确实等价是十分容易的: + 形式化这种直觉并证明 P ↔ b = true 和 reflect P b + 这两个表述确实等价是十分容易的。首先是从左到右的蕴含:-Theorem iff_reflect : ∀ P b, (P ↔ b = true) → reflect P b.
+Theorem iff_reflect : ∀P b, (P ↔ b = true) → reflect P b.
Proof.
(* 课上已完成 *)
intros P b H. destruct b.
@@ -1862,11 +1917,14 @@IndProp归纳定义的命题<
-练习:2 星, recommended (reflect_iff)
+Now you prove the right-to-left implication: ++ +练习:2 星, standard, recommended (reflect_iff)
-Theorem reflect_iff : ∀ P b, reflect P b → (P ↔ b = true).@@ -1882,14 +1940,14 @@
+Theorem reflect_iff : ∀P b, reflect P b → (P ↔ b = true).
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
-Lemma eqbP : ∀ n m, reflect (n = m) (n =? m).
+Lemma eqbP : ∀n m, reflect (n = m) (n =? m).
Proof.
intros n m. apply iff_reflect. rewrite eqb_eq. reflexivity.
Qed.
-filter_not_empty_In 的新证明如下所示。请注意对 destruct 和 apply +filter_not_empty_In 的一种更流畅证明如下所示。请注意对 destruct 和 apply 的使用是如何合并成一个 destruct 的使用。@@ -1898,7 +1956,7 @@IndProp归纳定义的命题<
-Theorem filter_not_empty_In' : ∀ n l,
+Theorem filter_not_empty_In' : ∀n l,
filter (fun x ⇒ n =? x) l ≠ [] →
In n l.
Proof.
@@ -1915,7 +1973,7 @@IndProp归纳定义的命题<
-练习:3 星, recommended (eqbP_practice)
+练习:3 星, standard, recommended (eqbP_practice)
使用上面的 eqbP 证明以下定理:@@ -1925,7 +1983,7 @@IndProp归纳定义的命题< | [] ⇒ 0
| m :: l' ⇒ (if n =? m then 1 else 0) + count n l'
end.
-Theorem eqbP_practice : ∀ n l,
+Theorem eqbP_practice : ∀n l,
count n l = 0 → ~(In n l).
Proof.
(* 请在此处解答 *) Admitted.
@@ -1935,24 +1993,24 @@IndProp归纳定义的命题<
- 在这个小例子中,这种技术仅仅在证明时提升了一点方便;然而,当证明变得庞大时, + 这个小例子展示了互映证明可以怎样为我们提供一些便利。在大型的开发中, 使用 reflect 往往更容易写出清晰和简短的证明脚本。我们将会在后面的章节 和编程语言基础一卷中看到更多的例子。- 对 reflect 性质的使用是随着 SSReflect 而流行开来的,这是一个 + 对 reflect 性质的使用已被 SSReflect 推广开来,这是一个 Coq 程序库,用于形式化一些数学上的重要结果,包括四色定理和法伊特-汤普森定理。 SSReflect 的名字代表着 small-scale reflection,也即,普遍性地使用 互映来简化与布尔值计算有关的证明。-额外练习
+额外练习
-练习:3 星, recommended (nostutter_defn)
+练习:3 星, standard, recommended (nostutter_defn)
写出性质的归纳定义是本课程中你需要的重要技能。请尝试去独立解决以下的练习。@@ -2000,7 +2058,7 @@IndProp归纳定义的命题< (*
Proof. intro.
repeat match goal with
- h: nostutter _ |- _ => inversion h; clear h; subst
+ h: nostutter _ ⊢ _ => inversion h; clear h; subst
end.
contradiction Hneq0; auto. Qed.
*)
@@ -2012,7 +2070,7 @@IndProp归纳定义的命题<
-练习:4 星, advanced (filter_challenge)
+练习:4 星, advanced (filter_challenge)
让我们证明在 Poly 一章中 filter 的定义匹配某个抽象的规范。 可以这样非形式化地描述这个规范: @@ -2070,7 +2128,7 @@IndProp归纳定义的命题<
@@ -2083,7 +2141,7 @@-练习:5 星, advanced, optional (filter_challenge_2)
+练习:5 星, advanced, optional (filter_challenge_2)
另一种刻画 filter 行为的方式是:在 l 的所有其元素满足 test 的子序列中, filter test l 是最长的那个。请形式化这个命题并证明它。IndProp归纳定义的命题<
-练习:4 星, optional (palindromes)
+练习:4 星, standard, optional (palindromes)
回文是倒序排列与正序排列相同的序列。@@ -2095,7 +2153,7 @@IndProp归纳定义的命题<
- c : ∀ l, l = rev l → pal l + c : ∀l, l = rev l → pal l@@ -2110,7 +2168,7 @@IndProp归纳定义的命题<
- ∀ l, pal (l ++ rev l). + ∀l, pal (l ++ rev l).@@ -2121,7 +2179,7 @@IndProp归纳定义的命题<
- ∀ l, pal l → l = rev l. + ∀l, pal l → l = rev l.@@ -2141,13 +2199,13 @@IndProp归纳定义的命题<
-练习:5 星, optional (palindrome_converse)
+练习:5 星, standard, optional (palindrome_converse)
由于缺乏证据,反方向的证明要困难许多。使用之前练习中定义的 pal 来证明- ∀ l, l = rev l → pal l. + ∀l, l = rev l → pal l.@@ -2162,7 +2220,7 @@IndProp归纳定义的命题<
-练习:4 星, advanced, optional (NoDup)
+练习:4 星, advanced, optional (NoDup)
请回忆一下 Logic 章节中性质 In 的定义,其断言值 x 在列表 l 中至少出现一次:@@ -2208,7 +2266,7 @@IndProp归纳定义的命题<
-练习:4 星, advanced, optional (pigeonhole_principle)
+练习:4 星, advanced, optional (pigeonhole_principle)
_鸽笼原理(Pigeonhole Principle)是一个关于计数的基本事实: 将超过 n 个物体放进 n 个鸽笼,则必有鸽笼包含至少两个物体。 与此前诸多情形相似,这一数学事实看似乏味,但其证明手段并不平凡, @@ -2219,9 +2277,9 @@IndProp归纳定义的命题<
-Lemma in_split : ∀ (X:Type) (x:X) (l:list X),@@ -2245,15 +2303,15 @@
+Lemma in_split : ∀(X:Type) (x:X) (l:list X),
In x l →
- ∃ l1 l2, l = l1 ++ x :: l2.
+ ∃l1 l2, l = l1 ++ x :: l2.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
如果使用 excluded_middule 假设并展示 In 是可判定的(decidable), - 即 ∀x l, (In x l) ∨ ¬ (In x l),那么这个证明会容易很多。 + 即 ∀ x l, (In x l) ∨ ¬ (In x l),那么这个证明会容易很多。 然而,若不假设 In 的可判定性也同样可以证明它;在这样的情况下便不必使用 excluded_middle 假设。-Theorem pigeonhole_principle: ∀ (X:Type) (l1 l2:list X),
+Theorem pigeonhole_principle: ∀(X:Type) (l1 l2:list X),
excluded_middle →
- (∀ x, In x l1 → In x l2) →
+ (∀x, In x l1 → In x l2) →
length l2 < length l1 →
repeats l1.
Proof.
@@ -2267,7 +2325,7 @@IndProp归纳定义的命题<
-Lemma provable_equiv_true : ∀ (P : Prop), P → (P ↔ True).
+Lemma provable_equiv_true : ∀(P : Prop), P → (P ↔ True).
Proof.
intros.
split.
@@ -2329,7 +2387,7 @@IndProp归纳定义的命题< 其逆可被证明的 Prop 等价于 False。
-Lemma not_equiv_false : ∀ (P : Prop), ¬P → (P ↔ False).
+Lemma not_equiv_false : ∀(P : Prop), ¬P → (P ↔ False).
Proof.
intros.
split.
@@ -2342,7 +2400,7 @@IndProp归纳定义的命题< EmptySet 不匹配字符串。
-Lemma null_matches_none : ∀ (s : string), (s =~ EmptySet) ↔ False.
+Lemma null_matches_none : ∀(s : string), (s =~ EmptySet) ↔ False.
Proof.
intros.
apply not_equiv_false.
@@ -2354,7 +2412,7 @@IndProp归纳定义的命题< EmptyStr 仅匹配空字符串。
-Lemma empty_matches_eps : ∀ (s : string), s =~ EmptyStr ↔ s = [ ].
+Lemma empty_matches_eps : ∀(s : string), s =~ EmptyStr ↔ s = [ ].
Proof.
split.
- intros. inversion H. reflexivity.
@@ -2366,7 +2424,7 @@IndProp归纳定义的命题< EmptyStr 不匹配非空字符串。
-Lemma empty_nomatch_ne : ∀ (a : ascii) s, (a :: s =~ EmptyStr) ↔ False.
+Lemma empty_nomatch_ne : ∀(a : ascii) s, (a :: s =~ EmptyStr) ↔ False.
Proof.
intros.
apply not_equiv_false.
@@ -2379,7 +2437,7 @@IndProp归纳定义的命题<
Lemma char_nomatch_char :
- ∀ (a b : ascii) s, b ≠ a → (b :: s =~ Char a ↔ False).
+ ∀(a b : ascii) s, b ≠ a → (b :: s =~ Char a ↔ False).
Proof.
intros.
apply not_equiv_false.
@@ -2395,7 +2453,7 @@IndProp归纳定义的命题< 如果 Char a 匹配一个非空字符串,那么这个字符串的尾(tail)为空。
-Lemma char_eps_suffix : ∀ (a : ascii) s, a :: s =~ Char a ↔ s = [ ].
+Lemma char_eps_suffix : ∀(a : ascii) s, a :: s =~ Char a ↔ s = [ ].
Proof.
split.
- intros. inversion H. reflexivity.
@@ -2408,13 +2466,13 @@IndProp归纳定义的命题< 匹配 re0 且 s1 匹配 re1。
-Lemma app_exists : ∀ (s : string) re0 re1,
+Lemma app_exists : ∀(s : string) re0 re1,
s =~ App re0 re1 ↔
- ∃ s0 s1, s = s0 ++ s1 ∧ s0 =~ re0 ∧ s1 =~ re1.
+ ∃s0 s1, s = s0 ++ s1 ∧ s0 =~ re0 ∧ s1 =~ re1.
Proof.
intros.
split.
- - intros. inversion H. ∃ s1, s2. split.
+ - intros. inversion H. ∃s1, s2. split.
* reflexivity.
* split. apply H3. apply H4.
- intros [ s0 [ s1 [ Happ [ Hmat0 Hmat1 ] ] ] ].
@@ -2423,7 +2481,7 @@IndProp归纳定义的命题<
-练习:3 星, optional (app_ne)
+练习:3 星, standard, optional (app_ne)
App re0 re1 匹配 a::s 当且仅当 re0 匹配空字符串 且 a::s 匹配 re1 或 s=s0++s1,其中 a::s0 匹配 re0 且 s1 匹配 re1。 @@ -2434,10 +2492,10 @@IndProp归纳定义的命题< 因此(1)花一些时间理解它,(2)证明它,并且(3)留心后面你会如何使用它。
-Lemma app_ne : ∀ (a : ascii) s re0 re1,@@ -2449,7 +2507,7 @@
+Lemma app_ne : ∀(a : ascii) s re0 re1,
a :: s =~ (App re0 re1) ↔
([ ] =~ re0 ∧ a :: s =~ re1) ∨
- ∃ s0 s1, s = s0 ++ s1 ∧ a :: s0 =~ re0 ∧ s1 =~ re1.
+ ∃s0 s1, s = s0 ++ s1 ∧ a :: s0 =~ re0 ∧ s1 =~ re1.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题< s 匹配 Union re0 re1 当且仅当 s 匹配 re0 或 s 匹配 re1.
-Lemma union_disj : ∀ (s : string) re0 re1,
+Lemma union_disj : ∀(s : string) re0 re1,
s =~ Union re0 re1 ↔ s =~ re0 ∨ s =~ re1.
Proof.
intros. split.
@@ -2463,7 +2521,7 @@IndProp归纳定义的命题<
-练习:3 星, optional (star_ne)
+练习:3 星, standard, optional (star_ne)
a::s 匹配 Star re 当且仅当 s = s0 ++ s1,其中 a::s0 匹配 re 且 s1 匹配 Star re。 同 app_ne一样,这个观察很重要, 因此理解,证明并留意它。 @@ -2481,9 +2539,9 @@IndProp归纳定义的命题<
-Lemma star_ne : ∀ (a : ascii) s re,@@ -2497,11 +2555,11 @@
+Lemma star_ne : ∀(a : ascii) s re,
a :: s =~ Star re ↔
- ∃ s0 s1, s = s0 ++ s1 ∧ a :: s0 =~ re ∧ s1 =~ Star re.
+ ∃s0 s1, s = s0 ++ s1 ∧ a :: s0 =~ re ∧ s1 =~ Star re.
Proof.
(* 请在此处解答 *) Admitted.
IndProp归纳定义的命题<
Definition refl_matches_eps m :=
- ∀ re : @reg_exp ascii, reflect ([ ] =~ re) (m re).
+ ∀re : @reg_exp ascii, reflect ([ ] =~ re) (m re).
-练习:2 星, optional (match_eps)
+练习:2 星, standard, optional (match_eps)
完成 match_eps 的定义,其测试给定的正则表达式是否匹配空字符串:@@ -2513,7 +2571,7 @@IndProp归纳定义的命题<
@@ -2540,7 +2598,7 @@-练习:3 星, optional (match_eps_refl)
+练习:3 星, standard, optional (match_eps_refl)
现在,请证明 match_eps 确实测试了给定的正则表达式是否匹配空字符串。 (提示:你会使用到互映引理 ReflectT 和 ReflectF。)IndProp归纳定义的命题<
Definition is_der re (a : ascii) re' :=
- ∀ s, a :: s =~ re ↔ s =~ re'.
+ ∀s, a :: s =~ re ↔ s =~ re'.
@@ -2548,11 +2606,11 @@IndProp归纳定义的命题< 它求值为 re 在 a 上的生成式。也即,d 满足以下关系:
-Definition derives d := ∀ a re, is_der re a (d a re).
+Definition derives d := ∀a re, is_der re a (d a re).
-@@ -2649,7 +2707,7 @@练习:3 星, optional (derive)
+练习:3 星, standard, optional (derive)
请定义 derive 使其生成字符串。一个自然的实现是在某些分类使用 match_eps 来判断正则表达式是否匹配空字符串。IndProp归纳定义的命题<
-练习:4 星, optional (derive_corr)
+练习:4 星, standard, optional (derive_corr)
请证明 derive 确实总是会生成字符串。@@ -2691,11 +2749,11 @@IndProp归纳定义的命题<
Definition matches_regex m : Prop :=
- ∀ (s : string) re, reflect (s =~ re) (m s re).
+ ∀(s : string) re, reflect (s =~ re) (m s re).
-练习:2 星, optional (regex_match)
+练习:2 星, standard, optional (regex_match)
完成 regex_match 的定义,使其可以匹配正则表达式。@@ -2707,7 +2765,7 @@diff --git a/lf-current/IndProp.v b/lf-current/IndProp.v index 4375cdc5..c27ad891 100644 --- a/lf-current/IndProp.v +++ b/lf-current/IndProp.v @@ -7,99 +7,115 @@ Require Coq.omega.Omega. (* ################################################################# *) (** * 归纳定义的命题 *) -(** 在 [Logic] 一章中,我们学习了多种方式来书写命题,包括合取、析取和量词。 - 在本章中,我们引入新的方式:_'归纳定义的命题(Inductive Definitions)'_。 *) +(** 在 [Logic] 一章中,我们学习了多种方式来书写命题,包括合取、析取和存在量词。 + 在本章中,我们引入另一种新的方式:_'归纳定义(Inductive Definitions)'_。 *) -(** 请回想一下我们已经学过的两种方法来表达 [n] 是偶数: - (1) [evenb n = true],以及 (2) [exists k, n = double k] 。 - 然而另一种可能是通过如下规则来建立 [n] 的偶数性质: +(** 在前面的章节中,我们已经见过两种表述 [n] 为偶数的方式了: + + (1) [evenb n = true],以及 + + (2) [exists k, n = double k]。 + + 然而还有一种方式是通过如下规则来建立 [n] 的偶数性质: - 规则 [ev_0]: [0] 是偶数。 - - 规则 [ev_SS]: 如果 [n] 是偶数, 那么 [S (S n)] 是偶数。 *) + - 规则 [ev_SS]: 如果 [n] 是偶数, 那么 [S (S n)] 也是偶数。 *) -(** 为了理解这样的偶数性质定义如何工作,我们可想象如何证明 [4] 是偶数。 +(** 为了理解这个新的偶数性质定义如何工作,我们可想象如何证明 [4] 是偶数。 根据规则 [ev_SS],需要证明 [2] 是偶数。这时,只要证明 [0] 是偶数, 我们可继续通过规则 [ev_SS] 确保它成立。而使用规则 [ev_0] 可直接证明 [0] 是偶数。*) (** 接下来的课程中,我们会看到很多类似方式定义的命题。 在非形式化的讨论中,使用轻量化的记法有助于阅读和书写。 -_'推断规则(Inference Rules)'_是其中的一种: *) -(** + _'推断规则(Inference Rules)'_是其中的一种: - ------------ (ev_0) - ev 0 + ------------ (ev_0) + even 0 - ev n - -------------- (ev_SS) - ev (S (S n)) + even n + ---------------- (ev_SS) + even (S (S n)) *) (** 若将前文所述的规则重新排版成推断规则,我们可以这样阅读它,如果线上方的 _'前提(premises)'_成立,那么线下方的_'结论(conclusion)'_成立。 - 比如,规则 [ev_SS] 读做如果 [n] 满足 [ev],那么 [S (S n)] 也满足。 + 比如,规则 [ev_SS] 读做如果 [n] 满足 [even],那么 [S (S n)] 也满足。 如果一条规则在线上方没有前提,则结论直接成立。 - 我们可以通过组合推断规则来展示证明。下面展示如何转译 [4] 是偶数的证明: *) -(** + 我们可以通过组合推断规则来展示证明。下面展示如何转译 [4] 是偶数的证明: - ------ (ev_0) - ev 0 - ------ (ev_SS) - ev 2 - ------ (ev_SS) - ev 4 + -------- (ev_0) + even 0 + -------- (ev_SS) + even 2 + -------- (ev_SS) + even 4 *) (** - 为什么我们把这样的证明称之为“树”(而非其他,比如“栈”)? - 因为一般来说推断规则可以有多个前提。我们会在后面看到一些例子。 *) + (为什么我们把这样的证明称之为“树”(而非其他,比如“栈”)? + 因为一般来说推断规则可以有多个前提。我们很快就会看到一些例子。 *) -(** 基于上述,可将偶数性质的定义翻译为在 Coq 中使用 [Inductive] 声明的定义, +(* ================================================================= *) +(** ** 偶数性的归纳定义 + + 基于上述,可将偶数性质的定义翻译为在 Coq 中使用 [Inductive] 声明的定义, 声明中每一个构造子对应一个推断规则: *) -Inductive ev : nat -> Prop := -| ev_0 : ev 0 -| ev_SS (n : nat) (H : ev n) : ev (S (S n)). +Inductive even : nat -> Prop := +| ev_0 : even 0 +| ev_SS (n : nat) (H : even n) : even (S (S n)). (** 这个定义同之前其他 [Inductive] 的使用有一个重要的区别: - 它的结果并不是一个 [Type] ,而是一个将 [nat] 映射到 [Prop] 的函数——即关于数的性质。 - 注意我们曾见过结果也为函数的归纳定义,比如 [list],其类型是 [Type -> Type] 。 - 值得注意的是,由于 [ev] 中出现在冒号_'右侧'_的 [nat] 参数是 _'未命名'_ 的, + 我们所定义的并不是一个 [Type],而是一个将 [nat] 映射到 [Prop] 的函数——即关于数的性质。 + 我们曾见过结果也是函数的归纳定义,比如 [list],其类型是 [Type -> Type] 。 + 真正要关注的是,由于 [even] 中出现在冒号_'右侧'_的 [nat] 参数是 _'未命名'_ 的, 这允许在不同的构造子类型中使用不同的值:例如 [ev_0] 类型中的 [0] 以及 [ev_SS] 类型中的 [S (S n)]。 相反,[list] 的定义以_'全局方式'_命名了冒号_'左侧'_的参数 [X], 强迫 [nil] 和 [cons] 的结果为同一个类型([list X])。 - 如果在定义 [ev] 时我们将 [nat] 置于冒号左侧,会得到如下错误: *) + 如果在定义 [even] 时我们将 [nat] 置于冒号左侧,会得到如下错误: *) Fail Inductive wrong_ev (n : nat) : Prop := | wrong_ev_0 : wrong_ev 0 -| wrong_ev_SS : forall n, wrong_ev n -> wrong_ev (S (S n)). -(* ===> Error: A parameter of an inductive type n is not - allowed to be used as a bound variable in the type - of its constructor. *) +| wrong_ev_SS : wrong_ev n -> wrong_ev (S (S n)). +(* ===> Error: Last occurrence of "[wrong_ev]" must have "[n]" + as 1st argument in "[wrong_ev 0]". *) + +(** 在 [Inductive] 定义中,类型构造子的冒号左侧的参数叫做形参(Parameter), + 而右侧的叫做索引(Index)。 + + 例如,在 [Inductive list (X : Type) := ...] 中,[X] 是一个形参;而在 + [Inductive even : nat -> Prop := ...] 中,未命名的 [nat] 参数是一个索引。 *) -(** (“parameter” 是 Coq 中的一个术语来表示 [Inductive] 定义中冒号左侧的参数; - “index” 则指冒号右侧的参数。) *) +(** 在 Coq 中,我们可以认为 [even] 定义了一个性质 [ev : nat -> Prop],其包括原语定理 + [ev_0 : even 0] 和 [ev_SS : forall n, even n -> even (S (S n))]。 *) -(** 在 Coq 中,我们可以认为 [ev] 定义了一个性质 [ev : nat -> Prop],其包括公理(primitive theorems) - [ev_0 : ev 0] 和 [ev_SS : forall n, ev n -> ev (S (S n))]。*) +(** 该定义也可写作如下形式... + + Inductive even : nat -> Prop := + | ev_0 : even 0 + | ev_SS : forall n, even n -> even (S (S n)). +*) + +(** ... 以便让 [ev_SS] 的类型更加直白。 *) (** 这些 “定理构造子” 等同于已经证明过的定理。 - 具体来说,我们可以使用 Coq 中的 [apply] 策略和规则名称来证明某个数的 [ev] 性质…… *) + 具体来说,我们可以使用 Coq 中的 [apply] 策略和规则名称来证明某个数的 [even] 性质…… *) -Theorem ev_4 : ev 4. +Theorem ev_4 : even 4. Proof. apply ev_SS. apply ev_SS. apply ev_0. Qed. (** ……或使用函数应用的语法: *) -Theorem ev_4' : ev 4. +Theorem ev_4' : even 4. Proof. apply (ev_SS 2 (ev_SS 0 ev_0)). Qed. -(** 我们同样可以对前提中使用到 [ev] 的定理进行证明。 *) +(** 我们同样可以对前提中使用到 [even] 的定理进行证明。 *) -Theorem ev_plus4 : forall n, ev n -> ev (4 + n). +Theorem ev_plus4 : forall n, even n -> even (4 + n). Proof. intros n. simpl. intros Hn. apply ev_SS. apply ev_SS. apply Hn. @@ -107,9 +123,9 @@ Qed. (** 更一般地,我们可以证明以任意数乘 2 是偶数: *) -(** **** 练习:1 星 (ev_double) *) +(** **** 练习:1 星, standard (ev_double) *) Theorem ev_double : forall n, - ev (double n). + even (double n). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -119,57 +135,60 @@ Proof. (** 除了_'构造'_证据(evidence)来表示某个数是偶数,我们还可以对这些证据进行_'推理'_。 - 对 [ev] 而言,使用 [Inductive] 声明来引入 [ev] 不仅仅表示在 Coq + 对 [even] 而言,使用 [Inductive] 声明来引入 [even] 不仅仅表示在 Coq 中 [ev_0] 和 [ev_SS] 这样的构造子是合法的方式来构造偶数证明的证据, 他们也是_'仅有的'_方式。 *) -(** 换句话说,如果某人展示了对于 [ev n] 的证据 [E],那么我们知道 [E] +(** 换句话说,如果某人展示了对于 [even n] 的证据 [E],那么我们知道 [E] 必是二者其一: - [E] 是 [ev_0](且 [n] 为 [O]), 或 - [E] 是 [ev_SS n' E'](且 [n] 为 [S (S n')], [E'] 为 - [ev n'] 的证据). *) + [even n'] 的证据). *) -(** 这样的形式暗示着,我们可以像分析归纳定义的数据结构一样分析形如 [ev n] +(** 这样的形式暗示着,我们可以像分析归纳定义的数据结构一样分析形如 [even n] 的假设;特别地,对于这类证据使用_'归纳(induction)'_和_'分类讨论(case analysis)'_来进行论证也是可行的。让我们通过一些例子来学习实践中如何使用他们。 *) (* ================================================================= *) (** ** 对证据进行反演 *) -(** Suppose we are proving some fact involving a number [n], and we - are given [ev n] as a hypothesis. We already know how to perform - case analysis on [n] using [destruct] or [induction], generating - separate subgoals for the case where [n = O] and the case where [n - = S n'] for some [n']. But for some proofs we may instead want to - analyze the evidence that [ev n] _directly_. As a tool, we can - prove our characterization of evidence for [ev n], using [destruct]. *) +(** Suppose we are proving some fact involving a number [n], and + we are given [even n] as a hypothesis. We already know how to + perform case analysis on [n] using [destruct] or [induction], + generating separate subgoals for the case where [n = O] and the + case where [n = S n'] for some [n']. But for some proofs we may + instead want to analyze the evidence that [even n] _directly_. As + a tool, we can prove our characterization of evidence for + [even n], using [destruct]. *) Theorem ev_inversion : - forall (n : nat), ev n -> - (n = 0) \/ (exists m, n = S (S m) /\ ev m). + forall (n : nat), even n -> + (n = 0) \/ (exists n', n = S (S n') /\ even n'). Proof. - intros n Hev. - destruct Hev as [ | m Hm]. - - left. reflexivity. - - right. exists m. split. reflexivity. apply Hm. + intros n E. + destruct E as [ | n' E']. + - (* E = ev_0 : even 0 *) + left. reflexivity. + - (* E = ev_SS n' E' : even (S (S n')) *) + right. exists n'. split. reflexivity. apply E'. Qed. (** 用 [destruct] 解构证据即可证明下述定理: *) Theorem ev_minus2 : forall n, - ev n -> ev (pred (pred n)). + even n -> even (pred (pred n)). Proof. intros n E. destruct E as [| n' E']. - (* E = ev_0 *) simpl. apply ev_0. - - (* E = ev_SS n' E' *) simpl. apply E'. Qed. + - (* E = ev_SS n' E' *) simpl. apply E'. +Qed. (** However, this variation cannot easily be handled with [destruct]. *) Theorem evSS_ev : forall n, - ev (S (S n)) -> ev n. - + even (S (S n)) -> even n. (** 直观来说,我们知道支撑前提的证据不会由 [ev_0] 组成,因为 [0] 和 [S] 是 [nat] 类型不同的构造子;由此 [ev_SS] 是唯一需要应对的情况(译注:[ev_0] 无条件成立)。 不幸的是,[destruct] 并没有如此智能,它仍然为我们生成两个子目标。 @@ -186,31 +205,30 @@ Abort. 这对于证明 [ev_minus2'] 是有帮助的,因为在最终目标中直接使用到了参数 [n]。 然而,这对于 [evSS_ev] 并没有帮助,因为被替换掉的 [S (S n)] 并没有在其他地方被使用。*) -(** We can patch this proof by replacing the goal [ev n], which - does not mention the replaced term [S (S n)], by the equivalent - goal [ev (pred (pred (S (S n))))], which does mention this - term, after which [destruct] can make progress. But it is +(** We could patch this proof by replacing the goal [even n], + which does not mention the replaced term [S (S n)], by the + equivalent goal [even (pred (pred (S (S n))))], which does mention + this term, after which [destruct] can make progress. But it is more straightforward to use our inversion lemma. *) - -Theorem evSS_ev : forall n, ev (S (S n)) -> ev n. +Theorem evSS_ev : forall n, even (S (S n)) -> even n. Proof. intros n H. apply ev_inversion in H. destruct H. - discriminate H. - destruct H as [n' [Hnm Hev]]. injection Hnm. intro Heq. rewrite Heq. apply Hev. Qed. -(** Coq provides the [inversion] tactic, which does the work - of our inversion lemma and more besides. *) +(** Coq provides a tactic called [inversion], which does the work of + our inversion lemma and more besides. *) (** The [inversion] tactic can detect (1) that the first case ([n = 0]) does not apply and (2) that the [n'] that appears in the - [ev_SS] case must be the same as [n]. It has an "as" - variant similar to [destruct], allowing us to assign names - rather than have Coq choose them. *) + [ev_SS] case must be the same as [n]. It has an "[as]" variant + similar to [destruct], allowing us to assign names rather than + have Coq choose them. *) Theorem evSS_ev' : forall n, - ev (S (S n)) -> ev n. + even (S (S n)) -> even n. Proof. intros n E. inversion E as [| n' E']. @@ -222,7 +240,7 @@ Qed. "obviously contradictory" hypotheses involving inductive properties, something that takes a bit more work using our inversion lemma. For example: *) -Theorem one_not_even : ~ ev 1. +Theorem one_not_even : ~ even 1. Proof. intros H. apply ev_inversion in H. destruct H as [ | [m [Hm _]]]. @@ -230,38 +248,36 @@ Proof. - discriminate Hm. Qed. -Theorem one_not_even' : ~ ev 1. +Theorem one_not_even' : ~ even 1. intros H. inversion H. Qed. +(** **** 练习:1 星, standard (inversion_practice) -(** **** 练习:1 星 (inversion_practice) *) -(** 利用 [inversion] 策略证明以下结论。如想进一步练习,请使用反演定理证明之。 *) + 利用 [inversion] 策略证明以下结论。如想进一步练习,请使用反演定理证明之。 *) Theorem SSSSev__even : forall n, - ev (S (S (S (S n)))) -> ev n. + even (S (S (S (S n)))) -> even n. Proof. (* 请在此处解答 *) Admitted. - (** [] *) -(** **** 练习:1 星 (even5_nonsense) *) -(** 请使用 [inversion] 策略证明以下结果。 *) +(** **** 练习:1 星, standard (even5_nonsense) + + 请使用 [inversion] 策略证明以下结果。 *) Theorem even5_nonsense : - ev 5 -> 2 + 2 = 9. + even 5 -> 2 + 2 = 9. Proof. (* 请在此处解答 *) Admitted. (** [] *) - -(** The [inversion] tactic is complex. When applied to equalities, as a - special case, it does the work of both [discriminate] and - [injection]. In addition, it carries out the [intros] and - [rewrite]s that are typically necessary in the case of - [injection]. It can also be applied, more generally, - to analyzing evidence for inductively defined propositions. - As examples, we'll use it to reprove some theorems from [Tactics.v]. *) - +(** The [inversion] tactic does quite a bit of work. When + applied to equalities, as a special case, it does the work of both + [discriminate] and [injection]. In addition, it carries out the + [intros] and [rewrite]s that are typically necessary in the case + of [injection]. It can also be applied, more generally, to analyze + evidence for inductively defined propositions. As examples, we'll + use it to reprove some theorems from [Tactics.v]. *) Theorem inversion_ex1 : forall (n m o : nat), [n; m] = [o; o] -> @@ -275,11 +291,10 @@ Theorem inversion_ex2 : forall (n : nat), Proof. intros n contra. inversion contra. Qed. - -(** [inversion] 的工作原理大致如下:假设 [I] 指代上下文中的假设 [P], - 且 [P] 由 [Inductive] 归纳定义,则对于 [P] 每一种可能的构造,[inversion I] +(** [inversion] 的工作原理大致如下:假设 [H] 指代上下文中的假设 [P], + 且 [P] 由 [Inductive] 归纳定义,则对于 [P] 每一种可能的构造,[inversion H] 各为其生成子目标。子目标中自相矛盾者被忽略,证明其余子命题即可得证原命题。 - 在证明子目标时,上下文中的 [I] 会替换为 [P] 的构造条件, + 在证明子目标时,上下文中的 [H] 会替换为 [P] 的构造条件, 即其构造子所需参数以及必要的等式关系。例如:倘若 [ev n] 由 [evSS] 构造, 上下文中会引入参数 [n']、[ev n'],以及等式 [S (S n') = n]。 *) @@ -289,13 +304,13 @@ Proof. 为了展示这三种方式的一致性,我们需要下面的引理: *) Lemma ev_even_firsttry : forall n, - ev n -> exists k, n = double k. + even n -> exists k, n = double k. Proof. (* 课上已完成 *) (** 我们可以尝试使用分类讨论或对 [n] 进行归纳。 - 但由于 [ev] 在前提中出现,如同之前章节的一些例子,这种策略或许无法行得通。 - 如此我们似乎可以首先尝试对 [ev] 的证据进行反演。 + 但由于 [even] 在前提中出现,如同之前章节的一些例子,这种策略或许无法行得通。 + 如此我们似乎可以首先尝试对 [even] 的证据进行反演。 确实,第一个分类可以被平凡地证明。 *) intros n E. inversion E as [| n' E']. @@ -304,18 +319,16 @@ Proof. - (* E = ev_SS n' E' *) simpl. (** 不幸地是,第二个分类要困难一些。我们需要证明 [exists k, S (S n') = double k], - 但唯一可用的假设是 [E'],也即 [ev n'] 成立。但这对证明并没有帮助, + 但唯一可用的假设是 [E'],也即 [even n'] 成立。但这对证明并没有帮助, 我们似乎被卡住了,而对 [E] 进行分类讨论是徒劳的。 如果仔细观察第二个(子)目标,我们可以发现一些有意思的事情: 对 [E] 进行分类讨论,我们可以把要证明的原始目标归约到另一个上, - 其涉及到另一个 [ev] 的证据: [E']。 + 其涉及到另一个 [even] 的证据: [E']。 形式化地说,我们可以通过展示如下证据来完成证明: - exists k', n' = double k', - 这同原始的命题是等价的,只是 [n'] 被替换为 n。确实,通过这个中间结果完成证明 并不困难。 *) @@ -335,20 +348,20 @@ Abort. 对证据和对数据使用 [induction] 具有同样的行为:它导致 Coq 对每个可用于构造证据的 构造子生成一个子目标,同时对递归出现的问题性质提供了归纳假设。 - To prove a property of [n] holds for all number for which [ev n] - holds, we can use induction on [ev n]. This requires us to prove - two things, corresponding to the two cases of how [ev n] could - have been constructed. If it was constructed by [ev_0], then [n=0], - and the property must hold of [0]. If it was constructed by [ev_SS], - then the evidence of [ev n] is of the form [ev_SS n' E'], where - [n = S (S n')] and [E'] is evidence for [ev n']. In this case, - the inductive hypothesis says that the property we are trying to prove - holds for [n']. *) + To prove a property of [n] holds for all numbers for which [even + n] holds, we can use induction on [even n]. This requires us to + prove two things, corresponding to the two ways in which [even n] + could have been constructed. If it was constructed by [ev_0], then + [n=0], and the property must hold of [0]. If it was constructed by + [ev_SS], then the evidence of [even n] is of the form [ev_SS n' + E'], where [n = S (S n')] and [E'] is evidence for [even n']. In + this case, the inductive hypothesis says that the property we are + trying to prove holds for [n']. *) (** 让我们再次尝试证明这个引理: *) Lemma ev_even : forall n, - ev n -> exists k, n = double k. + even n -> exists k, n = double k. Proof. intros n E. induction E as [|n' E' IH]. @@ -361,13 +374,13 @@ Proof. Qed. (** 这里我们看到 Coq 对 [E'] 产生了 [IH],而 [E'] 是唯一递归出现的 - [ev] 命题。 由于 [E'] 中涉及到 [n'],这个归纳假设是关于 [n'] 的, + [even] 命题。 由于 [E'] 中涉及到 [n'],这个归纳假设是关于 [n'] 的, 而非关于 [n] 或其他数字的。 *) (** 关于偶数性质的第二个和第三个定义的等价关系如下: *) Theorem ev_even_iff : forall n, - ev n <-> exists k, n = double k. + even n <-> exists k, n = double k. Proof. intros n. split. - (* -> *) apply ev_even. @@ -379,41 +392,45 @@ Qed. (** 下面的练习提供了一些简单的例子,来帮助你熟悉这项技术。 *) -(** **** 练习:2 星 (ev_sum) *) -Theorem ev_sum : forall n m, ev n -> ev m -> ev (n + m). +(** **** 练习:2 星, standard (ev_sum) *) +Theorem ev_sum : forall n m, even n -> even m -> even (n + m). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced, optional (ev'_ev) *) -(** 一般来说,有很多种方式来归纳地定义一个性质。比如说,下面是关于 [ev] 的另一种(蹩脚的)定义:*) +(** **** 练习:4 星, advanced, optional (even'_ev) + + 一般来说,有很多种方式来归纳地定义一个性质。比如说,下面是关于 + [even] 的另一种(蹩脚的)定义:*) -Inductive ev' : nat -> Prop := -| ev'_0 : ev' 0 -| ev'_2 : ev' 2 -| ev'_sum n m (Hn : ev' n) (Hm : ev' m) : ev' (n + m). +Inductive even' : nat -> Prop := +| even'_0 : even' 0 +| even'_2 : even' 2 +| even'_sum n m (Hn : even' n) (Hm : even' m) : even' (n + m). (** 请证明这个定义在逻辑上等同于前述定义。(当进入到归纳步骤时,你可能会想参考一下上一个定理。)*) -Theorem ev'_ev : forall n, ev' n <-> ev n. +Theorem even'_ev : forall n, even' n <-> even n. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, advanced, recommended (ev_ev__ev) *) -(** 在本题中找到适合进行归纳的项需要一点技巧: *) +(** **** 练习:3 星, advanced, recommended (ev_ev__ev) + + 在本题中找到适合进行归纳的项需要一点技巧: *) Theorem ev_ev__ev : forall n m, - ev (n+m) -> ev n -> ev m. + even (n+m) -> even n -> even m. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (ev_plus_plus) *) -(** 这个练习仅仅需要使用前述引理,而不需要使用归纳或分类讨论,尽管一些重写可能会比较乏味。 *) +(** **** 练习:3 星, standard, optional (ev_plus_plus) + + 这个练习仅仅需要使用前述引理,而不需要使用归纳或分类讨论,尽管一些重写可能会比较乏味。 *) Theorem ev_plus_plus : forall n m p, - ev (n+m) -> ev (n+p) -> ev (m+p). + even (n+m) -> even (n+p) -> even (m+p). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -421,7 +438,7 @@ Proof. (* ################################################################# *) (** * 归纳关系 *) -(** 我们可以认为被一个数所参数化的命题(比如 [ev])是一个_'性质'_,也即, +(** 我们可以认为被一个数所参数化的命题(比如 [even])是一个_'性质'_,也即, 它定义了 [nat] 的一个子集,其中的数可以被证明满足此命题。 以同样的方式,我们可认为有两个参数的命题是一个_'关系'_,也即,它定义了一个 可满足此命题的序对集合。*) @@ -439,7 +456,7 @@ Inductive le : nat -> nat -> Prop := Notation "m <= n" := (le m n). -(** 类似于证明 [ev] 这样的性质,使用 [le_n] 和 [le_S] 构造子来证明关于 [<=] +(** 类似于证明 [even] 这样的性质,使用 [le_n] 和 [le_S] 构造子来证明关于 [<=] 的事实遵循了同样的模式。我们可以对构造子使用 [apply] 策略来证明 [<=] 目标 (比如证明 [3<=3] 或 [3<=6]),也可以使用 [inversion] 策略来从上下文中 [<=] 的假设里抽取信息(比如证明 [(2<=1) -> 2+2=5])。 *) @@ -483,20 +500,24 @@ Inductive next_nat : nat -> nat -> Prop := | nn n : next_nat n (S n). Inductive next_even : nat -> nat -> Prop := - | ne_1 n : ev (S n) -> next_even n (S n) - | ne_2 n (H : ev (S (S n))) : next_even n (S (S n)). + | ne_1 n : even (S n) -> next_even n (S n) + | ne_2 n (H : even (S (S n))) : next_even n (S (S n)). -(** **** 练习:2 星, optional (total_relation) *) -(** 请定一个二元归纳关系 [total_relation] 对每一个自然数的序对成立。 *) +(** **** 练习:2 星, standard, optional (total_relation) -(* 请在此处解答 *) -(** [] *) + 请定一个二元归纳关系 [total_relation] 对每一个自然数的序对成立。 *) -(** **** 练习:2 星, optional (empty_relation) *) -(** 请定一个二元归纳关系 [empty_relation] 对自然数永远为假。 *) +(* 请在此处解答 -(* 请在此处解答 *) -(** [] *) + [] *) + +(** **** 练习:2 星, standard, optional (empty_relation) + + 请定一个二元归纳关系 [empty_relation] 对自然数永远为假。 *) + +(* 请在此处解答 + + [] *) (** From the definition of [le], we can sketch the behaviors of [destruct], [inversion], and [induction] on a hypothesis [H] @@ -506,12 +527,13 @@ Inductive next_even : nat -> nat -> Prop := In the second case, [e2 = S n'] for some [n'] for which [le e1 n'] holds, and it will replace instances of [e2] with [S n']. Doing [inversion H] will remove impossible cases and add generated - equalities to the context for further use. Doing [induction H] will, - in the second case, add the inductive hypothesis that the goal holds - when [e2] is replaced with [n'].*) + equalities to the context for further use. Doing [induction H] + will, in the second case, add the induction hypothesis that the + goal holds when [e2] is replaced with [n']. *) + +(** **** 练习:3 星, standard, optional (le_exercises) -(** **** 练习:3 星, optional (le_exercises) *) -(** 这里展示一些 [<=] 和 [<] 关系的事实,我们在接下来的课程中将会用到他们。 + 这里展示一些 [<=] 和 [<] 关系的事实,我们在接下来的课程中将会用到他们。 证明他们将会是非常有益的练习。 *) Lemma le_trans : forall m n o, m <= n -> n <= o -> m <= o. @@ -572,7 +594,7 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (leb_iff) *) +(** **** 练习:2 星, standard, optional (leb_iff) *) Theorem leb_iff : forall n m, n <=? m = true <-> n <= m. Proof. @@ -581,8 +603,9 @@ Proof. Module R. -(** **** 练习:3 星, recommended (R_provability) *) -(** 通过同样的方式,我们可以定义三元关系、四元关系等。例如,考虑以下定义在自然数上的三元关系: *) +(** **** 练习:3 星, standard, recommended (R_provability) + + 通过同样的方式,我们可以定义三元关系、四元关系等。例如,考虑以下定义在自然数上的三元关系: *) Inductive R : nat -> nat -> nat -> Prop := | c1 : R 0 0 0 @@ -608,8 +631,9 @@ Inductive R : nat -> nat -> nat -> Prop := Definition manual_grade_for_R_provability : option (nat*string) := None. (** [] *) -(** **** 练习:3 星, optional (R_fact) *) -(** 关系 [R] 其实编码了一个熟悉的函数。请找出这个函数,定义它并在 Coq 中证明他们等价。*) +(** **** 练习:3 星, standard, optional (R_fact) + + 关系 [R] 其实编码了一个熟悉的函数。请找出这个函数,定义它并在 Coq 中证明他们等价。*) Definition fR : nat -> nat -> nat (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. @@ -621,8 +645,9 @@ Proof. End R. -(** **** 练习:4 星, advanced (subsequence) *) -(** 如果一个列表的所有元素以相同的顺序出现在另一个列表之中(但允许其中出现其他额外的元素), +(** **** 练习:2 星, advanced (subsequence) + + 如果一个列表的所有元素以相同的顺序出现在另一个列表之中(但允许其中出现其他额外的元素), 我们把第一个列表称作第二个列表的_'子序列'_。 例如: [1;2;3] @@ -652,14 +677,31 @@ End R. 的子序列,且 [l2] 是 [l3] 的子序列,那么 [l1] 是 [l3] 的子序列。 (提示:仔细选择进行归纳的项!) *) +Inductive subseq : list nat -> list nat -> Prop := (* 请在此处解答 *) +. -(* 请勿修改下面这一行: *) -Definition manual_grade_for_subsequence : option (nat*string) := None. +Theorem subseq_refl : forall (l : list nat), subseq l l. +Proof. + (* 请在此处解答 *) Admitted. + +Theorem subseq_app : forall (l1 l2 l3 : list nat), + subseq l1 l2 -> + subseq l1 (l2 ++ l3). +Proof. + (* 请在此处解答 *) Admitted. + +Theorem subseq_trans : forall (l1 l2 l3 : list nat), + subseq l1 l2 -> + subseq l2 l3 -> + subseq l1 l3. +Proof. + (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (R_provability2) *) -(** 假设我们在 Coq 中有如下定义: +(** **** 练习:2 星, standard, optional (R_provability2) + + 假设我们在 Coq 中有如下定义: Inductive R : nat -> list nat -> Prop := | c1 : R 0 [] @@ -672,19 +714,19 @@ Definition manual_grade_for_subsequence : option (nat*string) := None. - [R 1 [1;2;1;0]] - [R 6 [3;2;1;0]] *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + [] *) (* ################################################################# *) (** * 案例学习:正则表达式 *) -(** 性质 [ev] 提供了一个简单的例子来展示归纳定义和其基础的推理技巧, - 但这还不是什么激动人心的东西——毕竟,[ev] 等价于我们之前见过的两个非归纳的定义, +(** 性质 [even] 提供了一个简单的例子来展示归纳定义和其基础的推理技巧, + 但这还不是什么激动人心的东西——毕竟,[even] 等价于我们之前见过的两个非归纳的定义, 而看起来归纳定义并没有提供什么好处。为了更好地展示归纳定义的表达能力, 我们继续使用它来建模计算机科学中的一个经典概念——正则表达式。 *) -(** 正则表达式是用来描述字符串的一种简单语言,定义如下: *) +(** 正则表达式是用来描述字符串集合的一种简单语言,定义如下: *) Inductive reg_exp {T : Type} : Type := | EmptySet @@ -845,8 +887,9 @@ Qed. (** (请注意对 [app_nil_r] 的使用改变了目标,以此可匹配 [MStarApp] 所需要的形式。)*) -(** **** 练习:3 星 (exp_match_ex1) *) -(** 下面的引理显示从形式化的归纳定义中可以得到本章开始的非形式化匹配规则。 *) +(** **** 练习:3 星, standard (exp_match_ex1) + + 下面的引理显示从形式化的归纳定义中可以得到本章开始的非形式化匹配规则。 *) Lemma empty_is_empty : forall T (s : list T), ~ (s =~ EmptySet). @@ -870,9 +913,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, optional (reg_exp_of_list_spec) *) -(** 请证明 [reg_exp_of_list] 满足以下规范: *) +(** **** 练习:4 星, standard, optional (reg_exp_of_list_spec) + 请证明 [reg_exp_of_list] 满足以下规范: *) Lemma reg_exp_of_list_spec : forall T (s1 s2 : list T), s1 =~ reg_exp_of_list s2 <-> s1 = s2. @@ -883,7 +926,6 @@ Proof. (** 由于 [exp_match] 以递归方式定义,我们可能会发现 关于正则表达式的证明常常需要对证据进行归纳。*) - (** 比如,假设我们想要证明以下显然的结果:如果正则表达式 [re] 匹配某个字符串 [s], 那么 [s] 中的所有元素必在 [re] 中某处以字符字面量的形式出现。 @@ -949,8 +991,9 @@ Proof. apply (IH2 Hin). Qed. -(** **** 练习:4 星 (re_not_empty) *) -(** 请编写一个递归函数 [re_not_empty] 用来测试某个正则表达式是否会匹配一些字符串。 +(** **** 练习:4 星, standard (re_not_empty) + + 请编写一个递归函数 [re_not_empty] 用来测试某个正则表达式是否会匹配一些字符串。 并证明你的函数是正确的。*) Fixpoint re_not_empty {T : Type} (re : @reg_exp T) : bool @@ -965,9 +1008,9 @@ Proof. (* ================================================================= *) (** ** [remember] 策略 *) -(** [induction] 策略让人困惑的一个特点是它会欣然接受任意一个项并尝试归纳, - 即使这个项不够一般(general)。其副作用是会丢失掉一些信息(类似 [destruct]), - 并且使你无法完成证明。比如: *) +(** [induction] 策略让人困惑的一个特点是它会接受任意一个项并尝试归纳, + 即使这个项不够一般(general)。其副作用是会丢失掉一些信息(类似没有 [eqn:] + 从句的 [destruct]),并且使你无法完成证明。比如: *) Lemma star_app: forall T (s1 s2 : list T) (re : @reg_exp T), s1 =~ Star re -> @@ -1005,9 +1048,11 @@ Abort. (** 问题是,只有当 [Prop] 的假设是完全一般的时候,对其使用 [induction] 的才会起作用, 也即,我们需要其所有的参数都是变量,而非更复杂的表达式,比如 [Star re]。 - (由此,对证据使用 [induction] 的行为更像是 [destruct] 而非 [inversion]。) + (由此,对证据使用 [induction] 的行为更像是没有 [eqn:] 的 [destruct] + 而非 [inversion]。) - 通过显式地添加一个等式来一般化这个有问题的表达式,我们便可以解决这个问题: *) + 解决此问题的一种直接的方式是“手动推广”这个有问题的表达式, + 即为此引理添加一个显式的等式: *) Lemma star_app: forall T (s1 s2 : list T) (re re' : reg_exp), re' = Star re -> @@ -1023,7 +1068,7 @@ Lemma star_app: forall T (s1 s2 : list T) (re re' : reg_exp), Abort. -(** 在 Coq 中使用 [remember e as x] 策略会(1)替换所有表达式 [e] 为变量 [x], +(** 在 Coq 中调用 [remember e as x] 策略会(1)替换所有表达式 [e] 为变量 [x], (2)在当前上下文中添加一个等式 [x = e]。我们可以这样使用 [remember] 来证明上面的结果: *) @@ -1068,9 +1113,9 @@ Proof. * apply H1. Qed. -(** **** 练习:4 星, optional (exp_match_ex2) *) +(** **** 练习:4 星, standard, optional (exp_match_ex2) *) -(** 下面的引理 [MStar''](以及它的逆,之前的练习题中的 [MStar'])显示 +(** 下面的引理 [MStar''](以及它的逆,之前的练习题中的 [MStar'])显示 [exp_match] 中 [Star] 的定义等价于前面给出的非形式化定义。*) Lemma MStar'' : forall T (s : list T) (re : reg_exp), @@ -1082,8 +1127,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:5 星, advanced (pumping) *) -(** 正则表达式中一个非常有趣的定理叫做_'泵引理(Pumping Lemma)'_, +(** **** 练习:5 星, advanced (pumping) + + 正则表达式中一个非常有趣的定理叫做_'泵引理(Pumping Lemma)'_, 非形式化地来讲,它陈述了任意某个足够长的字符串 [s] 若匹配一个正则表达式 [re], 则可以被抽取(pumped)——将 [s] 的某个中间部分重复任意次产生的新字符串 仍然匹配 [re]。 @@ -1184,7 +1230,7 @@ Qed. (** 为了简化这样的证明,我们可定义一个归纳命题,用于对 [n =? m] 产生更好的分类讨论原理。 - 它不会生成类似 [n =? m = true] 这样的等式,因为一般来说对证明并不直接有用, + 它不会生成类似 [(n =? m) = true]这样的等式,因为一般来说对证明并不直接有用, 其生成的分类讨论原理正是我们所需要的假设: [n = m]。*) Inductive reflect (P : Prop) : bool -> Prop := @@ -1194,12 +1240,13 @@ Inductive reflect (P : Prop) : bool -> Prop := (** 性质 [reflect] 接受两个参数:一个命题 [P] 和一个布尔值 [b]。 直观地讲,它陈述了性质 [P] 在布尔值 [b] 中所_'映现'_(也即,等价): 换句话说,[P] 成立当且仅当 [b = true]。为了理解这一点,请注意定义, - 我们能够产生 [reflect P true] 的证据的唯一方式是证明 [P] 为真且使用 + 我们能够产生 [reflect P true] 的证据的唯一方式是证明 [P] 为真并使用 [ReflectT] 构造子。如果我们反转这个陈述,意味着从 [reflect P true] - 的证明中抽取出 [P] 的证据也是可能的。相反地,展示 [reflect P false] + 的证明中抽取出 [P] 的证据也是可能的。与此类似,证明 [reflect P false] 的唯一方式是合并 [~ P] 的证据和 [ReflectF] 构造子。 - 形式化这种直觉并证明两个表述确实等价是十分容易的:*) + 形式化这种直觉并证明 [P <-> b = true] 和 [reflect P b] + 这两个表述确实等价是十分容易的。首先是从左到右的蕴含:*) Theorem iff_reflect : forall P b, (P <-> b = true) -> reflect P b. Proof. @@ -1209,7 +1256,9 @@ Proof. - apply ReflectF. rewrite H. intros H'. discriminate. Qed. -(** **** 练习:2 星, recommended (reflect_iff) *) +(** Now you prove the right-to-left implication: *) + +(** **** 练习:2 星, standard, recommended (reflect_iff) *) Theorem reflect_iff : forall P b, reflect P b -> (P <-> b = true). Proof. (* 请在此处解答 *) Admitted. @@ -1220,13 +1269,12 @@ Proof. 进行分类讨论,同时为两个分支(第一个子目标中的 [P] 和第二个中的 [~ P])生成适当的假设。 *) - Lemma eqbP : forall n m, reflect (n = m) (n =? m). Proof. intros n m. apply iff_reflect. rewrite eqb_eq. reflexivity. Qed. -(** [filter_not_empty_In] 的新证明如下所示。请注意对 [destruct] 和 [apply] +(** [filter_not_empty_In] 的一种更流畅证明如下所示。请注意对 [destruct] 和 [apply] 的使用是如何合并成一个 [destruct] 的使用。 *) (** (为了更清晰地看到这点,使用 Coq 查看 [filter_not_empty_In] @@ -1247,8 +1295,9 @@ Proof. intros H'. right. apply IHl'. apply H'. Qed. -(** **** 练习:3 星, recommended (eqbP_practice) *) -(** 使用上面的 [eqbP] 证明以下定理:*) +(** **** 练习:3 星, standard, recommended (eqbP_practice) + + 使用上面的 [eqbP] 证明以下定理:*) Fixpoint count n l := match l with @@ -1262,11 +1311,11 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** 在这个小例子中,这种技术仅仅在证明时提升了一点方便;然而,当证明变得庞大时, +(** 这个小例子展示了互映证明可以怎样为我们提供一些便利。在大型的开发中, 使用 [reflect] 往往更容易写出清晰和简短的证明脚本。我们将会在后面的章节 和_'编程语言基础'_一卷中看到更多的例子。 - 对 [reflect] 性质的使用是随着 _'SSReflect'_ 而流行开来的,这是一个 + 对 [reflect] 性质的使用已被 _'SSReflect'_ 推广开来,这是一个 Coq 程序库,用于形式化一些数学上的重要结果,包括四色定理和法伊特-汤普森定理。 SSReflect 的名字代表着 _'small-scale reflection'_,也即,普遍性地使用 互映来简化与布尔值计算有关的证明。*) @@ -1274,8 +1323,9 @@ Proof. (* ################################################################# *) (** * 额外练习 *) -(** **** 练习:3 星, recommended (nostutter_defn) *) -(** 写出性质的归纳定义是本课程中你需要的重要技能。请尝试去独立解决以下的练习。 +(** **** 练习:3 星, standard, recommended (nostutter_defn) + + 写出性质的归纳定义是本课程中你需要的重要技能。请尝试去独立解决以下的练习。 列表连续地重复某元素称为 "百叶窗式" (stutter)。 (此概念不同于不包含重复元素:[1;4;1] 虽然包含重复元素 [1], @@ -1325,8 +1375,9 @@ Example test_nostutter_4: not (nostutter [3;1;1;4]). Definition manual_grade_for_nostutter : option (nat*string) := None. (** [] *) -(** **** 练习:4 星, advanced (filter_challenge) *) -(** 让我们证明在 [Poly] 一章中 [filter] 的定义匹配某个抽象的规范。 +(** **** 练习:4 星, advanced (filter_challenge) + + 让我们证明在 [Poly] 一章中 [filter] 的定义匹配某个抽象的规范。 可以这样非形式化地描述这个规范: 列表 [l] 是一个 [l1] 和 [l2] 的“顺序合并”(in-order merge),如果它以 @@ -1357,15 +1408,18 @@ Definition manual_grade_for_nostutter : option (nat*string) := None. Definition manual_grade_for_filter_challenge : option (nat*string) := None. (** [] *) -(** **** 练习:5 星, advanced, optional (filter_challenge_2) *) -(** 另一种刻画 [filter] 行为的方式是:在 [l] 的所有其元素满足 [test] 的子序列中, +(** **** 练习:5 星, advanced, optional (filter_challenge_2) + + 另一种刻画 [filter] 行为的方式是:在 [l] 的所有其元素满足 [test] 的子序列中, [filter test l] 是最长的那个。请形式化这个命题并证明它。*) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 -(** **** 练习:4 星, optional (palindromes) *) -(** 回文是倒序排列与正序排列相同的序列。 + [] *) + +(** **** 练习:4 星, standard, optional (palindromes) + + 回文是倒序排列与正序排列相同的序列。 - 在 [listX] 上定义一个归纳命题 [pal] 来表达回文的含义。 (提示:你需要三个分类。定义应当基于列表的结构;仅仅使用一个构造子,例如 @@ -1389,17 +1443,20 @@ Definition manual_grade_for_filter_challenge : option (nat*string) := None. Definition manual_grade_for_pal_pal_app_rev_pal_rev : option (nat*string) := None. (** [] *) -(** **** 练习:5 星, optional (palindrome_converse) *) -(** 由于缺乏证据,反方向的证明要困难许多。使用之前练习中定义的 [pal] 来证明 +(** **** 练习:5 星, standard, optional (palindrome_converse) + + 由于缺乏证据,反方向的证明要困难许多。使用之前练习中定义的 [pal] 来证明 forall l, l = rev l -> pal l. *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) -(** **** 练习:4 星, advanced, optional (NoDup) *) -(** 请回忆一下 [Logic] 章节中性质 [In] 的定义,其断言值 [x] 在列表 [l] 中至少出现一次:*) +(** **** 练习:4 星, advanced, optional (NoDup) + + 请回忆一下 [Logic] 章节中性质 [In] 的定义,其断言值 [x] 在列表 [l] 中至少出现一次:*) (* Fixpoint In (A : Type) (x : A) (l : list A) : Prop := match l with @@ -1427,8 +1484,9 @@ Definition manual_grade_for_pal_pal_app_rev_pal_rev : option (nat*string) := Non Definition manual_grade_for_NoDup_disjoint_etc : option (nat*string) := None. (** [] *) -(** **** 练习:4 星, advanced, optional (pigeonhole_principle) *) -(** _鸽笼原理(Pigeonhole Principle)'_是一个关于计数的基本事实: +(** **** 练习:4 星, advanced, optional (pigeonhole_principle) + + _鸽笼原理(Pigeonhole Principle)'_是一个关于计数的基本事实: 将超过 [n] 个物体放进 [n] 个鸽笼,则必有鸽笼包含至少两个物体。 与此前诸多情形相似,这一数学事实看似乏味,但其证明手段并不平凡, 如下所述: *) @@ -1470,9 +1528,8 @@ Proof. Definition manual_grade_for_check_repeats : option (nat*string) := None. (** [] *) - (* ================================================================= *) -(** ** 扩展练习:验证正则表达式匹配器 *) +(** ** 扩展练习:经验证的正则表达式匹配器 *) (** 我们现在已经定义了正则表达式的匹配关系和多态列表。我们可以使用这些定义来手动地证明 给定的正则表达式是否匹配某个字符串,但这并不是一个可以自动地判断是否匹配的程序。 @@ -1503,7 +1560,6 @@ Definition string := list ascii. [match] 关系并不依赖匹配函数。我们将会首先证明后一类性质。他们中的多数 将会是很直接的证明,已经被直接给出;少部分关键的引理会留给你来证明。 *) - (** 每个可被证明的 [Prop] 等价于 [True]。 *) Lemma provable_equiv_true : forall (P : Prop), P -> (P <-> True). Proof. @@ -1582,8 +1638,9 @@ Proof. rewrite Happ. apply (MApp s0 _ s1 _ Hmat0 Hmat1). Qed. -(** **** 练习:3 星, optional (app_ne) *) -(** [App re0 re1] 匹配 [a::s] 当且仅当 [re0] 匹配空字符串 +(** **** 练习:3 星, standard, optional (app_ne) + + [App re0 re1] 匹配 [a::s] 当且仅当 [re0] 匹配空字符串 且 [a::s] 匹配 [re1] 或 [s=s0++s1],其中 [a::s0] 匹配 [re0] 且 [s1] 匹配 [re1]。 @@ -1610,8 +1667,9 @@ Proof. + apply MUnionR. apply H. Qed. -(** **** 练习:3 星, optional (star_ne) *) -(** [a::s] 匹配 [Star re] 当且仅当 [s = s0 ++ s1],其中 [a::s0] 匹配 +(** **** 练习:3 星, standard, optional (star_ne) + + [a::s] 匹配 [Star re] 当且仅当 [s = s0 ++ s1],其中 [a::s0] 匹配 [re] 且 [s1] 匹配 [Star re]。 同 [app_ne]一样,这个观察很重要, 因此理解,证明并留意它。 @@ -1634,14 +1692,16 @@ Proof. Definition refl_matches_eps m := forall re : @reg_exp ascii, reflect ([ ] =~ re) (m re). -(** **** 练习:2 星, optional (match_eps) *) -(** 完成 [match_eps] 的定义,其测试给定的正则表达式是否匹配空字符串: *) +(** **** 练习:2 星, standard, optional (match_eps) + + 完成 [match_eps] 的定义,其测试给定的正则表达式是否匹配空字符串: *) Fixpoint match_eps (re: @reg_exp ascii) : bool (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. (** [] *) -(** **** 练习:3 星, optional (match_eps_refl) *) -(** 现在,请证明 [match_eps] 确实测试了给定的正则表达式是否匹配空字符串。 +(** **** 练习:3 星, standard, optional (match_eps_refl) + + 现在,请证明 [match_eps] 确实测试了给定的正则表达式是否匹配空字符串。 (提示:你会使用到互映引理 [ReflectT] 和 [ReflectF]。) *) Lemma match_eps_refl : refl_matches_eps match_eps. Proof. @@ -1651,7 +1711,6 @@ Proof. (** 我们将会定义其他函数也使用到 [match_eps]。然而,这些函数的证明中你唯一会用到的 [match_eps] 的性质是 [match_eps_refl]。*) - (** 我们匹配器所进行的关键操作是迭代地构造一个正则表达式生成式的序列。 对于字符 [a] 和正则表达式 [re],[re] 在 [a] 上的生成式是一个正则表达式, 其匹配所有匹配 [re] 且以 [a] 开始的字符串的后缀。也即,[re'] @@ -1664,8 +1723,9 @@ Definition is_der re (a : ascii) re' := 它求值为 [re] 在 [a] 上的生成式。也即,[d] 满足以下关系: *) Definition derives d := forall a re, is_der re a (d a re). -(** **** 练习:3 星, optional (derive) *) -(** 请定义 [derive] 使其生成字符串。一个自然的实现是在某些分类使用 +(** **** 练习:3 星, standard, optional (derive) + + 请定义 [derive] 使其生成字符串。一个自然的实现是在某些分类使用 [match_eps] 来判断正则表达式是否匹配空字符串。 *) Fixpoint derive (a : ascii) (re : @reg_exp ascii) : @reg_exp ascii (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. @@ -1719,8 +1779,9 @@ Example test_der7 : Proof. (* 请在此处解答 *) Admitted. -(** **** 练习:4 星, optional (derive_corr) *) -(** 请证明 [derive] 确实总是会生成字符串。 +(** **** 练习:4 星, standard, optional (derive_corr) + + 请证明 [derive] 确实总是会生成字符串。 提示:一种证明方法是对 [re] 归纳,尽管你需要通过归纳和一般化合适的项来 仔细选择要证明的性质。 @@ -1742,20 +1803,21 @@ Proof. (** 我们将会使用 [derive] 来定义正则表达式匹配器。然而,在匹配器的性质的证明中你唯一会用到 的 [derive] 的性质是 [derive_corr]。 *) - (** 函数 [m] 匹配正则表达式如果对给定的字符串 [s] 和正则表达式 [re], 它求值的结果映射了 [s] 是否被 [re] 匹配。也即,[m] 满足以下性质:*) Definition matches_regex m : Prop := forall (s : string) re, reflect (s =~ re) (m s re). -(** **** 练习:2 星, optional (regex_match) *) -(** 完成 [regex_match] 的定义,使其可以匹配正则表达式。*) +(** **** 练习:2 星, standard, optional (regex_match) + + 完成 [regex_match] 的定义,使其可以匹配正则表达式。*) Fixpoint regex_match (s : string) (re : @reg_exp ascii) : bool (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. (** [] *) -(** **** 练习:3 星, optional (regex_refl) *) -(** 最后,证明 [regex_match] 确实可以匹配正则表达式。 +(** **** 练习:3 星, standard, optional (regex_refl) + + 最后,证明 [regex_match] 确实可以匹配正则表达式。 提示:如果你定义的 [regex_match] 对正则表达式 [re] 使用了 [match_eps], 那么可对 [re] 应用 [match_eps_refl],接着对结果解构并生成 @@ -1769,4 +1831,4 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) - +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/IndPropTest.v b/lf-current/IndPropTest.v index b071118c..ccc9cae1 100644 --- a/lf-current/IndPropTest.v +++ b/lf-current/IndPropTest.v @@ -37,7 +37,7 @@ idtac " ". idtac "#> ev_double". idtac "Possible points: 1". -check_type @ev_double ((forall n : nat, ev (double n))). +check_type @ev_double ((forall n : nat, even (double n))). idtac "Assumptions:". Abort. Print Assumptions ev_double. @@ -49,7 +49,7 @@ idtac " ". idtac "#> SSSSev__even". idtac "Possible points: 1". -check_type @SSSSev__even ((forall n : nat, ev (S (S (S (S n)))) -> ev n)). +check_type @SSSSev__even ((forall n : nat, even (S (S (S (S n)))) -> even n)). idtac "Assumptions:". Abort. Print Assumptions SSSSev__even. @@ -61,7 +61,7 @@ idtac " ". idtac "#> even5_nonsense". idtac "Possible points: 1". -check_type @even5_nonsense ((ev 5 -> 2 + 2 = 9)). +check_type @even5_nonsense ((even 5 -> 2 + 2 = 9)). idtac "Assumptions:". Abort. Print Assumptions even5_nonsense. @@ -73,7 +73,7 @@ idtac " ". idtac "#> ev_sum". idtac "Possible points: 2". -check_type @ev_sum ((forall n m : nat, ev n -> ev m -> ev (n + m))). +check_type @ev_sum ((forall n m : nat, even n -> even m -> even (n + m))). idtac "Assumptions:". Abort. Print Assumptions ev_sum. @@ -86,7 +86,7 @@ idtac " ". idtac "#> ev_ev__ev". idtac "Advanced". idtac "Possible points: 3". -check_type @ev_ev__ev ((forall n m : nat, ev (n + m) -> ev n -> ev m)). +check_type @ev_ev__ev ((forall n m : nat, even (n + m) -> even n -> even m)). idtac "Assumptions:". Abort. Print Assumptions ev_ev__ev. @@ -104,10 +104,25 @@ idtac " ". idtac "------------------- subsequence --------------------". idtac " ". -idtac "#> Manually graded: subsequence". +idtac "#> subseq_refl". idtac "Advanced". -idtac "Possible points: 4". -print_manual_grade manual_grade_for_subsequence. +idtac "Possible points: 1". +check_type @subseq_refl ((forall l : list nat, subseq l l)). +idtac "Assumptions:". +Abort. +Print Assumptions subseq_refl. +Goal True. +idtac " ". + +idtac "#> subseq_app". +idtac "Advanced". +idtac "Possible points: 1". +check_type @subseq_app ( +(forall l1 l2 l3 : list nat, subseq l1 l2 -> subseq l1 (l2 ++ l3))). +idtac "Assumptions:". +Abort. +Print Assumptions subseq_app. +Goal True. idtac " ". idtac "------------------- exp_match_ex1 --------------------". @@ -232,7 +247,7 @@ idtac " ". idtac " ". idtac "Max points - standard: 23". -idtac "Max points - advanced: 39". +idtac "Max points - advanced: 37". idtac "". idtac "********** Summary **********". idtac "". @@ -267,10 +282,14 @@ idtac "". idtac "********** Advanced **********". idtac "---------- ev_ev__ev ---------". Print Assumptions ev_ev__ev. -idtac "---------- subsequence ---------". -idtac "MANUAL". +idtac "---------- subseq_refl ---------". +Print Assumptions subseq_refl. +idtac "---------- subseq_app ---------". +Print Assumptions subseq_app. idtac "---------- Pumping.pumping ---------". Print Assumptions Pumping.pumping. idtac "---------- filter_challenge ---------". idtac "MANUAL". Abort. + +(* Sat Jan 26 15:14:54 UTC 2019 *) diff --git a/lf-current/Induction.html b/lf-current/Induction.html index 5dfbfa49..7ebea673 100644 --- a/lf-current/Induction.html +++ b/lf-current/Induction.html @@ -179,7 +179,7 @@IndProp归纳定义的命题<
☐ +-练习:3 星, optional (regex_refl)
+练习:3 星, standard, optional (regex_refl)
最后,证明 regex_match 确实可以匹配正则表达式。@@ -2729,6 +2787,10 @@IndProp归纳定义的命题<
+ +(* Sat Jan 26 15:14:46 UTC 2019 *)
+Induction归纳证明
-Theorem plus_n_O_firsttry : ∀ n:nat,@@ -210,7 +210,7 @@
+Theorem plus_n_O_firsttry : ∀n:nat,
n = n + 0.
Induction归纳证明
-Theorem plus_n_O_secondtry : ∀ n:nat,
+Theorem plus_n_O_secondtry : ∀n:nat,
n = n + 0.
Proof.
intros n. destruct n as [| n'] eqn:E.
@@ -257,7 +257,7 @@Induction归纳证明
-Theorem plus_n_O : ∀ n:nat, n = n + 0.
+Theorem plus_n_O : ∀n:nat, n = n + 0.
Proof.
intros n. induction n as [| n' IHn'].
- (* n = 0 *) reflexivity.
@@ -285,7 +285,7 @@Induction归纳证明
-Theorem minus_diag : ∀ n,
+Theorem minus_diag : ∀n,
minus n n = 0.
Proof.
(* 课上已完成 *)
@@ -301,24 +301,24 @@Induction归纳证明
策略被应用到包含量化变量的目标中时,它会自动将需要的变量移到上下文中。)-练习:2 星, recommended (basic_induction)
+练习:2 星, standard, recommended (basic_induction)
用归纳法证明以下命题。你可能需要之前的证明结果。-Theorem mult_0_r : ∀ n:nat,
+Theorem mult_0_r : ∀n:nat,
n * 0 = 0.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem plus_n_Sm : ∀ n m : nat,
+Theorem plus_n_Sm : ∀n m : nat,
S (n + m) = n + (S m).
Proof.
(* 请在此处解答 *) Admitted.
-Theorem plus_comm : ∀ n m : nat,
+Theorem plus_comm : ∀n m : nat,
n + m = m + n.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem plus_assoc : ∀ n m p : nat,
+Theorem plus_assoc : ∀n m p : nat,
n + (m + p) = (n + m) + p.
Proof.
(* 请在此处解答 *) Admitted.
@@ -328,7 +328,7 @@Induction归纳证明
@@ -345,7 +345,7 @@Induction归纳证明
-Lemma double_plus : ∀ n, double n = n + n .@@ -354,14 +354,14 @@
+Lemma double_plus : ∀n, double n = n + n .
Proof.
(* 请在此处解答 *) Admitted.
Induction归纳证明
-练习:2 星, optional (evenb_S)
+练习:2 星, standard, optional (evenb_S)
我们的 evenb n 定义对 n - 2 的递归调用不大方便。这让证明 evenb n 时更难对 n 进行归纳,因此我们需要一个关于 n - 2 的归纳假设。 以下引理赋予了 evenb (S n) 另一个特征,使其在归纳时能够更好地工作:-Theorem evenb_S : ∀ n : nat,
+Theorem evenb_S : ∀n : nat,
evenb (S n) = negb (evenb n).
Proof.
(* 请在此处解答 *) Admitted.
@@ -371,7 +371,7 @@Induction归纳证明
-练习:1 星 (destruct_induction)
+练习:1 星, standard (destruct_induction)
请简要说明一下 destruct 策略和 induction 策略之间的区别。@@ -388,7 +388,7 @@Induction归纳证明
☐-Theorem mult_0_plus' : ∀ n m : nat,
+Theorem mult_0_plus' : ∀n m : nat,
(0 + n) * m = n * m.
Proof.
intros n m.
@@ -433,7 +433,7 @@Induction归纳证明
-Theorem plus_rearrange_firsttry : ∀ n m p q : nat,
+Theorem plus_rearrange_firsttry : ∀n m p q : nat,
(n + m) + (p + q) = (m + n) + (p + q).
Proof.
intros n m p q.
@@ -450,7 +450,7 @@Induction归纳证明
-Theorem plus_rearrange : ∀ n m p q : nat,
+Theorem plus_rearrange : ∀n m p q : nat,
(n + m) + (p + q) = (m + n) + (p + q).
Proof.
intros n m p q.
@@ -460,7 +460,7 @@Induction归纳证明
-Theorem plus_assoc' : ∀ n m p : nat,
+Theorem plus_assoc' : ∀n m p : nat,
n + (m + p) = (n + m) + p.
Proof. intros n m p. induction n as [| n' IHn']. reflexivity.
simpl. rewrite → IHn'. reflexivity. Qed.
@@ -520,7 +520,7 @@Induction归纳证明
-Theorem plus_assoc'' : ∀ n m p : nat,diff --git a/lf-current/Induction.v b/lf-current/Induction.v index 49500e7e..350a2c8a 100644 --- a/lf-current/Induction.v +++ b/lf-current/Induction.v @@ -151,7 +151,6 @@ Proof. [(S n') + 0 = S n'];它可被化简为 [S (n' + 0) = S n'],而此结论可通过 [IHn'] 得出。 *) - Theorem minus_diag : forall n, minus n n = 0. Proof. @@ -165,8 +164,9 @@ Proof. (** (其实在这些证明中我们并不需要 [intros]:当 [induction] 策略被应用到包含量化变量的目标中时,它会自动将需要的变量移到上下文中。) *) -(** **** 练习:2 星, recommended (basic_induction) *) -(** 用归纳法证明以下命题。你可能需要之前的证明结果。 *) +(** **** 练习:2 星, standard, recommended (basic_induction) + + 用归纳法证明以下命题。你可能需要之前的证明结果。 *) Theorem mult_0_r : forall n:nat, n * 0 = 0. @@ -189,8 +189,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星 (double_plus) *) -(** 考虑以下函数,它将其参数乘以二: *) +(** **** 练习:2 星, standard (double_plus) + + 考虑以下函数,它将其参数乘以二: *) Fixpoint double (n:nat) := match n with @@ -205,8 +206,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (evenb_S) *) -(** 我们的 [evenb n] 定义对 [n - 2] 的递归调用不大方便。这让证明 [evenb n] +(** **** 练习:2 星, standard, optional (evenb_S) + + 我们的 [evenb n] 定义对 [n - 2] 的递归调用不大方便。这让证明 [evenb n] 时更难对 [n] 进行归纳,因此我们需要一个关于 [n - 2] 的归纳假设。 以下引理赋予了 [evenb (S n)] 另一个特征,使其在归纳时能够更好地工作: *) @@ -216,8 +218,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (destruct_induction) *) -(** 请简要说明一下 [destruct] 策略和 [induction] 策略之间的区别。 +(** **** 练习:1 星, standard (destruct_induction) + + 请简要说明一下 [destruct] 策略和 [induction] 策略之间的区别。 (* 请在此处解答 *) *) @@ -372,8 +375,9 @@ Proof. 但在其它方面则不够明确(特别是 Coq 证明中任何一处的“证明状态”都是完全 隐含的,而非形式化证明则经常反复告诉读者目前证明进行的状态)。 *) -(** **** 练习:2 星, advanced, recommended (plus_comm_informal) *) -(** 将你对 [plus_comm] 的解答翻译成非形式化证明: +(** **** 练习:2 星, advanced, recommended (plus_comm_informal) + + 将你对 [plus_comm] 的解答翻译成非形式化证明: 定理:加法满足交换律。 @@ -384,21 +388,23 @@ Proof. Definition manual_grade_for_plus_comm_informal : option (nat*string) := None. (** [] *) -(** **** 练习:2 星, optional (eqb_refl_informal) *) -(** 以 [plus_assoc] 的非形式化证明为范本,写出以下定理的非形式化证明。 +(** **** 练习:2 星, standard, optional (eqb_refl_informal) + + 以 [plus_assoc] 的非形式化证明为范本,写出以下定理的非形式化证明。 不要只是用中文来解释 Coq 策略! 定理:对于任何 [n],均有 [true = n =? n]。 证明: (* 请在此处解答 *) -*) -(** [] *) + + [] *) (* ################################################################# *) (** * 更多练习 *) -(** **** 练习:3 星, recommended (mult_comm) *) -(** 用 [assert] 来帮助证明此定理。你应该不需要对 [plus_swap] 进行归纳。 *) +(** **** 练习:3 星, standard, recommended (mult_comm) + + 用 [assert] 来帮助证明此定理。你应该不需要对 [plus_swap] 进行归纳。 *) Theorem plus_swap : forall n m p : nat, n + (m + p) = m + (n + p). @@ -414,8 +420,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (more_exercises) *) -(** 找一张纸。对于以下定理,首先请 _'思考'_ (a) 它能否能只用化简和改写来证明, +(** **** 练习:3 星, standard, optional (more_exercises) + + 找一张纸。对于以下定理,首先请 _'思考'_ (a) 它能否能只用化简和改写来证明, (b) 它还需要分类讨论([destruct]),以及 (c) 它还需要归纳证明。先写下你的 预判,然后填写下面的证明(你的纸不用交上来,这只是鼓励你先思考再行动!) *) @@ -470,8 +477,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (eqb_refl) *) -(** 证明以下定理。(把 [true] 放在等式左边可能看起来有点奇怪,不过 Coq 标准库中 +(** **** 练习:2 星, standard, optional (eqb_refl) + + 证明以下定理。(把 [true] 放在等式左边可能看起来有点奇怪,不过 Coq 标准库中 就是这样表示的,我们照做就是。无论按哪个方向改写都一样好用,所以无论我们如何 表示定理,用起来都没问题。) *) @@ -481,8 +489,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (plus_swap') *) -(** [replace] 策略允许你指定一个具体的要改写的子项和你想要将它改写成的项: +(** **** 练习:2 星, standard, optional (plus_swap') + + [replace] 策略允许你指定一个具体的要改写的子项和你想要将它改写成的项: [replace (t) with (u)] 会将目标中表达式 [t](的所有副本)替换为表达式 [u], 并生成 [t = u] 作为附加的子目标。在简单的 [rewrite] 作用在目标错误的部分上时 这种做法通常很有用。 @@ -496,8 +505,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, recommended (binary_commute) *) -(** 回忆一下你在 [Basics] 中为练习 [binary] 编写的 [incr] 和 [bin_to_nat] +(** **** 练习:3 星, standard, recommended (binary_commute) + + 回忆一下你在 [Basics] 中为练习 [binary] 编写的 [incr] 和 [bin_to_nat] 函数。证明下图可交换。 incr @@ -523,8 +533,9 @@ Proof. Definition manual_grade_for_binary_commute : option (nat*string) := None. (** [] *) -(** **** 练习:5 星, advanced (binary_inverse) *) -(** This is a further continuation of the previous exercises about +(** **** 练习:5 星, advanced (binary_inverse) + + This is a further continuation of the previous exercises about binary numbers. You may find you need to go back and change your earlier definitions to get things to work here. @@ -577,7 +588,4 @@ Definition manual_grade_for_binary_inverse_c : option (nat*string) := None. (** [] *) -(* NEW NAME *) -Notation zero_neqb_S := zero_nbeq_S (only parsing). -Notation S_neqb_0 := S_nbeq_0 (only parsing). -Notation plus_leb_compat_l := plus_ble_compat_l (only parsing). +(* Sat Jan 26 15:14:45 UTC 2019 *) diff --git a/lf-current/InductionTest.v b/lf-current/InductionTest.v index 9ccd1d4f..649553c2 100644 --- a/lf-current/InductionTest.v +++ b/lf-current/InductionTest.v @@ -176,3 +176,5 @@ idtac "MANUAL". idtac "---------- binary_inverse_c ---------". idtac "MANUAL". Abort. + +(* Sat Jan 26 15:14:48 UTC 2019 *) diff --git a/lf-current/LICENSE b/lf-current/LICENSE index 15ebac8e..568f5c1d 100644 --- a/lf-current/LICENSE +++ b/lf-current/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018 +Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/lf-current/Lists.html b/lf-current/Lists.html index 58501a5f..abb65d23 100644 --- a/lf-current/Lists.html +++ b/lf-current/Lists.html @@ -39,7 +39,7 @@
+Theorem plus_assoc'' : ∀n m p : nat,
n + (m + p) = (n + m) + p.
Proof.
intros n m p. induction n as [| n' IHn'].
@@ -615,7 +615,7 @@Induction归纳证明
隐含的,而非形式化证明则经常反复告诉读者目前证明进行的状态)。-练习:2 星, advanced, recommended (plus_comm_informal)
+练习:2 星, advanced, recommended (plus_comm_informal)
将你对 plus_comm 的解答翻译成非形式化证明:@@ -637,7 +637,7 @@Induction归纳证明
-练习:2 星, optional (eqb_refl_informal)
+练习:2 星, standard, optional (eqb_refl_informal)
以 plus_assoc 的非形式化证明为范本,写出以下定理的非形式化证明。 不要只是用中文来解释 Coq 策略! @@ -654,10 +654,7 @@Induction归纳证明
-(* NEW NAME *)
-Notation zero_neqb_S := zero_nbeq_S (only parsing).
-Notation S_neqb_0 := S_nbeq_0 (only parsing).
-Notation plus_leb_compat_l := plus_ble_compat_l (only parsing).
+(* Sat Jan 26 15:14:45 UTC 2019 *)
Lists使用结构化的数据
-Theorem surjective_pairing' : ∀ (n m : nat),
+Theorem surjective_pairing' : ∀(n m : nat),
(n,m) = (fst (n,m), snd (n,m)).
Proof.
reflexivity. Qed.
@@ -180,7 +180,7 @@Lists使用结构化的数据
-Theorem surjective_pairing_stuck : ∀ (p : natprod),
+Theorem surjective_pairing_stuck : ∀(p : natprod),
p = (fst p, snd p).
Proof.
simpl. (* 啥也没有归约! *)
@@ -193,7 +193,7 @@Lists使用结构化的数据
-Theorem surjective_pairing : ∀ (p : natprod),
+Theorem surjective_pairing : ∀(p : natprod),
p = (fst p, snd p).
Proof.
intros p. destruct p as [n m]. simpl. reflexivity. Qed.
@@ -204,11 +204,11 @@Lists使用结构化的数据 一个子目标。这是因为 natprod 只有一种构造方法。
-练习:1 星 (snd_fst_is_swap)
+练习:1 星, standard (snd_fst_is_swap)
-Theorem snd_fst_is_swap : ∀ (p : natprod),
+Theorem snd_fst_is_swap : ∀(p : natprod),
(snd p, fst p) = swap_pair p.
Proof.
(* 请在此处解答 *) Admitted.
@@ -218,11 +218,11 @@Lists使用结构化的数据
-Theorem fst_swap_is_snd : ∀ (p : natprod),
+Theorem fst_swap_is_snd : ∀(p : natprod),
fst (swap_pair p) = snd p.
Proof.
(* 请在此处解答 *) Admitted.
@@ -231,7 +231,7 @@Lists使用结构化的数据 ☐
-数值列表
+数值列表
@@ -307,7 +307,7 @@Lists使用结构化的数据 以及将它们翻译成嵌套的二元构造子序列的方法。
-Repeat
+Repeat
@@ -324,7 +324,7 @@Lists使用结构化的数据
-@@ -437,7 +437,7 @@练习
+练习
-练习:2 星, recommended (list_funs)
+练习:2 星, standard, recommended (list_funs)
完成以下 nonzeros、oddmembers 和 countoddmembers 的定义, 你可以查看测试函数来理解这些函数应该做什么。Lists使用结构化的数据
-练习:3 星, advanced (alternate)
+练习:3 星, advanced (alternate)
完成 alternate 的定义,它从两个列表中交替地取出元素并合并为一个列表, 就像把拉链“拉”起来一样。更多具体示例见后面的测试。 @@ -469,7 +469,7 @@Lists使用结构化的数据 ☐
-练习:3 星, recommended (bag_functions)
+练习:3 星, standard, recommended (bag_functions)
为袋子完成以下 count、sum、add、和 member 函数的定义。@@ -539,7 +539,7 @@Lists使用结构化的数据
-练习:3 星, optional (bag_more_functions)
+练习:3 星, standard, optional (bag_more_functions)
你可以把下面这些和 bag 有关的函数当作额外的练习@@ -585,7 +585,7 @@Lists使用结构化的数据
-练习:2 星, recommended (bag_theorem)
+练习:2 星, standard, recommended (bag_theorem)
写一个你认为有趣的关于袋子的定理 bag_theorem,然后证明它; 这个定理需要用到 count 和 add。注意,这是个开放性问题。 也许你写下的定理是正确的,但它可能会涉及到你尚未学过的技巧因而无法证明。 @@ -609,7 +609,7 @@Lists使用结构化的数据 ☐
-Theorem nil_app : ∀ l:natlist,@@ -632,7 +632,7 @@
+Theorem nil_app : ∀l:natlist,
[] ++ l = l.
Proof. reflexivity. Qed.
Lists使用结构化的数据
-Theorem tl_length_pred : ∀ l:natlist,
+Theorem tl_length_pred : ∀l:natlist,
pred (length l) = length (tl l).
Proof.
intros l. destruct l as [| n l'].
@@ -652,7 +652,7 @@Lists使用结构化的数据
-Theorem app_assoc : ∀ l1 l2 l3 : natlist,
+Theorem app_assoc : ∀l1 l2 l3 : natlist,
(l1 ++ l2) ++ l3 = l1 ++ (l2 ++ l3).
Proof.
intros l1 l2 l3. induction l1 as [| n l1' IHl1'].
@@ -778,7 +778,7 @@Lists使用结构化的数据
-反转列表
+反转列表
@@ -799,7 +799,7 @@Lists使用结构化的数据
-Theorem rev_length_firsttry : ∀ l : natlist,
+Theorem rev_length_firsttry : ∀l : natlist,
length (rev l) = length l.
Proof.
intros l. induction l as [| n l' IHl'].
@@ -833,7 +833,7 @@Lists使用结构化的数据
-Theorem app_length : ∀ l1 l2 : natlist,
+Theorem app_length : ∀l1 l2 : natlist,
length (l1 ++ l2) = (length l1) + (length l2).
Proof.
(* 课上已完成 *)
@@ -854,7 +854,7 @@Lists使用结构化的数据
-Theorem rev_length : ∀ l : natlist,
+Theorem rev_length : ∀l : natlist,
length (rev l) = length l.
Proof.
intros l. induction l as [| n l' IHl'].
@@ -1006,7 +1006,7 @@Lists使用结构化的数据
-Theorem app_nil_r : ∀ l : natlist,
+Theorem app_nil_r : ∀l : natlist,
l ++ [] = l.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem rev_app_distr: ∀ l1 l2 : natlist,
+Theorem rev_app_distr: ∀l1 l2 : natlist,
rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem rev_involutive : ∀ l : natlist,
+Theorem rev_involutive : ∀l : natlist,
rev (rev l) = l.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1064,7 +1064,7 @@Lists使用结构化的数据
-Theorem app_assoc4 : ∀ l1 l2 l3 l4 : natlist,
+Theorem app_assoc4 : ∀l1 l2 l3 l4 : natlist,
l1 ++ (l2 ++ (l3 ++ l4)) = ((l1 ++ l2) ++ l3) ++ l4.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1075,7 +1075,7 @@Lists使用结构化的数据
-Lemma nonzeros_app : ∀ l1 l2 : natlist,
+Lemma nonzeros_app : ∀l1 l2 : natlist,
nonzeros (l1 ++ l2) = (nonzeros l1) ++ (nonzeros l2).
Proof.
(* 请在此处解答 *) Admitted.
@@ -1085,7 +1085,7 @@Lists使用结构化的数据
@@ -1102,7 +1102,7 @@-练习:2 星 (eqblist)
+练习:2 星, standard (eqblist)
填写 eqblist 的定义,它通过比较列表中的数字来判断是否相等。 证明对于所有列表 l,eqblist l l 返回 true。Lists使用结构化的数据 Example test_eqblist3 :
eqblist [1;2;3] [1;2;4] = false.
(* 请在此处解答 *) Admitted.
-Theorem eqblist_refl : ∀ l:natlist,
+Theorem eqblist_refl : ∀l:natlist,
true = eqblist l l.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1111,18 +1111,18 @@Lists使用结构化的数据 ☐
-列表练习, 第二部分
+列表练习, 第二部分
下面这组简单的定理用于证明你之前关于袋子的定义。-练习:1 星 (count_member_nonzero)
+练习:1 星, standard (count_member_nonzero)
-Theorem count_member_nonzero : ∀ (s : bag),
+Theorem count_member_nonzero : ∀(s : bag),
1 <=? (count 1 (1 :: s)) = true.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1136,7 +1136,7 @@Lists使用结构化的数据
-Theorem leb_n_Sn : ∀ n,
+Theorem leb_n_Sn : ∀n,
n <=? (S n) = true.
Proof.
intros n. induction n as [| n' IHn'].
@@ -1148,11 +1148,11 @@Lists使用结构化的数据
Before doing the next exercise, make sure you've filled in the - definition of remove_one above.练习:3 星, advanced (remove_does_not_increase_count)
+ definition of remove_one above.练习:3 星, advanced (remove_does_not_increase_count)
-Theorem remove_does_not_increase_count: ∀ (s : bag),
+Theorem remove_does_not_increase_count: ∀(s : bag),
(count 0 (remove_one 0 s)) <=? (count 0 s) = true.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1162,7 +1162,7 @@Lists使用结构化的数据
@@ -1174,13 +1174,13 @@-练习:3 星, optional (bag_count_sum)
+练习:3 星, standard, optional (bag_count_sum)
写下一个用到函数 count 和 sum 的,关于袋子的有趣定理 bag_count_sum, 然后证明它。(你可能会发现该证明的难度取决于你如何定义 count!)Lists使用结构化的数据
@@ -71,7 +71,7 @@-练习:4 星, advanced (rev_injective)
+练习:4 星, advanced (rev_injective)
求证 rev 是单射函数,即:- ∀ (l1 l2 : natlist), rev l1 = rev l2 → l1 = l2. + ∀(l1 l2 : natlist), rev l1 = rev l2 → l1 = l2.@@ -1196,7 +1196,7 @@Lists使用结构化的数据 ☐
@@ -1317,12 +1317,12 @@Lists使用结构化的数据
-练习:1 星, optional (option_elim_hd)
+练习:1 星, standard, optional (option_elim_hd)
此练习能帮助你在新的 hd_error 和旧的 hd 之间建立联系。-Theorem option_elim_hd : ∀ (l:natlist) (default:nat),
+Theorem option_elim_hd : ∀(l:natlist) (default:nat),
hd default l = option_elim default (hd_error l).
Proof.
(* 请在此处解答 *) Admitted.
@@ -1335,7 +1335,7 @@Lists使用结构化的数据
-Theorem eqb_id_refl : ∀ x, true = eqb_id x x.@@ -1425,12 +1425,12 @@
+Theorem eqb_id_refl : ∀x, true = eqb_id x x.
Proof.
(* 请在此处解答 *) Admitted.
Lists使用结构化的数据
Theorem update_eq :diff --git a/lf-current/Lists.v b/lf-current/Lists.v index 095e6cd6..b1c2ce49 100644 --- a/lf-current/Lists.v +++ b/lf-current/Lists.v @@ -123,14 +123,14 @@ Proof. (** 注意:不同于解构自然数产生两个子目标,[destruct] 在此只产生 一个子目标。这是因为 [natprod] 只有一种构造方法。 *) -(** **** 练习:1 星 (snd_fst_is_swap) *) +(** **** 练习:1 星, standard (snd_fst_is_swap) *) Theorem snd_fst_is_swap : forall (p : natprod), (snd p, fst p) = swap_pair p. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星, optional (fst_swap_is_snd) *) +(** **** 练习:1 星, standard, optional (fst_swap_is_snd) *) Theorem fst_swap_is_snd : forall (p : natprod), fst (swap_pair p) = snd p. Proof. @@ -261,8 +261,9 @@ Proof. reflexivity. Qed. (* ----------------------------------------------------------------- *) (** *** 练习 *) -(** **** 练习:2 星, recommended (list_funs) *) -(** 完成以下 [nonzeros]、[oddmembers] 和 [countoddmembers] 的定义, +(** **** 练习:2 星, standard, recommended (list_funs) + + 完成以下 [nonzeros]、[oddmembers] 和 [countoddmembers] 的定义, 你可以查看测试函数来理解这些函数应该做什么。 *) Fixpoint nonzeros (l:natlist) : natlist @@ -295,8 +296,9 @@ Example test_countoddmembers3: (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, advanced (alternate) *) -(** 完成 [alternate] 的定义,它从两个列表中交替地取出元素并合并为一个列表, +(** **** 练习:3 星, advanced (alternate) + + 完成 [alternate] 的定义,它从两个列表中交替地取出元素并合并为一个列表, 就像把拉链“拉”起来一样。更多具体示例见后面的测试。 (注意:[alternate] 有一种自然而优雅的定义,但是这一定义无法满足 Coq @@ -332,8 +334,9 @@ Example test_alternate4: Definition bag := natlist. -(** **** 练习:3 星, recommended (bag_functions) *) -(** 为袋子完成以下 [count]、[sum]、[add]、和 [member] 函数的定义。 *) +(** **** 练习:3 星, standard, recommended (bag_functions) + + 为袋子完成以下 [count]、[sum]、[add]、和 [member] 函数的定义。 *) Fixpoint count (v:nat) (s:bag) : nat (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. @@ -381,8 +384,9 @@ Example test_member2: member 2 [1;4;1] = false. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (bag_more_functions) *) -(** 你可以把下面这些和 [bag] 有关的函数当作额外的练习 *) +(** **** 练习:3 星, standard, optional (bag_more_functions) + + 你可以把下面这些和 [bag] 有关的函数当作额外的练习 *) (** 倘若某口袋不包含所要移除的数字,那么将 [remove_one] 作用其上不应改变其内容。 (本练习为选做,但高级班的学生为了完成后面的练习,需要写出 [remove_one] @@ -428,8 +432,9 @@ Example test_subset2: subset [1;2;2] [2;1;4;1] = false. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, recommended (bag_theorem) *) -(** 写一个你认为有趣的关于袋子的定理 [bag_theorem],然后证明它; +(** **** 练习:2 星, standard, recommended (bag_theorem) + + 写一个你认为有趣的关于袋子的定理 [bag_theorem],然后证明它; 这个定理需要用到 [count] 和 [add]。注意,这是个开放性问题。 也许你写下的定理是正确的,但它可能会涉及到你尚未学过的技巧因而无法证明。 如果你遇到麻烦了,欢迎提问! *) @@ -445,8 +450,9 @@ Qed. Definition manual_grade_for_bag_theorem : option (nat*string) := None. (* Note to instructors: For silly technical reasons, in this file (only) you will need to write [Some (Datatypes.pair 3 ""%string)] - rather than [Some (3,""%string)] to enter your grade and comments. *) -(** [] *) + rather than [Some (3,""%string)] to enter your grade and comments. + + [] *) (* ################################################################# *) (** * 有关列表的论证 *) @@ -687,7 +693,6 @@ Proof. 以及当前的证明与读者熟悉的证明之间的相似度都会影响到这一点。 对于我们现在的目的而言,最好先用更加冗长的方式。 *) - (** ** [Search] 搜索*) (** 我们已经见过很多需要使用之前证明过的结论(例如通过 [rewrite])来证明的定理了。 @@ -708,8 +713,9 @@ Proof. (* ================================================================= *) (** ** 列表练习,第一部分 *) -(** **** 练习:3 星 (list_exercises) *) -(** 更多有关列表的实践: *) +(** **** 练习:3 星, standard (list_exercises) + + 更多有关列表的实践: *) Theorem app_nil_r : forall l : natlist, l ++ [] = l. @@ -742,8 +748,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星 (eqblist) *) -(** 填写 [eqblist] 的定义,它通过比较列表中的数字来判断是否相等。 +(** **** 练习:2 星, standard (eqblist) + + 填写 [eqblist] 的定义,它通过比较列表中的数字来判断是否相等。 证明对于所有列表 [l],[eqblist l l] 返回 [true]。 *) Fixpoint eqblist (l1 l2 : natlist) : bool @@ -772,7 +779,7 @@ Proof. (** 下面这组简单的定理用于证明你之前关于袋子的定义。 *) -(** **** 练习:1 星 (count_member_nonzero) *) +(** **** 练习:1 星, standard (count_member_nonzero) *) Theorem count_member_nonzero : forall (s : bag), 1 <=? (count 1 (1 :: s)) = true. Proof. @@ -799,14 +806,17 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (bag_count_sum) *) -(** 写下一个用到函数 [count] 和 [sum] 的,关于袋子的有趣定理 [bag_count_sum], +(** **** 练习:3 星, standard, optional (bag_count_sum) + + 写下一个用到函数 [count] 和 [sum] 的,关于袋子的有趣定理 [bag_count_sum], 然后证明它。(你可能会发现该证明的难度取决于你如何定义 [count]!) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 -(** **** 练习:4 星, advanced (rev_injective) *) -(** 求证 [rev] 是单射函数,即: + [] *) + +(** **** 练习:4 星, advanced (rev_injective) + + 求证 [rev] 是单射函数,即: forall (l1 l2 : natlist), rev l1 = rev l2 -> l1 = l2. @@ -867,7 +877,6 @@ Proof. reflexivity. Qed. 本例也是个介绍 Coq 编程语言更多细微特性的机会,比如条件表达式... *) - Fixpoint nth_error' (l:natlist) (n:nat) : natoption := match l with | nil => None @@ -889,7 +898,7 @@ Definition option_elim (d : nat) (o : natoption) : nat := | None => d end. -(** **** 练习:2 星 (hd_error) *) +(** **** 练习:2 星, standard (hd_error) *) (** 用同样的思路修正之前的 [hd] 函数,使我们无需为 [nil] 的情况提供默认元素。 *) Definition hd_error (l : natlist) : natoption @@ -905,7 +914,7 @@ Example test_hd_error3 : hd_error [5;6] = Some 5. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星, optional (option_elim_hd) *) +(** **** 练习:1 星, standard, optional (option_elim_hd) *) (** 此练习能帮助你在新的 [hd_error] 和旧的 [hd] 之间建立联系。 *) Theorem option_elim_hd : forall (l:natlist) (default:nat), @@ -937,7 +946,7 @@ Definition eqb_id (x1 x2 : id) := | Id n1, Id n2 => n1 =? n2 end. -(** **** 练习:1 星 (eqb_id_refl) *) +(** **** 练习:1 星, standard (eqb_id_refl) *) Theorem eqb_id_refl : forall x, true = eqb_id x x. Proof. (* 请在此处解答 *) Admitted. @@ -976,7 +985,7 @@ Fixpoint find (x : id) (d : partial_map) : natoption := else find x d' end. -(** **** 练习:1 星 (update_eq) *) +(** **** 练习:1 星, standard (update_eq) *) Theorem update_eq : forall (d : partial_map) (x : id) (v: nat), find x (update d x v) = Some v. @@ -984,7 +993,7 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (update_neq) *) +(** **** 练习:1 星, standard (update_neq) *) Theorem update_neq : forall (d : partial_map) (x y : id) (o: nat), eqb_id x y = false -> find x (update d y o) = find x d. @@ -993,8 +1002,9 @@ Proof. (** [] *) End PartialMap. -(** **** 练习:2 星 (baz_num_elts) *) -(** 考虑以下归纳定义: *) +(** **** 练习:2 星, standard (baz_num_elts) + + 考虑以下归纳定义: *) Inductive baz : Type := | Baz1 (x : baz) @@ -1008,3 +1018,4 @@ Inductive baz : Type := Definition manual_grade_for_baz_num_elts : option (nat*string) := None. (** [] *) +(* Sat Jan 26 15:14:45 UTC 2019 *) diff --git a/lf-current/ListsTest.v b/lf-current/ListsTest.v index 5569520e..0f8df109 100644 --- a/lf-current/ListsTest.v +++ b/lf-current/ListsTest.v @@ -472,3 +472,5 @@ Print Assumptions NatList.remove_does_not_increase_count. idtac "---------- rev_injective ---------". idtac "MANUAL". Abort. + +(* Sat Jan 26 15:14:49 UTC 2019 *) diff --git a/lf-current/Logic.html b/lf-current/Logic.html index c2f6f799..1fc1de93 100644 --- a/lf-current/Logic.html +++ b/lf-current/Logic.html @@ -43,7 +43,7 @@
- ∀ (d : partial_map) (x : id) (v: nat),
+ ∀(d : partial_map) (x : id) (v: nat),
find x (update d x v) = Some v.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1440,12 +1440,12 @@Lists使用结构化的数据
Theorem update_neq :
- ∀ (d : partial_map) (x y : id) (o: nat),
+ ∀(d : partial_map) (x y : id) (o: nat),
eqb_id x y = false → find x (update d y o) = find x d.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1457,7 +1457,7 @@Lists使用结构化的数据
@@ -1478,6 +1478,10 @@☐ +Lists使用结构化的数据
+ +(* Sat Jan 26 15:14:45 UTC 2019 *)
+LogicCoq 中的逻辑系统 在前面的章节中,我们已经见过很多对事实的断言(即命题) 以及如何用证据展示其正确性(即证明)的例子了。特别是, 我们证明了大量形如 e1 = e2 的相等关系命题、形如 P → Q - 的蕴含式、以及形如 ∀x, P x 的量化命题。 + 的蕴含式、以及形如 ∀ x, P x 的量化命题。
@@ -57,7 +57,7 @@LogicCoq 中的逻辑系统 Check 3 = 3.
(* ===> Prop *)
-Check ∀ n m : nat, n + m = m + n.
+Check ∀n m : nat, n + m = m + n.
(* ===> Prop *)
LogicCoq 中的逻辑系统 Check 2 = 2.
(* ===> Prop *)
-Check ∀ n : nat, n = 2.
+Check ∀n : nat, n = 2.
(* ===> Prop *)
Check 3 = 4.
(* ===> Prop *)
@@ -126,7 +126,7 @@LogicCoq 中的逻辑系统 Definition is_three (n : nat) : Prop :=
n = 3.
Check is_three.
-(* ===> nat -> Prop *)
+(* ===> nat -> Prop *)
@@ -139,7 +139,7 @@LogicCoq 中的逻辑系统
Definition injective {A B} (f : A → B) :=
- ∀ x y : A, f x = f y → x = y.
+ ∀x y : A, f x = f y → x = y.
Lemma succ_inj : injective S.
Proof.
intros n m H. injection H as H1. apply H1.
@@ -157,7 +157,7 @@LogicCoq 中的逻辑系统
Check @eq.
-(* ===> forall A : Type, A -> A -> Prop *)
+(* ===> forall A : Type, A -> A -> Prop *)
@@ -166,11 +166,11 @@LogicCoq 中的逻辑系统
-逻辑联结词
+逻辑联结词
-合取
+合取
@@ -188,7 +188,6 @@LogicCoq 中的逻辑系统
Proof.
- (* 课上已完成 *)
split.
- (* 3 + 4 = 7 *) reflexivity.
- (* 2 + 2 = 4 *) reflexivity.
@@ -201,7 +200,7 @@LogicCoq 中的逻辑系统
-Lemma and_intro : ∀ A B : Prop, A → B → A ∧ B.
+Lemma and_intro : ∀A B : Prop, A → B → A ∧ B.
Proof.
intros A B HA HB. split.
- apply HA.
@@ -224,12 +223,12 @@LogicCoq 中的逻辑系统
Example and_exercise :@@ -250,7 +249,7 @@
- ∀ n m : nat, n + m = 0 → n = 0 ∧ m = 0.
+ ∀n m : nat, n + m = 0 → n = 0 ∧ m = 0.
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
Lemma and_example2 :
- ∀ n m : nat, n = 0 ∧ m = 0 → n + m = 0.
+ ∀n m : nat, n = 0 ∧ m = 0 → n + m = 0.
Proof.
(* 课上已完成 *)
intros n m H.
@@ -267,7 +266,7 @@LogicCoq 中的逻辑系统
Lemma and_example2' :
- ∀ n m : nat, n = 0 ∧ m = 0 → n + m = 0.
+ ∀n m : nat, n = 0 ∧ m = 0 → n + m = 0.
Proof.
intros n m [Hn Hm].
rewrite Hn. rewrite Hm.
@@ -282,7 +281,7 @@LogicCoq 中的逻辑系统
Lemma and_example2'' :
- ∀ n m : nat, n = 0 → m = 0 → n + m = 0.
+ ∀n m : nat, n = 0 → m = 0 → n + m = 0.
Proof.
intros n m Hn Hm.
rewrite Hn. rewrite Hm.
@@ -298,7 +297,7 @@LogicCoq 中的逻辑系统
Lemma and_example3 :
- ∀ n m : nat, n + m = 0 → n * m = 0.
+ ∀n m : nat, n + m = 0 → n * m = 0.
Proof.
(* 课上已完成 *)
intros n m H.
@@ -315,7 +314,7 @@LogicCoq 中的逻辑系统
-Lemma proj1 : ∀ P Q : Prop,
+Lemma proj1 : ∀P Q : Prop,
P ∧ Q → P.
Proof.
intros P Q [HP HQ].
@@ -323,11 +322,11 @@LogicCoq 中的逻辑系统
-Lemma proj2 : ∀ P Q : Prop,
+Lemma proj2 : ∀P Q : Prop,
P ∧ Q → Q.
Proof.
(* 请在此处解答 *) Admitted.
@@ -342,7 +341,7 @@LogicCoq 中的逻辑系统
-Theorem and_commut : ∀ P Q : Prop,
+Theorem and_commut : ∀P Q : Prop,
P ∧ Q → Q ∧ P.
Proof.
intros P Q [HP HQ].
@@ -352,14 +351,14 @@LogicCoq 中的逻辑系统
-练习:2 星 (and_assoc)
+练习:2 星, standard (and_assoc)
(在以下结合律的证明中,注意嵌套的 intros 模式是如何将 H : P ∧ (Q ∧ R) 拆分为 HP : P、HQ : Q 和 HR : R 的。 请从那里开始完成证明。)-Theorem and_assoc : ∀ P Q R : Prop,
+Theorem and_assoc : ∀P Q R : Prop,
P ∧ (Q ∧ R) → (P ∧ Q) ∧ R.
Proof.
intros P Q R [HP [HQ HR]].
@@ -376,27 +375,27 @@LogicCoq 中的逻辑系统
Check and.
-(* ===> and : Prop -> Prop -> Prop *)
+(* ===> and : Prop -> Prop -> Prop *)
-析取
+析取
另一个重要的联结词是_析取_,即两个命题的逻辑或:若 A 或 B - 二者之一为真,则 A ∨ B 为真。(我们也可以写作 or A B,其中 + 二者之一为真,则 A ∨ B 为真。(这中中缀记法表示 or A B,其中 or : Prop → Prop → Prop。)为了在证明中使用析取前提,我们需要分类讨论,它与 nat - 或其它数据类型一样,都可以通过 destruct 或 intros 来拆分。 - 下面就是个例子: + 或其它数据类型一样,都可以显示地通过 destruct 或隐式地通过 intros + 模式来拆分:Lemma or_example :
- ∀ n m : nat, n = 0 ∨ m = 0 → n * m = 0.
+ ∀n m : nat, n = 0 ∨ m = 0 → n * m = 0.
Proof.
(* Hn | Hm 会隐式地对 n = 0 ∨ m = 0 进行分类讨论 *)
intros n m [Hn | Hm].
@@ -416,7 +415,7 @@LogicCoq 中的逻辑系统
-Lemma or_intro : ∀ A B : Prop, A → A ∨ B.
+Lemma or_intro : ∀A B : Prop, A → A ∨ B.
Proof.
intros A B HA.
left.
@@ -425,12 +424,12 @@LogicCoq 中的逻辑系统
-...而更有趣的例子则同时需要 left 和 right: +...而这个更有趣的例子则同时需要 left 和 right:Lemma zero_or_succ :
- ∀ n : nat, n = 0 ∨ n = S (pred n).
+ ∀n : nat, n = 0 ∨ n = S (pred n).
Proof.
(* 课上已完成 *)
intros [|n].
@@ -440,37 +439,42 @@LogicCoq 中的逻辑系统
-假命题与否定
+假命题与否定
目前为止,我们主要都在证明某些东西是真的:加法满足结合律, 列表的连接满足结合律,等等。当然,我们也关心否定的结果, - 即证明某些命题不是真的。在 Coq 中,这样的否定语句使用否定运算符 + 即证明某些给定的命题不是真的。在 Coq 中,这样的否定语句使用否定运算符 ¬ 来表达。- 为了理解否定背后的原理,我们需要回想一下Tactics一章中对爆炸原理的讨论。 - 爆炸原理断言,当我们假设了矛盾存在时,就能推出任何命题。遵循这一直觉, - 我们可以可以将 ¬ P(即非 P)定义为 ∀Q, P → Q。 - 不过 Coq 选择了稍有些不同的做法,它将 ¬ P 定义为 P → False,而 + 为了理解否定背后的原理,我们需要回想一下Tactics一章中的爆炸原理。 + 爆炸原理断言,当我们假设了矛盾存在时,就能推出任何命题。 + ++ + 遵循这一直觉,我们可以可以将 ¬ P(即非 P)定义为 ∀ Q, P → Q。 + ++ + 不过 Coq 选择了稍有些不同(但等价)的做法,它将 ¬ P 定义为 P → False,而 False 是在标准库中特别定义的矛盾性命题。Module MyNot.
Definition not (P:Prop) := P → False.
-Notation "¬ x" := (not x) : type_scope.
+Notation "¬x" := (not x) : type_scope.
Check not.
-(* ===> Prop -> Prop *)
+(* ===> Prop -> Prop *)
End MyNot.
由于 False 是个矛盾性命题,因此爆炸原理对它也适用。如果我们让 False - 进入到了证明的上下文中,可以对它使用 destruct(或 discriminate) - 来完成任何待证目标。 + 进入到了证明的上下文中,可以对它使用 destruct 来完成任何待证目标。-Theorem ex_falso_quodlibet : ∀ (P:Prop),
+Theorem ex_falso_quodlibet : ∀(P:Prop),
False → P.
Proof.
(* 课上已完成 *)
@@ -483,13 +487,13 @@LogicCoq 中的逻辑系统 你能够证明任何你想要的”,这也是爆炸原理的另一个广为人知的名字。
-练习:2 星, optional (not_implies_our_not)
+练习:2 星, standard, optional (not_implies_our_not)
证明 Coq 对否定的定义蕴含前面提到的直觉上的定义:-Fact not_implies_our_not : ∀ (P:Prop),@@ -498,26 +502,48 @@
- ¬ P → (∀ (Q:Prop), P → Q).
+Fact not_implies_our_not : ∀(P:Prop),
+ ¬P → (∀(Q:Prop), P → Q).
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
- 下面我们用 not 陈述了 0 和 1 是不同的 nat 元素: + 不等性是十分常见的否定句的例子,,它有一个特别的记法 x ≠ y: + ++ ++ Notation "x ≠ y" := (~(x = y)). ++ ++ ++ + 我们可以用 not 来陈述 0 和 1 是不同的 nat 元素:-Theorem zero_not_one : ~(0 = 1).
+Theorem zero_not_one : 0 ≠ 1.
Proof.
- intros contra. discriminate contra.
-Qed.
-这样的不等性表述频繁出现,足以让我们为其定义一种特殊的记法 x ≠ y: +性质 0 ≠ 1 就是 ~(0 = 1),即 not (0 = 1), + 它会展开为 (0 = 1) → False。(这里显式地用 unfold not + 展示了这一点,不过一般可以忽略。+ unfold not.-Check (0 ≠ 1).
+
-(* ===> Prop *)
-Theorem zero_not_one' : 0 ≠ 1.
-Proof.
- intros H. discriminate H.
++要证明不等性,我们可以反过来假设其相等... +++ intros contra.+ +
++... 然后从中推出矛盾。在这里,等式 O = S O 与构造子 O 和 S + 的不交性相矛盾,因此用 discriminate 就能解决它。 +++ discriminate contra.@@ -529,16 +555,16 @@
Qed.
LogicCoq 中的逻辑系统
Theorem not_False :
- ¬ False.
+ ¬False.
Proof.
unfold not. intros H. destruct H. Qed.
-Theorem contradiction_implies_anything : ∀ P Q : Prop,
+Theorem contradiction_implies_anything : ∀P Q : Prop,
(P ∧ ¬P) → Q.
Proof.
(* 课上已完成 *)
intros P Q [HP HNA]. unfold not in HNA.
apply HNA in HP. destruct HP. Qed.
-Theorem double_neg : ∀ P : Prop,
+Theorem double_neg : ∀P : Prop,
P → ~~P.
Proof.
(* 课上已完成 *)
@@ -546,7 +572,7 @@LogicCoq 中的逻辑系统
-练习:2 星, advanced (double_neg_inf)
+练习:2 星, advanced (double_neg_inf)
请写出 double_neg 的非形式化证明:@@ -564,11 +590,11 @@LogicCoq 中的逻辑系统
-Theorem contrapositive : ∀ (P Q : Prop),
+Theorem contrapositive : ∀(P Q : Prop),
(P → Q) → (¬Q → ¬P).
Proof.
(* 请在此处解答 *) Admitted.
@@ -578,12 +604,12 @@LogicCoq 中的逻辑系统
-Theorem not_both_true_and_false : ∀ P : Prop,@@ -592,8 +618,8 @@
- ¬ (P ∧ ¬P).
+Theorem not_both_true_and_false : ∀P : Prop,
+ ¬(P ∧ ¬P).
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
-练习:1 星, advanced (informal_not_PNP)
- 请写出 ∀P : Prop, ~(P ∧ ¬P) 的非形式化证明。 +练习:1 星, advanced (informal_not_PNP)
+ 请写出 ∀ P : Prop, ~(P ∧ ¬P) 的非形式化证明。@@ -614,7 +640,7 @@LogicCoq 中的逻辑系统
-Theorem not_true_is_false : ∀ b : bool,
+Theorem not_true_is_false : ∀b : bool,
b ≠ true → b = false.
Proof.
intros [] H.
@@ -633,7 +659,7 @@LogicCoq 中的逻辑系统
-Theorem not_true_is_false' : ∀ b : bool,
+Theorem not_true_is_false' : ∀b : bool,
b ≠ true → b = false.
Proof.
intros [] H.
@@ -646,7 +672,7 @@LogicCoq 中的逻辑系统
-真值
+真值
@@ -665,7 +691,7 @@LogicCoq 中的逻辑系统 它还是挺有用的。之后我们会看到 True 的这类用法。
-逻辑等价
+逻辑等价
@@ -680,31 +706,31 @@LogicCoq 中的逻辑系统 (at level 95, no associativity)
: type_scope.
End MyIff.
-Theorem iff_sym : ∀ P Q : Prop,
+Theorem iff_sym : ∀P Q : Prop,
(P ↔ Q) → (Q ↔ P).
Proof.
(* 课上已完成 *)
intros P Q [HAB HBA].
split.
- - (* -> *) apply HBA.
+ - (* -> *) apply HBA.
- (* <- *) apply HAB. Qed.
-Lemma not_true_iff_false : ∀ b,
+Lemma not_true_iff_false : ∀b,
b ≠ true ↔ b = false.
Proof.
(* 课上已完成 *)
intros b. split.
- - (* -> *) apply not_true_is_false.
+ - (* -> *) apply not_true_is_false.
- (* <- *)
intros H. rewrite H. intros H'. discriminate H'.
Qed.
-Theorem or_distributes_over_and : ∀ P Q R : Prop,
+Theorem or_distributes_over_and : ∀P Q R : Prop,
P ∨ (Q ∧ R) ↔ (P ∨ Q) ∧ (P ∨ R).
Proof.
(* 请在此处解答 *) Admitted.
@@ -720,7 +746,7 @@LogicCoq 中的逻辑系统
-Require Import Coq.Setoids.Setoid.
+From Coq Require Import Setoids.Setoid.
@@ -729,7 +755,7 @@LogicCoq 中的逻辑系统
-Lemma mult_0 : ∀ n m, n * m = 0 ↔ n = 0 ∨ m = 0.
+Lemma mult_0 : ∀n m, n * m = 0 ↔ n = 0 ∨ m = 0.
Proof.
@@ -741,7 +767,7 @@LogicCoq 中的逻辑系统
Lemma or_assoc :
- ∀ P Q R : Prop, P ∨ (Q ∨ R) ↔ (P ∨ Q) ∨ R.
+ ∀P Q R : Prop, P ∨ (Q ∨ R) ↔ (P ∨ Q) ∨ R.
Proof.
@@ -766,7 +792,7 @@LogicCoq 中的逻辑系统
Lemma mult_0_3 :
- ∀ n m p, n * m * p = 0 ↔ n = 0 ∨ m = 0 ∨ p = 0.
+ ∀n m p, n * m * p = 0 ↔ n = 0 ∨ m = 0 ∨ p = 0.
Proof.
intros n m p.
rewrite mult_0. rewrite mult_0. rewrite or_assoc.
@@ -781,61 +807,61 @@LogicCoq 中的逻辑系统
Lemma apply_iff_example :
- ∀ n m : nat, n * m = 0 → n = 0 ∨ m = 0.
+ ∀n m : nat, n * m = 0 → n = 0 ∨ m = 0.
Proof.
intros n m H. apply mult_0. apply H.
Qed.
-存在量化
+存在量化
存在量化也是十分重要的逻辑联结词。我们说存在某个类型为 T - 的 x,使得某些性质 P 对于 x 成立,写作 ∃x : T, P。 - 和 ∀一样,如果 Coq 能从上下文中推断出 x 的类型,那么类型标注 + 的 x,使得某些性质 P 对于 x 成立,写作 ∃ x : T, P。 + 和 ∀ 一样,如果 Coq 能从上下文中推断出 x 的类型,那么类型标注 : T 就可以省略。- 为了证明形如 ∃x, P 的语句,我们必须证明 P 对于某些特定的 + 为了证明形如 ∃ x, P 的语句,我们必须证明 P 对于某些特定的 x 成立,这些特定的 x 被称作存在性的例证。证明分为两步: - 首先,我们调用 ∃t 策略向 Coq 指出已经知道了使 P + 首先,我们调用 ∃ t 策略向 Coq 指出已经知道了使 P 成立的例证 t,然后证明将所有出现的 x 替换成 t 的命题 P。-Lemma four_is_even : ∃ n : nat, 4 = n + n.
+Lemma four_is_even : ∃n : nat, 4 = n + n.
Proof.
- ∃ 2. reflexivity.
+ ∃2. reflexivity.
Qed.
-反之,如果我们的的上下文中有形如 ∃x, P 的存在前提, +反之,如果我们的的上下文中有形如 ∃ x, P 的存在前提, 可以将其解构得到一个例证 x 和一个陈述 P 对于 x 成立的前提。-Theorem exists_example_2 : ∀ n,
- (∃ m, n = 4 + m) →
- (∃ o, n = 2 + o).
+Theorem exists_example_2 : ∀n,
+ (∃m, n = 4 + m) →
+ (∃o, n = 2 + o).
Proof.
(* 课上已完成 *)
intros n [m Hm]. (* 注意这里隐式使用了 destruct *)
- ∃ (2 + m).
+ ∃(2 + m).
apply Hm. Qed.
-练习:1 星, recommended (dist_not_exists)
+练习:1 星, standard, recommended (dist_not_exists)
请证明“P 对所有 x 成立”蕴含“不存在 x 使 P 不成立。” (提示:destruct H as [x E] 可以用于存在假设!)-Theorem dist_not_exists : ∀ (X:Type) (P : X → Prop),@@ -844,13 +870,13 @@
- (∀ x, P x) → ¬ (∃ x, ¬ P x).
+Theorem dist_not_exists : ∀(X:Type) (P : X → Prop),
+ (∀x, P x) → ¬(∃x, ¬P x).
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
-Theorem dist_exists_or : ∀ (X:Type) (P Q : X → Prop),@@ -858,7 +884,7 @@
- (∃ x, P x ∨ Q x) ↔ (∃ x, P x) ∨ (∃ x, Q x).
+Theorem dist_exists_or : ∀(X:Type) (P Q : X → Prop),
+ (∃x, P x ∨ Q x) ↔ (∃x, P x) ∨ (∃x, Q x).
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统 ☐
-@@ -931,7 +957,7 @@使用命题编程
+使用命题编程
@@ -906,14 +932,14 @@LogicCoq 中的逻辑系统 simpl. right. right. right. left. reflexivity.
Qed.
Example In_example_2 :
- ∀ n, In n [2; 4] →
- ∃ n', n = 2 * n'.
+ ∀n, In n [2; 4] →
+ ∃n', n = 2 * n'.
Proof.
(* 课上已完成 *)
simpl.
intros n [H | [H | []]].
- - ∃ 1. rewrite <- H. reflexivity.
- - ∃ 2. rewrite <- H. reflexivity.
+ - ∃1. rewrite <- H. reflexivity.
+ - ∃2. rewrite <- H. reflexivity.
Qed.
LogicCoq 中的逻辑系统
Lemma In_map :
- ∀ (A B : Type) (f : A → B) (l : list A) (x : A),
+ ∀(A B : Type) (f : A → B) (l : list A) (x : A),
In x l →
In (f x) (map f l).
Proof.
@@ -953,14 +979,14 @@LogicCoq 中的逻辑系统 这是一种与之不同的技巧,有着其独特的优势和限制。
-练习:2 星 (In_map_iff)
+练习:2 星, standard (In_map_iff)
Lemma In_map_iff :@@ -969,11 +995,11 @@
- ∀ (A B : Type) (f : A → B) (l : list A) (y : B),
+ ∀(A B : Type) (f : A → B) (l : list A) (y : B),
In y (map f l) ↔
- ∃ x, f x = y ∧ In x l.
+ ∃x, f x = y ∧ In x l.
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
-Lemma In_app_iff : ∀ A l l' (a:A),
+Lemma In_app_iff : ∀A l l' (a:A),
In a (l++l') ↔ In a l ∨ In a l'.
Proof.
(* 请在此处解答 *) Admitted.
@@ -983,7 +1009,7 @@LogicCoq 中的逻辑系统
-练习:3 星, recommended (All)
+练习:3 星, standard, recommended (All)
回忆一下,返回命题的函数可以视作对其参数性质的定义。例如,若 P 的类型为 nat → Prop,那么 P n 就陈述了性质 P 对 n 成立。 @@ -998,8 +1024,8 @@LogicCoq 中的逻辑系统 Fixpoint All {T : Type} (P : T → Prop) (l : list T) : Prop
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
Lemma All_In :
- ∀ T (P : T → Prop) (l : list T),
- (∀ x, In x l → P x) ↔
+ ∀T (P : T → Prop) (l : list T),
+ (∀x, In x l → P x) ↔
All P l.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1009,7 +1035,7 @@LogicCoq 中的逻辑系统
-练习:3 星 (combine_odd_even)
+练习:3 星, standard (combine_odd_even)
完成以下 combine_odd_even 函数的定义。它接受两个对数字成立的性质 Podd 与 Peven,返回性质 P 使得当 n 为奇数时 P n 等价于 Podd n, 否则等价于 Peven n。 @@ -1026,21 +1052,21 @@LogicCoq 中的逻辑系统
Theorem combine_odd_even_intro :
- ∀ (Podd Peven : nat → Prop) (n : nat),
+ ∀(Podd Peven : nat → Prop) (n : nat),
(oddb n = true → Podd n) →
(oddb n = false → Peven n) →
combine_odd_even Podd Peven n.
Proof.
(* 请在此处解答 *) Admitted.
Theorem combine_odd_even_elim_odd :
- ∀ (Podd Peven : nat → Prop) (n : nat),
+ ∀(Podd Peven : nat → Prop) (n : nat),
combine_odd_even Podd Peven n →
oddb n = true →
Podd n.
Proof.
(* 请在此处解答 *) Admitted.
Theorem combine_odd_even_elim_even :
- ∀ (Podd Peven : nat → Prop) (n : nat),
+ ∀(Podd Peven : nat → Prop) (n : nat),
combine_odd_even Podd Peven n →
oddb n = false →
Peven n.
@@ -1051,15 +1077,16 @@LogicCoq 中的逻辑系统 ☐
-对参数应用定理
+对参数应用定理
- Coq 拥有一个不同于其它证明助理的特性,即它将证明本身也作为一等对象。 + Coq 拥有一个不同于其它的证明助理(如 ACL2 和 Isabelle)的特性, + 即它将证明本身也作为一等对象。- 关于这一点有很多地方值得着墨,不过详细了解它对于使用 Coq 来说不是必须的。 + 关于这一点有很多地方值得着墨,不过了解所有的细节对于使用 Coq 来说不是必须的。 本节点到为止,深入的探讨参见 ProofObjects 和 IndPrinciples。@@ -1078,7 +1105,7 @@LogicCoq 中的逻辑系统
原因在于标识符 plus_comm 其实指代的是被称作证明对象的数据结构, - 它表示在命题 ∀n m : nat, n + m = m + n 的真实性上建立的逻辑推导。 + 它表示在命题 ∀ n m : nat, n + m = m + n 的真实性上建立的逻辑推导。 此对象的类型就是其所证命题的陈述。@@ -1095,7 +1122,7 @@LogicCoq 中的逻辑系统
Lemma plus_comm3 :
- ∀ x y z, x + (y + z) = (z + y) + x.
+ ∀x y z, x + (y + z) = (z + y) + x.
@@ -1105,6 +1132,7 @@LogicCoq 中的逻辑系统
Proof.
+ (* 课上已完成 *)
intros x y z.
rewrite plus_comm.
rewrite plus_comm.
@@ -1119,7 +1147,7 @@LogicCoq 中的逻辑系统
Lemma plus_comm3_take2 :
- ∀ x y z, x + (y + z) = (z + y) + x.
+ ∀x y z, x + (y + z) = (z + y) + x.
Proof.
intros x y z.
rewrite plus_comm.
@@ -1137,7 +1165,7 @@LogicCoq 中的逻辑系统
Lemma plus_comm3_take3 :+
- ∀ x y z, x + (y + z) = (z + y) + x.
+ ∀x y z, x + (y + z) = (z + y) + x.
Proof.
intros x y z.
rewrite plus_comm.
@@ -1146,15 +1174,80 @@LogicCoq 中的逻辑系统 Qed.
+我们来展示另一个像函数那样使用定理或引理的例子。以下定理说明: + 任何包含元素的列表 l 一定非空。 +++ +Lemma in_not_nil :+ +
+ ∀A (x : A) (l : list A), In x l → l ≠ [].
+Proof.
+ intros A x l H. unfold not. intro Hl. destruct l.
+ - simpl in H. destruct H.
+ - discriminate Hl.
+Qed.
++有趣的地方是一个量化的变量(x)没有出现在结论(l ≠ [])中。 +++ + 我们可以用此引理来证明 x 为 42 的特殊情况。直接用 apply in_not_nil + 会失败,因为它无法推出 x 的值。有一些方法可以绕开它... ++ +Lemma in_not_nil_42 :+
+ ∀l : list nat, In 42 l → l ≠ [].
+Proof.
+ (* 课上已完成 *)
+ intros l H.
+ Fail apply in_not_nil.
+Abort.
+(* apply ... with ... *)
+Lemma in_not_nil_42_take2 :
+ ∀l : list nat, In 42 l → l ≠ [].
+Proof.
+ intros l H.
+ apply in_not_nil with (x := 42).
+ apply H.
+Qed.
+(* apply ... in ... *)
+Lemma in_not_nil_42_take3 :
+ ∀l : list nat, In 42 l → l ≠ [].
+Proof.
+ intros l H.
+ apply in_not_nil in H.
+ apply H.
+Qed.
+(* 显式地对 x 的值应用引理。 *)
+Lemma in_not_nil_42_take4 :
+ ∀l : list nat, In 42 l → l ≠ [].
+Proof.
+ intros l H.
+ apply (in_not_nil nat 42).
+ apply H.
+Qed.
+(* 显式地对假设应用引理。 *)
+Lemma in_not_nil_42_take5 :
+ ∀l : list nat, In 42 l → l ≠ [].
+Proof.
+ intros l H.
+ apply (in_not_nil _ _ _ H).
+Qed.
+对于几乎所有将定理名作为参数的策略而言,你都可以“将定理作为函数”来使用。 注意,定理应用与函数应用使用了同样的类型推导机制,所以你可以将通配符作为定理的参数, - 或者为定理声明默认的隐式前提。这些特性在以下证明中展示。 + 或者为定理声明默认的隐式前提。这些特性在以下证明中展示。(此证明如何工作的细节 + 不必关心,这里的目标只是为了展示它的用途。)Example lemma_application_ex :
- ∀ {n : nat} {ns : list nat},
+ ∀{n : nat} {ns : list nat},
In n (map (fun m ⇒ m * 0) ns) →
n = 0.
Proof.
@@ -1170,7 +1263,7 @@LogicCoq 中的逻辑系统
-Coq vs. 集合论
+Coq vs. 集合论
@@ -1180,7 +1273,7 @@LogicCoq 中的逻辑系统 一个数学对象可同时属于不同的集合;而在 Coq 的逻辑中,一个项最多只属于一个类型。 这些不同之处需要人们用稍微不同的方式来描述非形式化的数学概念,但总的来说, 它们都是非常自然而易于使用的。例如,在 Coq 中我们一般不说某个自然数 n - 属于偶数集合,而是说 ev n 成立,其中的 ev : nat → Prop 描述了偶数的性质。 + 属于偶数集合,而是说 even n 成立,其中的 even : nat → Prop 描述了偶数的性质。
@@ -1189,7 +1282,7 @@LogicCoq 中的逻辑系统 我们将探讨这两个世界之间最显著的区别。
-函数的外延性
+函数的外延性
@@ -1199,7 +1292,8 @@LogicCoq 中的逻辑系统
-Example function_equality_ex1 : plus 3 = plus (pred 4).
+Example function_equality_ex1 :
+ (fun x ⇒ 3 + x) = (fun x ⇒ (pred 4) + x).
Proof. reflexivity. Qed.@@ -1241,9 +1335,9 @@
@@ -1213,7 +1307,7 @@LogicCoq 中的逻辑系统
- (∀ x, f x = g x) → f = g + (∀x, f x = g x) → f = g@@ -1232,7 +1326,7 @@LogicCoq 中的逻辑系统 Example function_equality_ex2 :
(fun x ⇒ plus x 1) = (fun x ⇒ plus 1 x).
Proof.
- (* Stuck *)
+ (* 卡住了 *)
Abort.
LogicCoq 中的逻辑系统
-Axiom functional_extensionality : ∀ {X Y: Type}
+Axiom functional_extensionality : ∀{X Y: Type}
{f g : X → Y},
- (∀ (x:X), f x = g x) → f = g.
+ (∀(x:X), f x = g x) → f = g.
@@ -1265,12 +1359,13 @@LogicCoq 中的逻辑系统
当然,在为 Coq 添加公理时必须十分小心,因为这有可能会导致系统 - 不一致,而当系统不一致的,任何命题都能在其中证明,包括 False! + 不一致,而当系统不一致的,任何命题都能在其中证明,包括 False + 和 2+2=5!不幸的是,并没有一种简单的方式能够判断添加某条公理是否安全: - 一般来说,确认任何一组公理的一致性都需要付出艰辛的努力。 + 一般来说,确认任何一组公理的一致性都需要训练有素的专家付出艰辛的努力。@@ -1285,12 +1380,12 @@LogicCoq 中的逻辑系统 (* ===>
Axioms:
functional_extensionality :
- forall (X Y : Type) (f g : X -> Y),
- (forall x : X, f x = g x) -> f = g *)
+ forall (X Y : Type) (f g : X -> Y),
+ (forall x : X, f x = g x) -> f = g *)
-练习:4 星 (tr_rev_correct)
+练习:4 星, standard (tr_rev_correct)
列表反转函数 rev 的定义有一个问题,它会在每一步都执行一次 app 调用,而运行 app 所需时间与列表的大小线性渐近,也就是说 rev 的时间复杂度与列表长度成平方关系。我们可以用以下定义来改进它: @@ -1313,7 +1408,7 @@LogicCoq 中的逻辑系统
-Lemma tr_rev_correct : ∀ X, @tr_rev X = @rev X.@@ -1321,7 +1416,7 @@
+Lemma tr_rev_correct : ∀X, @tr_rev X = @rev X.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
+-命题与布尔值
+命题与布尔值
@@ -1330,81 +1425,105 @@LogicCoq 中的逻辑系统
- 例如,我们可以通过以下两种方式来断言 n 为偶数: - + 例如,我们可以通过以下两种方式来断言 n 为偶数:--
+ evenb n 求值为 true: +- (1) evenb n 返回 true,或者 - -
-- (2) 存在某个 k 使得 n = double k。 - 这两种对偶数的定义确实是等价的,我们可以通过一些辅助引理来证明它。 - -
-+Example even_42_bool : evenb 42 = true.-
+++Proof. reflexivity. Qed.+
+++或者存在某个 k 使得 n = double k: +++Example even_42_prop : ∃k, 42 = double k.- 当然,如果二者对偶数的刻画描述的并是不同一个自然数集,那会非常奇怪! - 幸运的是,我们可以证明二者确实等价... +
+++Proof. ∃21. reflexivity. Qed.+
++当然,如果二者刻画的偶数性描述的不是同一个自然数集合,那么会非常奇怪! + 幸运的是,我们确实可以证明二者相同...首先我们需要两个辅助引理。-Theorem evenb_double : ∀ k, evenb (double k) = true.
+Theorem evenb_double : ∀k, evenb (double k) = true.
++Proof.+
intros k. induction k as [|k' IHk'].
- reflexivity.
- simpl. apply IHk'.
Qed.
-Theorem evenb_double_conv : ∀ n,
- ∃ k, n = if evenb n then double k
+Theorem evenb_double_conv : ∀n,
+ ∃k, n = if evenb n then double k
else S (double k).
++Proof.☐ -
(* 提示:使用 Induction.v 中的 evenb_S 引理。 *)
(* 请在此处解答 *) Admitted.
-Theorem even_bool_prop : ∀ n,
- evenb n = true ↔ ∃ k, n = double k.
--+
+Theorem even_bool_prop : ∀n,
+ evenb n = true ↔ ∃k, n = double k.
++Proof.
intros n. split.
- intros H. destruct (evenb_double_conv n) as [k Hk].
- rewrite Hk. rewrite H. ∃ k. reflexivity.
+ rewrite Hk. rewrite H. ∃k. reflexivity.
- intros [k Hk]. rewrite Hk. apply evenb_double.
Qed.
-此定理说明,逻辑命题 ∃k, n = double k 的真伪对应布尔计算 evenb n +此定理说明,逻辑命题 ∃ k, n = double k 的真伪对应布尔计算 evenb n 的真值。- 类似地,以下两种描述 n 与 m 相等的表达方式等价: - (一)n =? m 值为 true; - (二)n = m。 + 类似地,以下两种 n 与 m 相等的表述等价: + ++ ++
+ 同样,二者的记法也等价。- (1) n =? m 值为 true; + +
+- (2) n = m。 + +
+-Theorem eqb_eq : ∀ n1 n2 : nat,
+Theorem eqb_eq : ∀n1 n2 : nat,
n1 =? n2 = true ↔ n1 = n2.
--++Proof.
intros n1 n2. split.
- apply eqb_true.
@@ -1415,20 +1534,14 @@LogicCoq 中的逻辑系统
然而,即便布尔值和某个断言的命题式在逻辑上是等价的,但它们在操作上 - 并不一样。 - -- - 相等关系就是一个极端的例子:就涉及 n 和 m 的证明的中间步骤而言, - 知道 n =? m = true 通常没什么帮助。然而,如果我们可以将此陈述 - 转换成 n = m 的形式,就能用它来改写证明。 + 也可能不一样。- 偶数也是个有趣的例子。回想一下,在证明 even_bool_prop - 的反向部分(即 evenb_double,从命题到布尔表达式的方向)时,我们对 + 在前面的偶数例子中,证明 even_bool_prop 的反向部分(即 + evenb_double,从命题到布尔表达式的方向)时,我们对 k 进行了简单的归纳。而反方向的证明(即练习 evenb_double_conv) - 则需要一种聪明的一般化方法,因为我们无法直接证明 (∃k, n = - double k) → evenb n = true。 + 则需要一种聪明的一般化方法,因为我们无法直接证明 + (∃ k, n = double k) → evenb n = true。对于这些例子来说,命题式的声明比与之对应的布尔表达式要更为有用, @@ -1467,7 +1580,7 @@LogicCoq 中的逻辑系统
-Example even_1000 : ∃ k, 1000 = double k.
+Example even_1000 : ∃k, 1000 = double k.
@@ -1475,7 +1588,7 @@LogicCoq 中的逻辑系统
-Proof. ∃ 500. reflexivity. Qed.
+Proof. ∃500. reflexivity. Qed.
@@ -1493,28 +1606,79 @@LogicCoq 中的逻辑系统
-Example even_1000'' : ∃ k, 1000 = double k.
+Example even_1000'' : ∃k, 1000 = double k.
Proof. apply even_bool_prop. reflexivity. Qed.
-尽管此例的证明的长度并未因此而减少,然而更大的证明通常可通过 +尽管此例的证明脚本的长度并未因此而减少,然而更大的证明通常可通过 这种互映的方式来显著化简。举一个极端的例子,在用 Coq 证明著名的 - 四色定理时,人们使用互映技巧将几百种不同的情况归约成了一个布尔计算。 - 我们不会详细地介绍互映技巧,然而对于展示布尔计算与一般命题的互补优势而言, + 四色定理时,人们使用互映技巧将几百种不同的情况归约成了一个布尔计算。 +++ + 另一点明显的不同是“布尔事实”的否定可以被直白地陈述并证明, + 只需翻转预期的布尔值结果即可。 ++ +Example not_even_1001 : evenb 1001 = false.+ +
+Proof.
+ (* 课上已完成 *)
+ reflexivity.
+Qed.
++相反,命题的否定形式可能更难以掌握。 +++ +Example not_even_1001' : ~(∃k, 1001 = double k).+ +
+Proof.
+ (* 课上已完成 *)
+ rewrite <- even_bool_prop.
+ unfold not.
+ simpl.
+ intro H.
+ discriminate H.
+Qed.
++相等性补充了另一个例子。在涉及 n 和 m 的证明中,知道 n =? m = true + 通常会有一点直接的帮助。然而如果我们将该语句转换为等价的 n = m 形式, + 那么我们可以对它进行改写。 + +++ +Lemma plus_eqb_example : ∀n m p : nat,+ +
+ n =? m = true → n + p =? m + p = true.
+Proof.
+ (* 课上已完成 *)
+ intros n m p H.
+ rewrite eqb_eq in H.
+ rewrite H.
+ rewrite eqb_eq.
+ reflexivity.
+Qed.
++我们不会详细地介绍互映技巧,然而对于展示布尔计算与一般命题的互补优势而言, 它是个很好的例子。-练习:2 星 (logical_connectives)
+练习:2 星, standard (logical_connectives)
以下引理将本章中讨论的命题联结词与对应的布尔操作关联了起来。-Lemma andb_true_iff : ∀ b1 b2:bool,
+Lemma andb_true_iff : ∀b1 b2:bool,
b1 && b2 = true ↔ b1 = true ∧ b2 = true.
Proof.
(* 请在此处解答 *) Admitted.
-Lemma orb_true_iff : ∀ b1 b2,
+Lemma orb_true_iff : ∀b1 b2,
b1 || b2 = true ↔ b1 = true ∨ b2 = true.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1524,13 +1688,13 @@LogicCoq 中的逻辑系统
-练习:1 星 (eqb_neq)
+练习:1 星, standard (eqb_neq)
以下定理为等价式 eqb_eq 的“否定”版本, 在某些场景中使用它会更方便些(后面的章节中会讲到这方面的例子)。-Theorem eqb_neq : ∀ x y : nat,
+Theorem eqb_neq : ∀x y : nat,
x =? y = false ↔ x ≠ y.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1540,7 +1704,7 @@LogicCoq 中的逻辑系统
@@ -1563,7 +1727,7 @@-练习:3 星 (eqb_list)
+练习:3 星, standard (eqb_list)
给定一个用于测试类型为 A 的元素相等关系的布尔操作符 eqb, 我们可以定义函数 eqb_list 来测试元素类型为 A 的列表的相等关系。 请完成以下 eqb_list 函数的定义。要确定你的定义是否正确,请证明引理 @@ -1552,9 +1716,9 @@LogicCoq 中的逻辑系统 (l1 l2 : list A) : bool
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
Lemma eqb_list_true_iff :
- ∀ A (eqb : A → A → bool),
- (∀ a1 a2, eqb a1 a2 = true ↔ a1 = a2) →
- ∀ l1 l2, eqb_list eqb l1 l2 = true ↔ l1 = l2.
+ ∀A (eqb : A → A → bool),
+ (∀a1 a2, eqb a1 a2 = true ↔ a1 = a2) →
+ ∀l1 l2, eqb_list eqb l1 l2 = true ↔ l1 = l2.
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
@@ -1581,7 +1745,7 @@-练习:2 星, recommended (All_forallb)
+练习:2 星, standard, recommended (All_forallb)
回忆一下Tactics一章中练习 forall_exists_challenge 的函数 forallb:LogicCoq 中的逻辑系统
-Theorem forallb_true_iff : ∀ X test (l : list X),diff --git a/lf-current/Logic.v b/lf-current/Logic.v index 45a72432..9667f778 100644 --- a/lf-current/Logic.v +++ b/lf-current/Logic.v @@ -107,7 +107,6 @@ Example and_example : 3 + 4 = 7 /\ 2 * 2 = 4. (** 证明合取的命题通常使用 [split] 策略。它会分别为语句的两部分生成两个子目标: *) Proof. - (* 课上已完成 *) split. - (* 3 + 4 = 7 *) reflexivity. - (* 2 + 2 = 4 *) reflexivity. @@ -133,7 +132,7 @@ Proof. - (* 2 + 2 = 4 *) reflexivity. Qed. -(** **** 练习:2 星 (and_exercise) *) +(** **** 练习:2 星, standard (and_exercise) *) Example and_exercise : forall n m : nat, n + m = 0 -> n = 0 /\ m = 0. Proof. @@ -203,7 +202,7 @@ Proof. intros P Q [HP HQ]. apply HP. Qed. -(** **** 练习:1 星, optional (proj2) *) +(** **** 练习:1 星, standard, optional (proj2) *) Lemma proj2 : forall P Q : Prop, P /\ Q -> Q. Proof. @@ -221,8 +220,9 @@ Proof. - (* left *) apply HQ. - (* right *) apply HP. Qed. -(** **** 练习:2 星 (and_assoc) *) -(** (在以下结合律的证明中,注意_'嵌套'_的 [intros] 模式是如何将 +(** **** 练习:2 星, standard (and_assoc) + + (在以下结合律的证明中,注意_'嵌套'_的 [intros] 模式是如何将 [H : P /\ (Q /\ R)] 拆分为 [HP : P]、[HQ : Q] 和 [HR : R] 的。 请从那里开始完成证明。) *) @@ -243,12 +243,12 @@ Check and. (** ** 析取 *) (** 另一个重要的联结词是_析取_,即两个命题的_'逻辑或'_:若 [A] 或 [B] - 二者之一为真,则 [A \/ B] 为真。(我们也可以写作 [or A B],其中 + 二者之一为真,则 [A \/ B] 为真。(这中中缀记法表示 [or A B],其中 [or : Prop -> Prop -> Prop]。) *) (** 为了在证明中使用析取前提,我们需要分类讨论,它与 [nat] - 或其它数据类型一样,都可以通过 [destruct] 或 [intros] 来拆分。 - 下面就是个例子: *) + 或其它数据类型一样,都可以显示地通过 [destruct] 或隐式地通过 [intros] + 模式来拆分: *) Lemma or_example : forall n m : nat, n = 0 \/ m = 0 -> n * m = 0. @@ -274,7 +274,7 @@ Proof. apply HA. Qed. -(** ...而更有趣的例子则同时需要 [left] 和 [right]: *) +(** ...而这个更有趣的例子则同时需要 [left] 和 [right]: *) Lemma zero_or_succ : forall n : nat, n = 0 \/ n = S (pred n). @@ -285,14 +285,14 @@ Proof. - right. reflexivity. Qed. -(** **** 练习:1 星 (mult_eq_0) *) +(** **** 练习:1 星, standard (mult_eq_0) *) Lemma mult_eq_0 : forall n m, n * m = 0 -> n = 0 \/ m = 0. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (or_commut) *) +(** **** 练习:1 星, standard (or_commut) *) Theorem or_commut : forall P Q : Prop, P \/ Q -> Q \/ P. Proof. @@ -300,16 +300,19 @@ Proof. (** [] *) (* ================================================================= *) -(** ** 假命题与否定 *) -(** 目前为止,我们主要都在证明某些东西是_'真'_的:加法满足结合律, +(** ** 假命题与否定 + + 目前为止,我们主要都在证明某些东西是_'真'_的:加法满足结合律, 列表的连接满足结合律,等等。当然,我们也关心_'否定'_的结果, - 即证明某些命题_'不是'_真的。在 Coq 中,这样的否定语句使用否定运算符 + 即证明某些给定的命题_'不是'_真的。在 Coq 中,这样的否定语句使用否定运算符 [~] 来表达。 *) -(** 为了理解否定背后的原理,我们需要回想一下[Tactics]一章中对_'爆炸原理'_的讨论。 - 爆炸原理断言,当我们假设了矛盾存在时,就能推出任何命题。遵循这一直觉, - 我们可以可以将 [~ P](即非 [P])定义为 [forall Q, P -> Q]。 - 不过 Coq 选择了稍有些不同的做法,它将 [~ P] 定义为 [P -> False],而 +(** 为了理解否定背后的原理,我们需要回想一下[Tactics]一章中的_'爆炸原理'_。 + 爆炸原理断言,当我们假设了矛盾存在时,就能推出任何命题。 + + 遵循这一直觉,我们可以可以将 [~ P](即非 [P])定义为 [forall Q, P -> Q]。 + + 不过 Coq 选择了稍有些不同(但等价)的做法,它将 [~ P] 定义为 [P -> False],而 [False] 是在标准库中特别定义的矛盾性命题。 *) Module MyNot. @@ -324,8 +327,7 @@ Check not. End MyNot. (** 由于 [False] 是个矛盾性命题,因此爆炸原理对它也适用。如果我们让 [False] - 进入到了证明的上下文中,可以对它使用 [destruct](或 [discriminate]) - 来完成任何待证目标。 *) + 进入到了证明的上下文中,可以对它使用 [destruct] 来完成任何待证目标。 *) Theorem ex_falso_quodlibet : forall (P:Prop), False -> P. @@ -337,8 +339,9 @@ Proof. (** 拉丁文 _'ex falso quodlibet'_ 的字面意思是“从谬误出发, 你能够证明任何你想要的”,这也是爆炸原理的另一个广为人知的名字。 *) -(** **** 练习:2 星, optional (not_implies_our_not) *) -(** 证明 Coq 对否定的定义蕴含前面提到的直觉上的定义: *) +(** **** 练习:2 星, standard, optional (not_implies_our_not) + + 证明 Coq 对否定的定义蕴含前面提到的直觉上的定义: *) Fact not_implies_our_not : forall (P:Prop), ~ P -> (forall (Q:Prop), P -> Q). @@ -346,21 +349,24 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** 下面我们用 [not] 陈述了 [0] 和 [1] 是不同的 [nat] 元素: *) +(** 不等性是十分常见的否定句的例子,,它有一个特别的记法 [x <> y]: -Theorem zero_not_one : ~(0 = 1). -Proof. - intros contra. discriminate contra. -Qed. + Notation "x <> y" := (~(x = y)). +*) -(** 这样的不等性表述频繁出现,足以让我们为其定义一种特殊的记法 [x <> y]: *) +(** 我们可以用 [not] 来陈述 [0] 和 [1] 是不同的 [nat] 元素: *) -Check (0 <> 1). -(* ===> Prop *) - -Theorem zero_not_one' : 0 <> 1. +Theorem zero_not_one : 0 <> 1. Proof. - intros H. discriminate H. + (** 性质 [0 <> 1] 就是 [~(0 = 1)],即 [not (0 = 1)], + 它会展开为 [(0 = 1) -> False]。(这里显式地用 [unfold not] + 展示了这一点,不过一般可以忽略。 *) + unfold not. + (** 要证明不等性,我们可以反过来假设其相等... *) + intros contra. + (** ... 然后从中推出矛盾。在这里,等式 [O = S O] 与构造子 [O] 和 [S] + 的不交性相矛盾,因此用 [discriminate] 就能解决它。 *) + discriminate contra. Qed. (** 为了习惯用 Coq 处理否定命题,我们需要一些练习。 @@ -385,8 +391,9 @@ Proof. (* 课上已完成 *) intros P H. unfold not. intros G. apply G. apply H. Qed. -(** **** 练习:2 星, advanced (double_neg_inf) *) -(** 请写出 [double_neg] 的非形式化证明: +(** **** 练习:2 星, advanced (double_neg_inf) + + 请写出 [double_neg] 的非形式化证明: _'定理'_:对于任何命题 [P] 而言,[P] 蕴含 [~~P]。 *) @@ -396,22 +403,23 @@ Proof. Definition manual_grade_for_double_neg_inf : option (nat*string) := None. (** [] *) -(** **** 练习:2 星, recommended (contrapositive) *) +(** **** 练习:2 星, standard, recommended (contrapositive) *) Theorem contrapositive : forall (P Q : Prop), (P -> Q) -> (~Q -> ~P). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (not_both_true_and_false) *) +(** **** 练习:1 星, standard (not_both_true_and_false) *) Theorem not_both_true_and_false : forall P : Prop, ~ (P /\ ~P). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星, advanced (informal_not_PNP) *) -(** 请写出 [forall P : Prop, ~(P /\ ~P)] 的非形式化证明。 *) +(** **** 练习:1 星, advanced (informal_not_PNP) + + 请写出 [forall P : Prop, ~(P /\ ~P)] 的非形式化证明。 *) (* 请在此处解答 *) @@ -461,8 +469,9 @@ Lemma True_is_true : True. Proof. apply I. Qed. (** 与经常使用的 [False] 不同,[True] 很少使用,因为它作为证明目标来说过于平凡, - 而作为前提又不携带任何有用的信息。 *) -(** 然而在使用条件从句定义复杂的 [Prop],或者作为高阶 [Prop] 的参数时, + 而作为前提又不携带任何有用的信息。 + + 然而在使用条件从句定义复杂的 [Prop],或者作为高阶 [Prop] 的参数时, 它还是挺有用的。之后我们会看到 [True] 的这类用法。 *) (* ================================================================= *) @@ -500,8 +509,9 @@ Proof. intros H. rewrite H. intros H'. discriminate H'. Qed. -(** **** 练习:1 星, optional (iff_properties) *) -(** 参照上面对 [<->] 对称性([iff_sym])的证明, +(** **** 练习:1 星, standard, optional (iff_properties) + + 参照上面对 [<->] 对称性([iff_sym])的证明, 请证明它同时也有自反性和传递性。 *) Theorem iff_refl : forall P : Prop, @@ -515,7 +525,7 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (or_distributes_over_and) *) +(** **** 练习:3 星, standard (or_distributes_over_and) *) Theorem or_distributes_over_and : forall P Q R : Prop, P \/ (Q /\ R) <-> (P \/ Q) /\ (P \/ R). Proof. @@ -526,7 +536,7 @@ Proof. 特别来说,[rewrite] 和 [reflexivity] 不仅可以用于相等关系,还可用于 [iff] 语句。为了开启此行为,我们需要导入一个 Coq 的库来支持它: *) -Require Import Coq.Setoids.Setoid. +From Coq Require Import Setoids.Setoid. (** 下面是一个简单的例子,它展示了这些策略如何使用 [iff]。 首先,我们来证明一些基本的 [iff] 等价关系命题... *) @@ -603,8 +613,9 @@ Proof. exists (2 + m). apply Hm. Qed. -(** **** 练习:1 星, recommended (dist_not_exists) *) -(** 请证明“[P] 对所有 [x] 成立”蕴含“不存在 [x] 使 [P] 不成立。” +(** **** 练习:1 星, standard, recommended (dist_not_exists) + + 请证明“[P] 对所有 [x] 成立”蕴含“不存在 [x] 使 [P] 不成立。” (提示:[destruct H as [x E]] 可以用于存在假设!) *) Theorem dist_not_exists : forall (X:Type) (P : X -> Prop), @@ -613,8 +624,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星 (dist_exists_or) *) -(** 请证明存在量化对析取满足分配律。 *) +(** **** 练习:2 星, standard (dist_exists_or) + + 请证明存在量化对析取满足分配律。 *) Theorem dist_exists_or : forall (X:Type) (P Q : X -> Prop), (exists x, P x \/ Q x) <-> (exists x, P x) \/ (exists x, Q x). @@ -627,10 +639,12 @@ Proof. (** 我们学过的逻辑联结词为我们提供了丰富的用简单命题构造复杂命题的词汇。 为了说明,我们来看一下如何表达“元素 [x] 出现在列表 [l] 中”这一断言。 - 注意此性质有着简单的递归结构: *) -(** - 若 [l] 为空列表,则 [x] 无法在其中出现,因此性质“[x] 出现在 [l] 中” - 为假。 *) -(** - 否则,若 [l] 的形式为 [x' :: l'],此时 [x] 是否出现在 [l] 中, + 注意此性质有着简单的递归结构: + + - 若 [l] 为空列表,则 [x] 无法在其中出现,因此性质“[x] 出现在 [l] 中” + 为假。 + + - 否则,若 [l] 的形式为 [x' :: l'],此时 [x] 是否出现在 [l] 中, 取决于它是否等于 [x'] 或出现在 [l'] 中。 *) (** 我们可以将此定义直接翻译成递归函数,它接受一个元素和一个列表, @@ -687,7 +701,7 @@ Qed. “明显会终止”的。在下一章中,我们会了解如何_'归纳地'_定义命题, 这是一种与之不同的技巧,有着其独特的优势和限制。 *) -(** **** 练习:2 星 (In_map_iff) *) +(** **** 练习:2 星, standard (In_map_iff) *) Lemma In_map_iff : forall (A B : Type) (f : A -> B) (l : list A) (y : B), In y (map f l) <-> @@ -696,15 +710,16 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星 (In_app_iff) *) +(** **** 练习:2 星, standard (In_app_iff) *) Lemma In_app_iff : forall A l l' (a:A), In a (l++l') <-> In a l \/ In a l'. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, recommended (All) *) -(** 回忆一下,返回命题的函数可以视作对其参数_'性质'_的定义。例如,若 +(** **** 练习:3 星, standard, recommended (All) + + 回忆一下,返回命题的函数可以视作对其参数_'性质'_的定义。例如,若 [P] 的类型为 [nat -> Prop],那么 [P n] 就陈述了性质 [P] 对 [n] 成立。 以 [In] 作为参考,请写出递归函数 [All],它陈述某个 [P] 对列表 [l] @@ -722,8 +737,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (combine_odd_even) *) -(** 完成以下 [combine_odd_even] 函数的定义。它接受两个对数字成立的性质 +(** **** 练习:3 星, standard (combine_odd_even) + + 完成以下 [combine_odd_even] 函数的定义。它接受两个对数字成立的性质 [Podd] 与 [Peven],返回性质 [P] 使得当 [n] 为奇数时 [P n] 等价于 [Podd n], 否则等价于 [Peven n]。*) @@ -760,9 +776,10 @@ Proof. (* ################################################################# *) (** * 对参数应用定理 *) -(** Coq 拥有一个不同于其它证明助理的特性,即它将_'证明'_本身也作为一等对象。 +(** Coq 拥有一个不同于其它的证明助理(如 ACL2 和 Isabelle)的特性, + 即它将_'证明'_本身也作为一等对象。 - 关于这一点有很多地方值得着墨,不过详细了解它对于使用 Coq 来说不是必须的。 + 关于这一点有很多地方值得着墨,不过了解所有的细节对于使用 Coq 来说不是必须的。 本节点到为止,深入的探讨参见 [ProofObjects] 和 [IndPrinciples]。 *) (** 我们已经知道 [Check] 可以用来显式表达式的类型了, @@ -794,6 +811,7 @@ Lemma plus_comm3 : 然而问题是,第二次 [rewrite] 会抵消第一次的效果。 *) Proof. + (* 课上已完成 *) intros x y z. rewrite plus_comm. rewrite plus_comm. @@ -826,9 +844,69 @@ Proof. reflexivity. Qed. +(** 我们来展示另一个像函数那样使用定理或引理的例子。以下定理说明: + 任何包含元素的列表 [l] 一定非空。 *) + +Lemma in_not_nil : + forall A (x : A) (l : list A), In x l -> l <> []. +Proof. + intros A x l H. unfold not. intro Hl. destruct l. + - simpl in H. destruct H. + - discriminate Hl. +Qed. + +(** 有趣的地方是一个量化的变量([x])没有出现在结论([l <> []])中。 *) + +(** 我们可以用此引理来证明 [x] 为 [42] 的特殊情况。直接用 [apply in_not_nil] + 会失败,因为它无法推出 [x] 的值。有一些方法可以绕开它... *) + +Lemma in_not_nil_42 : + forall l : list nat, In 42 l -> l <> []. +Proof. + (* 课上已完成 *) + intros l H. + Fail apply in_not_nil. +Abort. + +(* [apply ... with ...] *) +Lemma in_not_nil_42_take2 : + forall l : list nat, In 42 l -> l <> []. +Proof. + intros l H. + apply in_not_nil with (x := 42). + apply H. +Qed. + +(* [apply ... in ...] *) +Lemma in_not_nil_42_take3 : + forall l : list nat, In 42 l -> l <> []. +Proof. + intros l H. + apply in_not_nil in H. + apply H. +Qed. + +(* 显式地对 [x] 的值应用引理。 *) +Lemma in_not_nil_42_take4 : + forall l : list nat, In 42 l -> l <> []. +Proof. + intros l H. + apply (in_not_nil nat 42). + apply H. +Qed. + +(* 显式地对假设应用引理。 *) +Lemma in_not_nil_42_take5 : + forall l : list nat, In 42 l -> l <> []. +Proof. + intros l H. + apply (in_not_nil _ _ _ H). +Qed. + (** 对于几乎所有将定理名作为参数的策略而言,你都可以“将定理作为函数”来使用。 注意,定理应用与函数应用使用了同样的类型推导机制,所以你可以将通配符作为定理的参数, - 或者为定理声明默认的隐式前提。这些特性在以下证明中展示。 *) + 或者为定理声明默认的隐式前提。这些特性在以下证明中展示。(此证明如何工作的细节 + 不必关心,这里的目标只是为了展示它的用途。) *) Example lemma_application_ex : forall {n : nat} {ns : list nat}, @@ -852,7 +930,7 @@ Qed. 一个数学对象可同时属于不同的集合;而在 Coq 的逻辑中,一个项最多只属于一个类型。 这些不同之处需要人们用稍微不同的方式来描述非形式化的数学概念,但总的来说, 它们都是非常自然而易于使用的。例如,在 Coq 中我们一般不说某个自然数 [n] - 属于偶数集合,而是说 [ev n] 成立,其中的 [ev : nat -> Prop] 描述了偶数的性质。 + 属于偶数集合,而是说 [even n] 成立,其中的 [even : nat -> Prop] 描述了偶数的性质。 然而在某些情况下,将标准的数学论证翻译到 Coq 中会十分繁琐甚至是不可能的, 除非我们引入新的公理来丰富其逻辑核心。作为本章的结尾, @@ -865,7 +943,8 @@ Qed. (如 [nat]、[bool] 等等)。然而由于 Coq 的相等关系运算符是多态的, 因此它们并不是唯一的可能。特别是,我们可以写出宣称_'两个函数相等'_的命题: *) -Example function_equality_ex1 : plus 3 = plus (pred 4). +Example function_equality_ex1 : + (fun x => 3 + x) = (fun x => (pred 4) + x). Proof. reflexivity. Qed. (** 在一般的数学研究中,对于任意的两个函数 [f] 和 [g],只要它们产生的结果相等, @@ -884,7 +963,7 @@ Proof. reflexivity. Qed. Example function_equality_ex2 : (fun x => plus x 1) = (fun x => plus 1 x). Proof. - (* Stuck *) + (* 卡住了 *) Abort. (** 然而,我们可以用 [Axiom] 指令将函数的外延性添加到 Coq 的核心逻辑系统中。 *) @@ -906,10 +985,11 @@ Proof. Qed. (** 当然,在为 Coq 添加公理时必须十分小心,因为这有可能会导致系统 - _'不一致'_,而当系统不一致的,任何命题都能在其中证明,包括 [False]! + _'不一致'_,而当系统不一致的,任何命题都能在其中证明,包括 [False] + 和 [2+2=5]! 不幸的是,并没有一种简单的方式能够判断添加某条公理是否安全: - 一般来说,确认任何一组公理的一致性都需要付出艰辛的努力。 + 一般来说,确认任何一组公理的一致性都需要训练有素的专家付出艰辛的努力。 然而,我们已经知道了添加函数外延性后的公理系统_'确实是'_一致的。 *) @@ -922,8 +1002,9 @@ Print Assumptions function_equality_ex2. forall (X Y : Type) (f g : X -> Y), (forall x : X, f x = g x) -> f = g *) -(** **** 练习:4 星 (tr_rev_correct) *) -(** 列表反转函数 [rev] 的定义有一个问题,它会在每一步都执行一次 [app] +(** **** 练习:4 星, standard (tr_rev_correct) + + 列表反转函数 [rev] 的定义有一个问题,它会在每一步都执行一次 [app] 调用,而运行 [app] 所需时间与列表的大小线性渐近,也就是说 [rev] 的时间复杂度与列表长度成平方关系。我们可以用以下定义来改进它: *) @@ -950,13 +1031,18 @@ Lemma tr_rev_correct : forall X, @tr_rev X = @rev X. (** 我们已经知道在 Coq 中有两种编码逻辑事实的方式了,即使用_'布尔值'_ (类型为 [bool])和_'命题'_(类型为 [Prop])。 - 例如,我们可以通过以下两种方式来断言 [n] 为偶数: - - (1) [evenb n] 返回 [true],或者 - - (2) 存在某个 [k] 使得 [n = double k]。 - 这两种对偶数的定义确实是等价的,我们可以通过一些辅助引理来证明它。 + 例如,我们可以通过以下两种方式来断言 [n] 为偶数: *) + +(** [evenb n] 求值为 [true]: *) +Example even_42_bool : evenb 42 = true. +Proof. reflexivity. Qed. + +(** 或者存在某个 [k] 使得 [n = double k]: *) +Example even_42_prop : exists k, 42 = double k. +Proof. exists 21. reflexivity. Qed. - 当然,如果二者对偶数的刻画描述的并是不同一个自然数集,那会非常奇怪! - 幸运的是,我们可以证明二者确实等价... *) +(** 当然,如果二者刻画的偶数性描述的不是同一个自然数集合,那么会非常奇怪! + 幸运的是,我们确实可以证明二者相同... *) (** 首先我们需要两个辅助引理。 *) Theorem evenb_double : forall k, evenb (double k) = true. @@ -966,7 +1052,7 @@ Proof. - simpl. apply IHk'. Qed. -(** **** 练习:3 星 (evenb_double_conv) *) +(** **** 练习:3 星, standard (evenb_double_conv) *) Theorem evenb_double_conv : forall n, exists k, n = if evenb n then double k else S (double k). @@ -987,9 +1073,10 @@ Qed. (** 此定理说明,逻辑命题 [exists k, n = double k] 的真伪对应布尔计算 [evenb n] 的真值。 *) -(** 类似地,以下两种描述 [n] 与 [m] 相等的表达方式等价: - (一)[n =? m] 值为 [true]; - (二)[n = m]。 *) +(** 类似地,以下两种 [n] 与 [m] 相等的表述等价: + - (1) [n =? m] 值为 [true]; + - (2) [n = m]。 + 同样,二者的记法也等价。 *) Theorem eqb_eq : forall n1 n2 : nat, n1 =? n2 = true <-> n1 = n2. @@ -1000,17 +1087,13 @@ Proof. Qed. (** 然而,即便布尔值和某个断言的命题式在逻辑上是等价的,但它们在_'操作上'_ - 并不一样。 - - 相等关系就是一个极端的例子:就涉及 [n] 和 [m] 的证明的中间步骤而言, - 知道 [n =? m = true] 通常没什么帮助。然而,如果我们可以将此陈述 - 转换成 [n = m] 的形式,就能用它来改写证明。 *) + 也可能不一样。 *) -(** 偶数也是个有趣的例子。回想一下,在证明 [even_bool_prop] - 的反向部分(即 [evenb_double],从命题到布尔表达式的方向)时,我们对 +(** 在前面的偶数例子中,证明 [even_bool_prop] 的反向部分(即 + [evenb_double],从命题到布尔表达式的方向)时,我们对 [k] 进行了简单的归纳。而反方向的证明(即练习 [evenb_double_conv]) - 则需要一种聪明的一般化方法,因为我们无法直接证明 [(exists k, n = - double k) -> evenb n = true]。 *) + 则需要一种聪明的一般化方法,因为我们无法直接证明 + [(exists k, n = double k) -> evenb n = true]。 *) (** 对于这些例子来说,命题式的声明比与之对应的布尔表达式要更为有用, 但并非总是如此。例如,我们无法在函数的定义中测试一般的命题是否为真, @@ -1055,14 +1138,53 @@ Proof. reflexivity. Qed. Example even_1000'' : exists k, 1000 = double k. Proof. apply even_bool_prop. reflexivity. Qed. -(** 尽管此例的证明的长度并未因此而减少,然而更大的证明通常可通过 +(** 尽管此例的证明脚本的长度并未因此而减少,然而更大的证明通常可通过 这种互映的方式来显著化简。举一个极端的例子,在用 Coq 证明著名的 - _'四色定理'_时,人们使用互映技巧将几百种不同的情况归约成了一个布尔计算。 - 我们不会详细地介绍互映技巧,然而对于展示布尔计算与一般命题的互补优势而言, + _'四色定理'_时,人们使用互映技巧将几百种不同的情况归约成了一个布尔计算。 *) + +(** 另一点明显的不同是“布尔事实”的否定可以被直白地陈述并证明, + 只需翻转预期的布尔值结果即可。 *) + +Example not_even_1001 : evenb 1001 = false. +Proof. + (* 课上已完成 *) + reflexivity. +Qed. + +(** 相反,命题的否定形式可能更难以掌握。 *) + +Example not_even_1001' : ~(exists k, 1001 = double k). +Proof. + (* 课上已完成 *) + rewrite <- even_bool_prop. + unfold not. + simpl. + intro H. + discriminate H. +Qed. + +(** 相等性补充了另一个例子。在涉及 [n] 和 [m] 的证明中,知道 [n =? m = true] + 通常会有一点直接的帮助。然而如果我们将该语句转换为等价的 [n = m] 形式, + 那么我们可以对它进行改写。 + *) + +Lemma plus_eqb_example : forall n m p : nat, + n =? m = true -> n + p =? m + p = true. +Proof. + (* 课上已完成 *) + intros n m p H. + rewrite eqb_eq in H. + rewrite H. + rewrite eqb_eq. + reflexivity. +Qed. + +(** 我们不会详细地介绍互映技巧,然而对于展示布尔计算与一般命题的互补优势而言, 它是个很好的例子。 *) -(** **** 练习:2 星 (logical_connectives) *) -(** 以下引理将本章中讨论的命题联结词与对应的布尔操作关联了起来。 *) +(** **** 练习:2 星, standard (logical_connectives) + + 以下引理将本章中讨论的命题联结词与对应的布尔操作关联了起来。 *) Lemma andb_true_iff : forall b1 b2:bool, b1 && b2 = true <-> b1 = true /\ b2 = true. @@ -1075,8 +1197,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (eqb_neq) *) -(** 以下定理为等价式 [eqb_eq] 的“否定”版本, +(** **** 练习:1 星, standard (eqb_neq) + + 以下定理为等价式 [eqb_eq] 的“否定”版本, 在某些场景中使用它会更方便些(后面的章节中会讲到这方面的例子)。 *) Theorem eqb_neq : forall x y : nat, @@ -1085,8 +1208,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (eqb_list) *) -(** 给定一个用于测试类型为 [A] 的元素相等关系的布尔操作符 [eqb], +(** **** 练习:3 星, standard (eqb_list) + + 给定一个用于测试类型为 [A] 的元素相等关系的布尔操作符 [eqb], 我们可以定义函数 [eqb_list] 来测试元素类型为 [A] 的列表的相等关系。 请完成以下 [eqb_list] 函数的定义。要确定你的定义是否正确,请证明引理 [eqb_list_true_iff]。 *) @@ -1103,8 +1227,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, recommended (All_forallb) *) -(** 回忆一下[Tactics]一章中练习 [forall_exists_challenge] 的函数 +(** **** 练习:2 星, standard, recommended (All_forallb) + + 回忆一下[Tactics]一章中练习 [forall_exists_challenge] 的函数 [forallb]: *) Fixpoint forallb {X : Type} (test : X -> bool) (l : list X) : bool := @@ -1122,8 +1247,9 @@ Proof. (** 函数 [forallb] 是否还存在尚未被此规范捕获的重要性质? *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ================================================================= *) (** ** 经典逻辑 vs. 构造逻辑 *) @@ -1204,8 +1330,9 @@ Qed. 允许自己从任意陈述中去掉双重否定等价于引入排中律。因此,只要我们不引入排中律, 就无法在 Coq 中编码此推理。 *) -(** **** 练习:3 星 (excluded_middle_irrefutable) *) -(** 证明通用排中律公理与 Coq 的一致性需要复杂的推理,而且并不能在 Coq +(** **** 练习:3 星, standard (excluded_middle_irrefutable) + + 证明通用排中律公理与 Coq 的一致性需要复杂的推理,而且并不能在 Coq 自身中进行。然而,以下定理蕴含了假设可判定性公理(即排中律的一个特例) 成立对于任何_'具体的'_命题 [P] 而言总是安全的。之所以如此, 是因为我们无法证明这类公理的否定命题。假如我们可以的话,就会同时有 @@ -1218,8 +1345,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, advanced (not_exists_dist) *) -(** 在经典逻辑中有这样一条定理,它断言以下两条命题是等价的: +(** **** 练习:3 星, advanced (not_exists_dist) + + 在经典逻辑中有这样一条定理,它断言以下两条命题是等价的: ~ (exists x, ~ P x) forall x, P x @@ -1235,8 +1363,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:5 星, optional (classical_axioms) *) -(** 对于喜欢挑战的读者,以下练习来自于 Bertot 与 Casteran 所著的 +(** **** 练习:5 星, standard, optional (classical_axioms) + + 对于喜欢挑战的读者,以下练习来自于 Bertot 与 Casteran 所著的 Coq'Art 一书中第 123 页。以下四条陈述的每一条,加上 [excluded_middle] 可以认为刻画了经典逻辑。我们无法在 Coq 中证明其中的任意一条, 不过如果我们希望在经典逻辑下工作的话,可以安全地将其中任意一条作为公理添加到 @@ -1256,6 +1385,8 @@ Definition de_morgan_not_and_not := forall P Q:Prop, Definition implies_to_or := forall P Q:Prop, (P->Q) -> (~P\/Q). -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) +(* Sat Jan 26 15:14:45 UTC 2019 *) diff --git a/lf-current/LogicTest.v b/lf-current/LogicTest.v index c0d768d8..5856ab32 100644 --- a/lf-current/LogicTest.v +++ b/lf-current/LogicTest.v @@ -389,3 +389,5 @@ idtac "MANUAL". idtac "---------- not_exists_dist ---------". Print Assumptions not_exists_dist. Abort. + +(* Sat Jan 26 15:14:52 UTC 2019 *) diff --git a/lf-current/Makefile b/lf-current/Makefile index b28e665f..0824765c 100644 --- a/lf-current/Makefile +++ b/lf-current/Makefile @@ -797,4 +797,3 @@ debug: .PHONY: debug .DEFAULT_GOAL := all -include .depend diff --git a/lf-current/Maps.html b/lf-current/Maps.html index 9f5f4beb..80668822 100644 --- a/lf-current/Maps.html +++ b/lf-current/Maps.html @@ -49,7 +49,7 @@
+Theorem forallb_true_iff : ∀X test (l : list X),
forallb test l = true ↔ All (fun x ⇒ test x = true) l.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1599,7 +1763,7 @@LogicCoq 中的逻辑系统
-Definition excluded_middle := ∀ P : Prop,
- P ∨ ¬ P.
+Definition excluded_middle := ∀P : Prop,
+ P ∨ ¬P.
@@ -1626,8 +1790,8 @@LogicCoq 中的逻辑系统
-Theorem restricted_excluded_middle : ∀ P b,
- (P ↔ b = true) → P ∨ ¬ P.
+Theorem restricted_excluded_middle : ∀P b,
+ (P ↔ b = true) → P ∨ ¬P.
Proof.
intros P [] H.
- left. rewrite H. reflexivity.
@@ -1640,7 +1804,7 @@LogicCoq 中的逻辑系统
-Theorem restricted_excluded_middle_eq : ∀ (n m : nat),
+Theorem restricted_excluded_middle_eq : ∀(n m : nat),
n = m ∨ n ≠ m.
Proof.
intros n m.
@@ -1654,7 +1818,7 @@LogicCoq 中的逻辑系统 通用的排中律默认在 Coq 中并不可用,这一点或许很奇怪,毕竟, 任何给定的断言都是非真即假的。尽管如此,不假设排中律的成立仍有其有限: Coq 中的陈述可以构造出比标准数学中同样陈述更强的断言。特别是, - 如果存在 ∃x, P x 的 Coq 证明,那么我们就能直接给出一个使 P x + 如果存在 ∃ x, P x 的 Coq 证明,那么我们就能直接给出一个使 P x 得证的值 x。换言之,任何关于存在性的证明必定是构造性的。
@@ -1697,19 +1861,19 @@LogicCoq 中的逻辑系统 我们需要一定的实践才能理解哪些证明技巧不应在构造推理中使用, 而其中的反证法尤为臭名昭著,因为它会导向非构造性证明。这里有个典型的例子: 假设我们想要证明存在 x 具有某种性质 P,即存在 P x。我们先假设结论为假, - 也就是说 ¬ ∃x, P x。根据此前提,不难推出 ∀x, ¬ P x。 + 也就是说 ¬ ∃ x, P x。根据此前提,不难推出 ∀ x, ¬ P x。 如果我们能够根据此中间事实得到矛盾,就能得到一个存在性证明而完全不必指出一个 x 的值使得 P x 成立!
从构造性的角度来看,这里存在着技术上的瑕疵,即我们试图通过对 - ¬ ¬ (∃x, P x) 的证明来证明 ∃x, P x。从以下练习中我们会看到, + ¬ ¬ (∃ x, P x) 的证明来证明 ∃ x, P x。从以下练习中我们会看到, 允许自己从任意陈述中去掉双重否定等价于引入排中律。因此,只要我们不引入排中律, 就无法在 Coq 中编码此推理。-练习:3 星 (excluded_middle_irrefutable)
+练习:3 星, standard (excluded_middle_irrefutable)
证明通用排中律公理与 Coq 的一致性需要复杂的推理,而且并不能在 Coq 自身中进行。然而,以下定理蕴含了假设可判定性公理(即排中律的一个特例) 成立对于任何具体的命题 P 而言总是安全的。之所以如此, @@ -1719,8 +1883,8 @@LogicCoq 中的逻辑系统
-Theorem excluded_middle_irrefutable: ∀ (P:Prop),@@ -1729,14 +1893,14 @@
- ¬ ¬ (P ∨ ¬ P).
+Theorem excluded_middle_irrefutable: ∀(P:Prop),
+ ¬¬(P ∨ ¬P).
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
@@ -1757,7 +1921,7 @@-练习:3 星, advanced (not_exists_dist)
+练习:3 星, advanced (not_exists_dist)
在经典逻辑中有这样一条定理,它断言以下两条命题是等价的:- ¬ (∃ x, ¬ P x)@@ -1747,8 +1911,8 @@
- ∀ x, P x + ¬(∃x, ¬P x)
+ ∀x, P xLogicCoq 中的逻辑系统 Theorem not_exists_dist :
excluded_middle →
- ∀ (X:Type) (P : X → Prop),
- ¬ (∃ x, ¬ P x) → (∀ x, P x).
+ ∀(X:Type) (P : X → Prop),
+ ¬(∃x, ¬P x) → (∀x, P x).
Proof.
(* 请在此处解答 *) Admitted.
LogicCoq 中的逻辑系统
-练习:5 星, optional (classical_axioms)
+练习:5 星, standard, optional (classical_axioms)
对于喜欢挑战的读者,以下练习来自于 Bertot 与 Casteran 所著的 Coq'Art 一书中第 123 页。以下四条陈述的每一条,加上 excluded_middle 可以认为刻画了经典逻辑。我们无法在 Coq 中证明其中的任意一条, @@ -1770,18 +1934,22 @@LogicCoq 中的逻辑系统
-Definition peirce := ∀ P Q: Prop,☐ +
+Definition peirce := ∀P Q: Prop,
((P→Q)→P)→P.
-Definition double_negation_elimination := ∀ P:Prop,
+Definition double_negation_elimination := ∀P:Prop,
~~P → P.
-Definition de_morgan_not_and_not := ∀ P Q:Prop,
+Definition de_morgan_not_and_not := ∀P Q:Prop,
~(~P ∧ ¬Q) → P∨Q.
-Definition implies_to_or := ∀ P Q:Prop,
+Definition implies_to_or := ∀P Q:Prop,
(P→Q) → (¬P∨Q).
(* 请在此处解答 *)
+ +(* Sat Jan 26 15:14:45 UTC 2019 *)
+Maps全映射与偏映射
-Coq 标准库
+Coq 标准库
@@ -65,11 +65,11 @@Maps全映射与偏映射
-Require Import Coq.Arith.Arith.@@ -83,23 +83,21 @@
-Require Import Coq.Bool.Bool.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Bool.Bool.
Require Export Coq.Strings.String.
-Require Import Coq.Logic.FunctionalExtensionality.
-Require Import Coq.Lists.List.
+From Coq Require Import Logic.FunctionalExtensionality.
+From Coq Require Import Lists.List.
Import ListNotations.
Maps全映射与偏映射
-标识符
+标识符
- First, we need a type for the keys that we use to index into our - maps. In Lists.v we introduced a fresh type id for this - purpose; for the rest of _Software Foundations_ we will use the - string type from Coq's standard library. + 首先我们需要键的类型来对映射进行索引。在 Lists.v 中, + 我们为类似的目的引入了 id 类型。而在《软件基础》后面的部分, + 我们会使用 Coq 标准库中的 string 类型。- To compare strings, we define the function eqb_string, which - internally uses the function string_dec from Coq's string - library. + 为了比较字符串,我们定义了 eqb_string 函数,它在内部使用 Coq + 字符串库中的 string_dec 函数。-Definition eqb_string x y :=@@ -113,10 +111,10 @@
+Definition eqb_string (x y : string) : bool :=
if string_dec x y then true else false.
Maps全映射与偏映射
bool。)- Now we need a few basic properties of string equality... + 现在我们需要一些关于字符串相等性的基本性质...-Theorem eqb_string_refl : ∀ s, true = eqb_string s s.
+Theorem eqb_string_refl : ∀s : string, true = eqb_string s s.
Proof. intros s. unfold eqb_string. destruct (string_dec s s) as [|Hs].
@@ -127,13 +125,12 @@Maps全映射与偏映射
-The following useful property follows from an analogous - lemma about strings: +以下有用的性质可由类似的字符串引理推出:-Theorem eqb_string_true_iff : ∀ x y : string,
- eqb_string x y = true ↔ x = y.
+Theorem eqb_string_true_iff : ∀x y : string,
+ eqb_string x y = true ↔ x = y.
Proof.
@@ -153,9 +150,8 @@Maps全映射与偏映射
-Theorem eqb_string_false_iff : ∀ x y : string,
- eqb_string x y = false
- ↔ x ≠ y.
+Theorem eqb_string_false_iff : ∀x y : string,
+ eqb_string x y = false ↔ x ≠ y.
Proof.
@@ -165,11 +161,11 @@Maps全映射与偏映射
-This handy variant follows just by rewriting: +以下方便使用的变体只需通过改写就能得出:-Theorem false_eqb_string : ∀ x y : string,
+Theorem false_eqb_string : ∀x y : string,
x ≠ y → eqb_string x y = false.
@@ -180,7 +176,7 @@Maps全映射与偏映射
-全映射
+全映射
@@ -200,7 +196,7 @@Maps全映射与偏映射
-Definition total_map (A:Type) := string → A.
+Definition total_map (A : Type) := string → A.
@@ -213,7 +209,7 @@Maps全映射与偏映射
-Definition t_empty {A:Type} (v : A) : total_map A :=@@ -224,7 +220,7 @@
+Definition t_empty {A : Type} (v : A) : total_map A :=
(fun _ ⇒ v).
Maps全映射与偏映射
-Definition t_update {A:Type} (m : total_map A)@@ -251,30 +247,17 @@
+Definition t_update {A : Type} (m : total_map A)
(x : string) (v : A) :=
fun x' ⇒ if eqb_string x x' then v else m x'.
Maps全映射与偏映射
-Notation "{ --> d }" := (t_empty d) (at level 0).
+Notation "'_' '!->' v" := (t_empty v)
+ (at level 100, right associativity).
+Example example_empty := (_ !-> false).
然后,我们引入一种方便的记法,通过一些绑定来扩展现有的映射。 -- - (这种记法的定义有点丑,因为 Coq 的记法机制不太适应递归记法, - 这是我们能做到最好的了。)- -Notation "m '&' { a --> x }" :=
- (t_update m a x) (at level 20).
-Notation "m '&' { a --> x ; b --> y }" :=
- (t_update (m & { a --> x }) b y) (at level 20).
-Notation "m '&' { a --> x ; b --> y ; c --> z }" :=
- (t_update (m & { a --> x ; b --> y }) c z) (at level 20).
-Notation "m '&' { a --> x ; b --> y ; c --> z ; d --> t }" :=
- (t_update (m & { a --> x ; b --> y ; c --> z }) d t) (at level 20).
-Notation "m '&' { a --> x ; b --> y ; c --> z ; d --> t ; e --> u }" :=
- (t_update (m & { a --> x ; b --> y ; c --> z ; d --> t }) e u) (at level 20).
-Notation "m '&' { a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }" :=
- (t_update (m & { a --> x ; b --> y ; c --> z ; d --> t ; e --> u }) f v) (at level 20).
+Notation "x '!->' v ';' m" := (t_update m x v)
+ (at level 100, v at next level, right associativity).
@@ -283,7 +266,10 @@Maps全映射与偏映射
Definition examplemap' :=
- { --> false } & { "foo" --> true ; "bar" --> true }.
+ ( "bar" !-> true;
+ "foo" !-> true;
+ _ !-> false
+ ).
@@ -301,12 +287,13 @@Maps全映射与偏映射
Logic一节中讨论过它)。-练习:1 星, optional (t_apply_empty)
+练习:1 星, standard, optional (t_apply_empty)
首先,空映射对于所有的键都会返回默认元素(即,空映射总是返回默认元素):-Lemma t_apply_empty: ∀ (A:Type) (x: string) (v: A), { --> v } x = v.@@ -315,15 +302,15 @@
+Lemma t_apply_empty : ∀(A : Type) (x : string) (v : A),
+ (_ !-> v) x = v.
Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
-练习:2 星, optional (t_update_eq)
+练习:2 星, standard, optional (t_update_eq)
接着,如果将映射 m 的键 x 关联的值更新为 v,然后在 update 产生的新映射中查找 x,就会得到 v(即,更新某个键的映射, 查找它就会得到更新后的值):-Lemma t_update_eq : ∀ A (m: total_map A) x v,@@ -332,17 +319,16 @@
- (m & {x --> v}) x = v.
+Lemma t_update_eq : ∀(A : Type) (m : total_map A) x v,
+ (x !-> v ; m) x = v.
Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
-练习:2 星, optional (t_update_neq)
+练习:2 星, standard, optional (t_update_neq)
此外,如果将映射 m 的键 x1 更新后在返回的结果中查找另一个键 x2,那么得到的结果与在 m 中查找它的结果相同 (即,更新某个键的映射,不影响其它键的映射):-Theorem t_update_neq : ∀ (X:Type) v x1 x2@@ -351,15 +337,15 @@
- (m : total_map X),
- x1 ≠ x2 →
- (m & {x1 --> v}) x2 = m x2.
+Theorem t_update_neq : ∀(A : Type) (m : total_map A) x1 x2 v,
+ x1 ≠ x2 →
+ (x1 !-> v ; m) x2 = m x2.
Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
-练习:2 星, optional (t_update_shadow)
+练习:2 星, standard, optional (t_update_shadow)
如果将映射 m 的键 x 关联的值更新为 v1 后,又将同一个键 x 更新为另一个值 v2,那么产生的映射与仅将第二次 update 应用于 m 所得到的映射表现一致(即二者应用到同一键时产生的结果相同):-Lemma t_update_shadow : ∀ A (m: total_map A) v1 v2 x,@@ -373,12 +359,13 @@
- m & {x --> v1 ; x --> v2} = m & {x --> v2}.
+Lemma t_update_shadow : ∀(A : Type) (m : total_map A) x v1 v2,
+ (x !-> v2 ; x !-> v1 ; m) = (x !-> v2 ; m).
Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
id 上的相等关系命题与布尔函数 eqb_id 关联起来。-练习:2 星, optional (eqb_stringP)
+练习:2 星, standard, optional (eqb_stringP)
请仿照IndProp一章中对 eqb_natP 的证明来证明以下引理:-Lemma eqb_stringP : ∀ x y, reflect (x = y) (eqb_string x y).@@ -387,22 +374,22 @@
+Lemma eqb_stringP : ∀x y : string,
+ reflect (x = y) (eqb_string x y).
Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
- 现在,给定 string 类型的字符串 x1 和 x2,我们可以在使用 + 现在,给定 string 类型的字符串 x1 和 x2,我们可以在使用策略 destruct (eqb_stringP x1 x2) 对 eqb_string x1 x2 的结果进行分类讨论的同时,生成关于 x1 和 x2 (在 = 的意义上) 的相等关系前提。-练习:2 星 (t_update_same)
+练习:2 星, standard (t_update_same)
请仿照IndProp一章中的示例,用 eqb_stringP 来证明以下定理, 它陈述了:如果我们用映射 m 中已经与键 x 相关联的值更新了 x, 那么其结果与 m 相等:-Theorem t_update_same : ∀ X x (m : total_map X),@@ -410,17 +397,18 @@
- m & { x --> m x } = m.
- Proof.
+Theorem t_update_same : ∀(A : Type) (m : total_map A) x,
+ (x !-> m x ; m) = m.
+Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
-练习:3 星, recommended (t_update_permute)
+练习:3 星, standard, recommended (t_update_permute)
使用 eqb_stringP 来证明最后一个 update 函数的性质: 如果我们更新了映射 m 中两个不同的键,那么更新的顺序无关紧要。-Theorem t_update_permute : ∀ (X:Type) v1 v2 x1 x2@@ -428,7 +416,7 @@
- (m : total_map X),
- x2 ≠ x1 →
- m & { x2 --> v2 ; x1 --> v1 }
- = m & { x1 --> v1 ; x2 --> v2 }.
+Theorem t_update_permute : ∀(A : Type) (m : total_map A)
+ v1 v2 x1 x2,
+ x2 ≠ x1 →
+ (x1 !-> v1 ; x2 !-> v2 ; m)
+ =
+ (x2 !-> v2 ; x1 !-> v1 ; m).
Proof.
(* 请在此处解答 *) Admitted.
Maps全映射与偏映射
☐-偏映射
+偏映射
@@ -437,31 +425,30 @@Maps全映射与偏映射
-Definition partial_map (A:Type) := total_map (option A).
-Definition empty {A:Type} : partial_map A :=
+Definition partial_map (A : Type) := total_map (option A).
+Definition empty {A : Type} : partial_map A :=
t_empty None.
-Definition update {A:Type} (m : partial_map A)
+Definition update {A : Type} (m : partial_map A)
(x : string) (v : A) :=
- m & { x --> (Some v) }.
+ (x !-> Some v ; m).
-我们用双花括号为偏映射引入类似的记法。 +我们为偏映射引入类似的记法。+Notation "x '⊢>' v ';' m" := (update m x v)-Notation "m '&' {{ a --> x }}" :=
+ (at level 100, v at next level, right associativity).
+
- (update m a x) (at level 20).
-Notation "m '&' {{ a --> x ; b --> y }}" :=
- (update (m & {{ a --> x }}) b y) (at level 20).
-Notation "m '&' {{ a --> x ; b --> y ; c --> z }}" :=
- (update (m & {{ a --> x ; b --> y }}) c z) (at level 20).
-Notation "m '&' {{ a --> x ; b --> y ; c --> z ; d --> t }}" :=
- (update (m & {{ a --> x ; b --> y ; c --> z }}) d t) (at level 20).
-Notation "m '&' {{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }}" :=
- (update (m & {{ a --> x ; b --> y ; c --> z ; d --> t }}) e u) (at level 20).
-Notation "m '&' {{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }}" :=
- (update (m & {{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }}) f v) (at level 20).
++当最后一种情况为空时,我们也可以隐藏它。 +++Notation "x '⊢>' v" := (update empty x v)
+ (at level 100).
+Example examplepmap :=
+ ("Church" ⊢> true ; "Turing" ⊢> false).
@@ -469,7 +456,8 @@Maps全映射与偏映射
-Lemma apply_empty : ∀ (A: Type) (x: string), @empty A x = None.
+Lemma apply_empty : ∀(A : Type) (x : string),
+ @empty A x = None.
Proof.diff --git a/lf-current/Maps.v b/lf-current/Maps.v index 23ab3229..076a578a 100644 --- a/lf-current/Maps.v +++ b/lf-current/Maps.v @@ -20,11 +20,11 @@ 因为我们一直小心地将自己的定义和定理的命名与标准库中的部分保持一致, 无论它们在哪里重复。 *) -Require Import Coq.Arith.Arith. -Require Import Coq.Bool.Bool. +From Coq Require Import Arith.Arith. +From Coq Require Import Bool.Bool. Require Export Coq.Strings.String. -Require Import Coq.Logic.FunctionalExtensionality. -Require Import Coq.Lists.List. +From Coq Require Import Logic.FunctionalExtensionality. +From Coq Require Import Lists.List. Import ListNotations. (** 标准库的文档见 @@ -35,16 +35,14 @@ Import ListNotations. (* ################################################################# *) (** * 标识符 *) -(** First, we need a type for the keys that we use to index into our - maps. In [Lists.v] we introduced a fresh type [id] for this - purpose; for the rest of _Software Foundations_ we will use the - [string] type from Coq's standard library. *) +(** 首先我们需要键的类型来对映射进行索引。在 [Lists.v] 中, + 我们为类似的目的引入了 [id] 类型。而在_'《软件基础》'_后面的部分, + 我们会使用 Coq 标准库中的 [string] 类型。 *) -(** To compare strings, we define the function [eqb_string], which - internally uses the function [string_dec] from Coq's string - library. *) +(** 为了比较字符串,我们定义了 [eqb_string] 函数,它在内部使用 Coq + 字符串库中的 [string_dec] 函数。 *) -Definition eqb_string x y := +Definition eqb_string (x y : string) : bool := if string_dec x y then true else false. (** (函数 [string_dec] 来自于 Coq 的字符串标准库。如果你查看 @@ -55,18 +53,17 @@ Definition eqb_string x y := 与一个标签一起来指出具体是哪一个。不过就目前来说,你可以把它当做一个 花哨的 [bool]。) *) -(** Now we need a few basic properties of string equality... *) -Theorem eqb_string_refl : forall s, true = eqb_string s s. +(** 现在我们需要一些关于字符串相等性的基本性质... *) +Theorem eqb_string_refl : forall s : string, true = eqb_string s s. Proof. intros s. unfold eqb_string. destruct (string_dec s s) as [|Hs]. - reflexivity. - destruct Hs. reflexivity. Qed. -(** The following useful property follows from an analogous - lemma about strings: *) +(** 以下有用的性质可由类似的字符串引理推出: *) Theorem eqb_string_true_iff : forall x y : string, - eqb_string x y = true <-> x = y. + eqb_string x y = true <-> x = y. Proof. intros x y. unfold eqb_string. @@ -80,13 +77,12 @@ Qed. (** 类似地: *) Theorem eqb_string_false_iff : forall x y : string, - eqb_string x y = false - <-> x <> y. + eqb_string x y = false <-> x <> y. Proof. intros x y. rewrite <- eqb_string_true_iff. rewrite not_true_iff_false. reflexivity. Qed. -(** This handy variant follows just by rewriting: *) +(** 以下方便使用的变体只需通过改写就能得出: *) Theorem false_eqb_string : forall x y : string, x <> y -> eqb_string x y = false. @@ -108,7 +104,7 @@ Proof. (** 我们会分两步构建偏映射。首先,我们定义一个_'全映射'_类型, 它在某个映射中查找不存在的键时会返回默认值。 *) -Definition total_map (A:Type) := string -> A. +Definition total_map (A : Type) := string -> A. (** 直观上来说,一个元素类型为 [A] 的全映射不过就是个根据 [string] 来查找 [A] 的函数。 *) @@ -116,14 +112,14 @@ Definition total_map (A:Type) := string -> A. (** 给定函数 [t_empty] 一个默认元素,它会产生一个空的全映射。 此映射在应用到任何字符串时都会返回默认元素。 *) -Definition t_empty {A:Type} (v : A) : total_map A := +Definition t_empty {A : Type} (v : A) : total_map A := (fun _ => v). (** 更有趣的是 [update] 函数,它和之前一样,接受一个映射 [m]、一个键 [x] 以及一个值 [v],并返回一个将 [x] 映射到 [v] 的新映射;其它键则与 [m] 中原来的保持一致。 *) -Definition t_update {A:Type} (m : total_map A) +Definition t_update {A : Type} (m : total_map A) (x : string) (v : A) := fun x' => if eqb_string x x' then v else m x'. @@ -140,30 +136,22 @@ Definition examplemap := (** 接下来,我们引入一些新的记法来方便映射的使用。 *) (** 首先,我们会使用以下记法,根据一个默认值来创建空的全映射。 *) -Notation "{ --> d }" := (t_empty d) (at level 0). +Notation "'_' '!->' v" := (t_empty v) + (at level 100, right associativity). -(** 然后,我们引入一种方便的记法,通过一些绑定来扩展现有的映射。 *) +Example example_empty := (_ !-> false). -(** (这种记法的定义有点丑,因为 Coq 的记法机制不太适应递归记法, - 这是我们能做到最好的了。) *) - -Notation "m '&' { a --> x }" := - (t_update m a x) (at level 20). -Notation "m '&' { a --> x ; b --> y }" := - (t_update (m & { a --> x }) b y) (at level 20). -Notation "m '&' { a --> x ; b --> y ; c --> z }" := - (t_update (m & { a --> x ; b --> y }) c z) (at level 20). -Notation "m '&' { a --> x ; b --> y ; c --> z ; d --> t }" := - (t_update (m & { a --> x ; b --> y ; c --> z }) d t) (at level 20). -Notation "m '&' { a --> x ; b --> y ; c --> z ; d --> t ; e --> u }" := - (t_update (m & { a --> x ; b --> y ; c --> z ; d --> t }) e u) (at level 20). -Notation "m '&' { a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }" := - (t_update (m & { a --> x ; b --> y ; c --> z ; d --> t ; e --> u }) f v) (at level 20). +(** 然后,我们引入一种方便的记法,通过一些绑定来扩展现有的映射。 *) +Notation "x '!->' v ';' m" := (t_update m x v) + (at level 100, v at next level, right associativity). (** 前面的 [examplemap] 现在可以定义如下: *) Definition examplemap' := - { --> false } & { "foo" --> true ; "bar" --> true }. + ( "bar" !-> true; + "foo" !-> true; + _ !-> false + ). (** 到这里就完成了全映射的定义。注意我们无需定义 [find] 操作, 因为它不过就是个函数应用! *) @@ -186,45 +174,49 @@ Proof. reflexivity. Qed. (** (其中有些证明需要函数的外延性公理,我们在[Logic]一节中讨论过它)。 *) -(** **** 练习:1 星, optional (t_apply_empty) *) -(** 首先,空映射对于所有的键都会返回默认元素(即,空映射总是返回默认元素): *) +(** **** 练习:1 星, standard, optional (t_apply_empty) -Lemma t_apply_empty: forall (A:Type) (x: string) (v: A), { --> v } x = v. + 首先,空映射对于所有的键都会返回默认元素(即,空映射总是返回默认元素): *) + +Lemma t_apply_empty : forall (A : Type) (x : string) (v : A), + (_ !-> v) x = v. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (t_update_eq) *) -(** 接着,如果将映射 [m] 的键 [x] 关联的值更新为 [v],然后在 [update] +(** **** 练习:2 星, standard, optional (t_update_eq) + + 接着,如果将映射 [m] 的键 [x] 关联的值更新为 [v],然后在 [update] 产生的新映射中查找 [x],就会得到 [v](即,更新某个键的映射, 查找它就会得到更新后的值): *) -Lemma t_update_eq : forall A (m: total_map A) x v, - (m & {x --> v}) x = v. +Lemma t_update_eq : forall (A : Type) (m : total_map A) x v, + (x !-> v ; m) x = v. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (t_update_neq) *) -(** 此外,如果将映射 [m] 的键 [x1] 更新后在返回的结果中查找_'另一个'_键 +(** **** 练习:2 星, standard, optional (t_update_neq) + + 此外,如果将映射 [m] 的键 [x1] 更新后在返回的结果中查找_'另一个'_键 [x2],那么得到的结果与在 [m] 中查找它的结果相同 (即,更新某个键的映射,不影响其它键的映射): *) -Theorem t_update_neq : forall (X:Type) v x1 x2 - (m : total_map X), - x1 <> x2 -> - (m & {x1 --> v}) x2 = m x2. +Theorem t_update_neq : forall (A : Type) (m : total_map A) x1 x2 v, + x1 <> x2 -> + (x1 !-> v ; m) x2 = m x2. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (t_update_shadow) *) -(** 如果将映射 [m] 的键 [x] 关联的值更新为 [v1] 后,又将同一个键 [x] +(** **** 练习:2 星, standard, optional (t_update_shadow) + + 如果将映射 [m] 的键 [x] 关联的值更新为 [v1] 后,又将同一个键 [x] 更新为另一个值 [v2],那么产生的映射与仅将第二次 [update] 应用于 [m] 所得到的映射表现一致(即二者应用到同一键时产生的结果相同): *) -Lemma t_update_shadow : forall A (m: total_map A) v1 v2 x, - m & {x --> v1 ; x --> v2} = m & {x --> v2}. +Lemma t_update_shadow : forall (A : Type) (m : total_map A) x v1 v2, + (x !-> v2 ; x !-> v1 ; m) = (x !-> v2 ; m). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -233,39 +225,44 @@ Proof. (Reflection idioms)来证明会十分方便。我们首先通过证明基本的_'互映引理'_, 将 [id] 上的相等关系命题与布尔函数 [eqb_id] 关联起来。*) -(** **** 练习:2 星, optional (eqb_stringP) *) -(** 请仿照[IndProp]一章中对 [eqb_natP] 的证明来证明以下引理: *) +(** **** 练习:2 星, standard, optional (eqb_stringP) + + 请仿照[IndProp]一章中对 [eqb_natP] 的证明来证明以下引理: *) -Lemma eqb_stringP : forall x y, reflect (x = y) (eqb_string x y). +Lemma eqb_stringP : forall x y : string, + reflect (x = y) (eqb_string x y). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** 现在,给定 [string] 类型的字符串 [x1] 和 [x2],我们可以在使用 +(** 现在,给定 [string] 类型的字符串 [x1] 和 [x2],我们可以在使用策略 [destruct (eqb_stringP x1 x2)] 对 [eqb_string x1 x2] 的结果进行分类讨论的同时,生成关于 [x1] 和 [x2] (在 [=] 的意义上) 的相等关系前提。 *) -(** **** 练习:2 星 (t_update_same) *) -(** 请仿照[IndProp]一章中的示例,用 [eqb_stringP] 来证明以下定理, +(** **** 练习:2 星, standard (t_update_same) + + 请仿照[IndProp]一章中的示例,用 [eqb_stringP] 来证明以下定理, 它陈述了:如果我们用映射 [m] 中已经与键 [x] 相关联的值更新了 [x], 那么其结果与 [m] 相等: *) -Theorem t_update_same : forall X x (m : total_map X), - m & { x --> m x } = m. - Proof. +Theorem t_update_same : forall (A : Type) (m : total_map A) x, + (x !-> m x ; m) = m. +Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, recommended (t_update_permute) *) -(** 使用 [eqb_stringP] 来证明最后一个 [update] 函数的性质: +(** **** 练习:3 星, standard, recommended (t_update_permute) + + 使用 [eqb_stringP] 来证明最后一个 [update] 函数的性质: 如果我们更新了映射 [m] 中两个不同的键,那么更新的顺序无关紧要。 *) -Theorem t_update_permute : forall (X:Type) v1 v2 x1 x2 - (m : total_map X), - x2 <> x1 -> - m & { x2 --> v2 ; x1 --> v1 } - = m & { x1 --> v1 ; x2 --> v2 }. +Theorem t_update_permute : forall (A : Type) (m : total_map A) + v1 v2 x1 x2, + x2 <> x1 -> + (x1 !-> v1 ; x2 !-> v2 ; m) + = + (x2 !-> v2 ; x1 !-> v1 ; m). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -276,77 +273,72 @@ Proof. (** 最后,我们在全映射之上定义_'偏映射'_。元素类型为 [A] 的偏映射不过就是个 元素类型为 [option A],默认元素为 [None] 的全映射。 *) -Definition partial_map (A:Type) := total_map (option A). +Definition partial_map (A : Type) := total_map (option A). -Definition empty {A:Type} : partial_map A := +Definition empty {A : Type} : partial_map A := t_empty None. -Definition update {A:Type} (m : partial_map A) +Definition update {A : Type} (m : partial_map A) (x : string) (v : A) := - m & { x --> (Some v) }. - -(** 我们用双花括号为偏映射引入类似的记法。 **) - -Notation "m '&' {{ a --> x }}" := - (update m a x) (at level 20). -Notation "m '&' {{ a --> x ; b --> y }}" := - (update (m & {{ a --> x }}) b y) (at level 20). -Notation "m '&' {{ a --> x ; b --> y ; c --> z }}" := - (update (m & {{ a --> x ; b --> y }}) c z) (at level 20). -Notation "m '&' {{ a --> x ; b --> y ; c --> z ; d --> t }}" := - (update (m & {{ a --> x ; b --> y ; c --> z }}) d t) (at level 20). -Notation "m '&' {{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }}" := - (update (m & {{ a --> x ; b --> y ; c --> z ; d --> t }}) e u) (at level 20). -Notation "m '&' {{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }}" := - (update (m & {{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }}) f v) (at level 20). + (x !-> Some v ; m). + +(** 我们为偏映射引入类似的记法。 **) +Notation "x '|->' v ';' m" := (update m x v) + (at level 100, v at next level, right associativity). + +(** 当最后一种情况为空时,我们也可以隐藏它。 *) +Notation "x '|->' v" := (update empty x v) + (at level 100). + +Example examplepmap := + ("Church" |-> true ; "Turing" |-> false). (** 现在我们将所有关于全映射的基本引理直接转换成对应的偏映射引理。 *) -Lemma apply_empty : forall (A: Type) (x: string), @empty A x = None. +Lemma apply_empty : forall (A : Type) (x : string), + @empty A x = None. Proof. intros. unfold empty. rewrite t_apply_empty. reflexivity. Qed. -Lemma update_eq : forall A (m: partial_map A) x v, - (m & {{ x --> v }}) x = Some v. +Lemma update_eq : forall (A : Type) (m : partial_map A) x v, + (x |-> v ; m) x = Some v. Proof. intros. unfold update. rewrite t_update_eq. reflexivity. Qed. -Theorem update_neq : forall (X:Type) v x1 x2 - (m : partial_map X), - x2 <> x1 -> - (m & {{ x2 --> v }}) x1 = m x1. +Theorem update_neq : forall (A : Type) (m : partial_map A) x1 x2 v, + x2 <> x1 -> + (x2 |-> v ; m) x1 = m x1. Proof. - intros X v x1 x2 m H. + intros A m x1 x2 v H. unfold update. rewrite t_update_neq. reflexivity. apply H. Qed. -Lemma update_shadow : forall A (m: partial_map A) v1 v2 x, - m & {{ x --> v1 ; x --> v2 }} = m & {{x --> v2}}. +Lemma update_shadow : forall (A : Type) (m : partial_map A) x v1 v2, + (x |-> v2 ; x |-> v1 ; m) = (x |-> v2 ; m). Proof. - intros A m v1 v2 x1. unfold update. rewrite t_update_shadow. + intros A m x v1 v2. unfold update. rewrite t_update_shadow. reflexivity. Qed. -Theorem update_same : forall X v x (m : partial_map X), - m x = Some v -> - m & {{x --> v}} = m. +Theorem update_same : forall (A : Type) (m : partial_map A) x v, + m x = Some v -> + (x |-> v ; m) = m. Proof. - intros X v x m H. unfold update. rewrite <- H. + intros A m x v H. unfold update. rewrite <- H. apply t_update_same. Qed. -Theorem update_permute : forall (X:Type) v1 v2 x1 x2 - (m : partial_map X), - x2 <> x1 -> - m & {{x2 --> v2 ; x1 --> v1}} - = m & {{x1 --> v1 ; x2 --> v2}}. +Theorem update_permute : forall (A : Type) (m : partial_map A) + x1 x2 v1 v2, + x2 <> x1 -> + (x1 |-> v1 ; x2 |-> v2 ; m) = (x2 |-> v2 ; x1 |-> v1 ; m). Proof. - intros X v1 v2 x1 x2 m. unfold update. + intros A m x1 x2 v1 v2. unfold update. apply t_update_permute. Qed. - +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/MapsTest.v b/lf-current/MapsTest.v index 74bfc8e2..3e78b902 100644 --- a/lf-current/MapsTest.v +++ b/lf-current/MapsTest.v @@ -38,7 +38,7 @@ idtac " ". idtac "#> t_update_same". idtac "Possible points: 2". check_type @t_update_same ( -(forall (X : Type) (x : string) (m : total_map X), m & {x --> m x} = m)). +(forall (A : Type) (m : total_map A) (x : string), (x !-> m x; m) = m)). idtac "Assumptions:". Abort. Print Assumptions t_update_same. @@ -51,8 +51,8 @@ idtac " ". idtac "#> t_update_permute". idtac "Possible points: 3". check_type @t_update_permute ( -(forall (X : Type) (v1 v2 : X) (x1 x2 : string) (m : total_map X), - x2 <> x1 -> m & {x2 --> v2; x1 --> v1} = m & {x1 --> v1; x2 --> v2})). +(forall (A : Type) (m : total_map A) (v1 v2 : A) (x1 x2 : string), + x2 <> x1 -> (x1 !-> v1; x2 !-> v2; m) = (x2 !-> v2; x1 !-> v1; m))). idtac "Assumptions:". Abort. Print Assumptions t_update_permute. @@ -74,3 +74,5 @@ Print Assumptions t_update_permute. idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:14:55 UTC 2019 *) diff --git a/lf-current/Poly.html b/lf-current/Poly.html index 737a7a10..db8e6d40 100644 --- a/lf-current/Poly.html +++ b/lf-current/Poly.html @@ -40,7 +40,7 @@
@@ -479,8 +467,8 @@Maps全映射与偏映射
-Lemma update_eq : ∀ A (m: partial_map A) x v,
- (m & {{ x --> v }}) x = Some v.
+Lemma update_eq : ∀(A : Type) (m : partial_map A) x v,
+ (x ⊢> v ; m) x = Some v.
Proof.
@@ -490,54 +478,55 @@Maps全映射与偏映射
-Theorem update_neq : ∀ (X:Type) v x1 x2
- (m : partial_map X),
- x2 ≠ x1 →
- (m & {{ x2 --> v }}) x1 = m x1.
+Theorem update_neq : ∀(A : Type) (m : partial_map A) x1 x2 v,
+ x2 ≠ x1 →
+ (x2 ⊢> v ; m) x1 = m x1.
Proof.
- intros X v x1 x2 m H.
+ intros A m x1 x2 v H.
unfold update. rewrite t_update_neq. reflexivity.
apply H. Qed.
-Lemma update_shadow : ∀ A (m: partial_map A) v1 v2 x,
- m & {{ x --> v1 ; x --> v2 }} = m & {{x --> v2}}.
+Lemma update_shadow : ∀(A : Type) (m : partial_map A) x v1 v2,
+ (x ⊢> v2 ; x ⊢> v1 ; m) = (x ⊢> v2 ; m).
Proof.
- intros A m v1 v2 x1. unfold update. rewrite t_update_shadow.
+ intros A m x v1 v2. unfold update. rewrite t_update_shadow.
reflexivity.
Qed.
-Theorem update_same : ∀ X v x (m : partial_map X),
- m x = Some v →
- m & {{x --> v}} = m.
+Theorem update_same : ∀(A : Type) (m : partial_map A) x v,
+ m x = Some v →
+ (x ⊢> v ; m) = m.
Proof.
- intros X v x m H. unfold update. rewrite <- H.
+ intros A m x v H. unfold update. rewrite <- H.
apply t_update_same.
Qed.
-Theorem update_permute : ∀ (X:Type) v1 v2 x1 x2
- (m : partial_map X),
- x2 ≠ x1 →
- m & {{x2 --> v2 ; x1 --> v1}}
- = m & {{x1 --> v1 ; x2 --> v2}}.
+Theorem update_permute : ∀(A : Type) (m : partial_map A)
+ x1 x2 v1 v2,
+ x2 ≠ x1 →
+ (x1 ⊢> v1 ; x2 ⊢> v2 ; m) = (x2 ⊢> v2 ; x1 ⊢> v1 ; m).
Proof.+ +
- intros X v1 v2 x1 x2 m. unfold update.
+ intros A m x1 x2 v1 v2. unfold update.
apply t_update_permute.
Qed.
+(* Sat Jan 26 15:14:46 UTC 2019 *)
Poly多态与高阶函数
-多态
+多态
@@ -49,7 +49,7 @@Poly多态与高阶函数
-多态列表
+多态列表
@@ -97,7 +97,7 @@Poly多态与高阶函数
Check list.
-(* ===> list : Type -> Type *)
+(* ===> list : Type -> Type *)
@@ -128,7 +128,7 @@Poly多态与高阶函数
nil 的类型可能是什么?我们可以从定义中看到 list X 的类型, 它忽略了 list 的形参 X 的绑定。Type → list X 并没有解释 X 的含义,(X : Type) → list X 则比较接近。Coq 对这种情况的记法为 - ∀X : Type, list X: + ∀ X : Type, list X:@@ -138,12 +138,12 @@Poly多态与高阶函数
类似地,定义中 cons 看起来像 X → list X → list X - 然而以此约定来解释 X 的含义则是类型 ∀X, X → list X → list X。 + 然而以此约定来解释 X 的含义则是类型 ∀ X, X → list X → list X。Check cons.
-(* ===> cons : forall X : Type, X -> list X -> list X *)
+(* ===> cons : forall X : Type, X -> list X -> list X *)
@@ -201,7 +201,7 @@Poly多态与高阶函数
@@ -256,7 +256,7 @@Poly多态与高阶函数
☐-类型标注的推断
+类型标注的推断
@@ -278,9 +278,9 @@Poly多态与高阶函数
Check repeat'.
-(* ===> forall X : Type, X -> nat -> list X *)
+(* ===> forall X : Type, X -> nat -> list X *)
Check repeat.
-(* ===> forall X : Type, X -> nat -> list X *)
+(* ===> forall X : Type, X -> nat -> list X *)
@@ -299,7 +299,7 @@Poly多态与高阶函数
-类型参数的推断
+类型参数的推断
@@ -376,7 +376,7 @@Poly多态与高阶函数
-隐式参数
+隐式参数
@@ -471,7 +471,7 @@Poly多态与高阶函数
-显式提供类型参数
+显式提供类型参数
@@ -533,25 +533,25 @@Poly多态与高阶函数
-练习
+练习
-练习:2 星, optional (poly_exercises)
+练习:2 星, standard, optional (poly_exercises)
下面是一些简单的练习,和 Lists 一章中的一样。 为了实践多态,请完成下面的证明。-Theorem app_nil_r : ∀ (X:Type), ∀ l:list X,
+Theorem app_nil_r : ∀(X:Type), ∀l:list X,
l ++ [] = l.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem app_assoc : ∀ A (l m n:list A),
+Theorem app_assoc : ∀A (l m n:list A),
l ++ m ++ n = (l ++ m) ++ n.
Proof.
(* 请在此处解答 *) Admitted.
-Lemma app_length : ∀ (X:Type) (l1 l2 : list X),
+Lemma app_length : ∀(X:Type) (l1 l2 : list X),
length (l1 ++ l2) = length l1 + length l2.
Proof.
(* 请在此处解答 *) Admitted.
@@ -561,16 +561,16 @@Poly多态与高阶函数
-练习:2 星, optional (more_poly_exercises)
+练习:2 星, standard, optional (more_poly_exercises)
这儿有些更有趣的东西...-Theorem rev_app_distr: ∀ X (l1 l2 : list X),
+Theorem rev_app_distr: ∀X (l1 l2 : list X),
rev (l1 ++ l2) = rev l2 ++ rev l1.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem rev_involutive : ∀ X : Type, ∀ l : list X,
+Theorem rev_involutive : ∀X : Type, ∀l : list X,
rev (rev l) = l.
Proof.
(* 请在此处解答 *) Admitted.
@@ -579,7 +579,7 @@Poly多态与高阶函数
☐-多态序对
+多态序对
@@ -653,7 +653,7 @@Poly多态与高阶函数
-练习:1 星, optional (combine_checks)
+练习:1 星, standard, optional (combine_checks)
请尝试在纸上回答以下问题并在 Coq 中检验你的解答:@@ -677,7 +677,7 @@Poly多态与高阶函数
☐-练习:2 星, recommended (split)
+练习:2 星, standard, recommended (split)
函数 split 是 combine 的右逆(right inverse): 它接受一个序对的列表并返回一个列表的序对。 在很多函数式语言中,它被称作 unzip。 @@ -700,7 +700,7 @@Poly多态与高阶函数
☐-多态候选
+多态候选
@@ -751,7 +751,7 @@Poly多态与高阶函数
-练习:1 星, optional (hd_error_poly)
+练习:1 星, standard, optional (hd_error_poly)
请完成上一章中 hd_error 的多态定义,确保它能通过下方的单元测试。@@ -775,7 +775,7 @@Poly多态与高阶函数
☐-函数作为数据
+函数作为数据
@@ -785,7 +785,7 @@Poly多态与高阶函数
-高阶函数
+高阶函数
@@ -804,7 +804,7 @@Poly多态与高阶函数
Check @doit3times.
-(* ===> doit3times : forall X : Type, (X -> X) -> X -> X *)
+(* ===> doit3times : forall X : Type, (X -> X) -> X -> X *)
Example test_doit3times: doit3times minustwo 9 = 3.
Proof. reflexivity. Qed.
Example test_doit3times': doit3times negb true = false.
@@ -812,7 +812,7 @@Poly多态与高阶函数
-过滤器
+过滤器
@@ -865,7 +865,7 @@Poly多态与高阶函数
-匿名函数
+匿名函数
@@ -902,7 +902,7 @@Poly多态与高阶函数
-@@ -922,13 +922,13 @@练习:2 星 (filter_even_gt7)
+练习:2 星, standard (filter_even_gt7)
使用 filter(而非 Fixpoint)来编写 Coq 函数 filter_even_gt7, 它接受一个自然数列表作为输入,返回一个只包含大于 7 的偶数的列表。Poly多态与高阶函数
-练习:3 星 (partition)
+练习:3 星, standard (partition)
使用 filter 编写一个 Coq 函数 partition:- partition : ∀ X : Type,
+ partition : ∀X : Type,
(X → bool) → list X → list X * list X@@ -954,7 +954,7 @@Poly多态与高阶函数
☐-映射
+映射
@@ -1005,16 +1005,16 @@Poly多态与高阶函数
-Theorem map_rev : ∀ (X Y : Type) (f : X → Y) (l : list X),
+Theorem map_rev : ∀(X Y : Type) (f : X → Y) (l : list X),
map f (rev l) = rev (map f l).
Proof.
(* 请在此处解答 *) Admitted.
@@ -1024,7 +1024,7 @@Poly多态与高阶函数
-练习:2 星, recommended (flat_map)
+练习:2 星, standard, recommended (flat_map)
函数 map 通过一个类型为 X → Y 的函数将 list X 映射到 list Y。 我们可以定义一个类似的函数 flat_map,它通过一个类型为 X → list Y 的函数 f 将 list X 映射到 list Y。你的定义应当可以“压扁”f @@ -1069,7 +1069,7 @@Poly多态与高阶函数
-diff --git a/lf-current/Preface.v b/lf-current/Preface.v index 9cff4c02..e00cdcb2 100644 --- a/lf-current/Preface.v +++ b/lf-current/Preface.v @@ -20,7 +20,6 @@ 本书为第一卷_'《逻辑基础》'_,它向读者介绍了函数式编程的基本概念、构造逻辑以及 Coq 证明助理,为其它卷本的学习奠定了基础。 *) - (* ################################################################# *) (** * 概览 *) @@ -165,7 +164,6 @@ 当我们更加深入地审视它时,会发现 Coq 的这两方面其实基于完全相同的底层机制 -- _'命题即类型,程序即证明'_,可谓殊途同归。 *) - (* ================================================================= *) (** ** 扩展阅读 *) @@ -188,7 +186,7 @@ (** Coq 可以在 Windows、Linux 和 macOS 上运行。我们需要: - 安装近期版本的 Coq,它可以从 Coq 主页获得。本书中的文件均已通过了 - Coq 8.8.0 的测试。 + Coq 8.8.1 的测试。 - 一个能跟 Coq 交互的 IDE。目前有两种选择: @@ -200,7 +198,12 @@ - CoqIDE 是个更加简单的独立 IDE。它随 Coq 一起发布, 所以如果你安装了 Coq,它应该就能用。你也可以从头编译安装它, - 不过在某些平台上还需要额外安装 GUI 之类的库。 *) + 不过在某些平台上还需要额外安装 GUI 之类的库。 + + 用户在运行 CoqIDE 时可以考虑关闭“异步”和“错误恢复”模式: + + coqide -async-proofs off -async-proofs-command-error-resilience off Foo.v & +*) (* ================================================================= *) (** ** 练习 *) @@ -237,14 +240,24 @@ 本书的中文版和压缩包可访问 https://github.com/Coq-zh/SF-zh 获取。 (如果你是在一门课程中使用本书的,那么你的教授可能会让你使用本地的修改版, - 此时你应当使用它们而非发布版。) *) + 此时你应当使用它们而非发布版,这样你可以获得所有该学期的本地更新。) *) + +(* ################################################################# *) +(** * 资源 *) + +(* ================================================================= *) +(** ** 模拟题 *) + +(** 宾夕法尼亚大学的 CIS500(软件基础)课程提供了大量的考试大纲,可访问 + https://www.seas.upenn.edu/~cis500/current/exams/index.html 获取。 + 近年来书中的记法有所变动,但大部分问题仍与本文对应。 *) (* ================================================================= *) (** ** 课程视频 *) -(** _'《逻辑基础》'_暑期加强班的课程讲义可访问 - https://deepspec.org/event/dsss17/coq_intensive.html 获取。 - 开始的视频清晰度不高,但在之后的课程中会更好。 *) +(** _'《逻辑基础》'_夏季加强班(DeepSpec 夏季班系列之一)的课程讲义可访问 + https://deepspec.org/event/dsss17 和 https://deepspec.org/event/dsss18/ + 获取。2017 年的视频清晰度不高,但在之后的课程中会更好。 *) (* ################################################################# *) (** * 对授课员的要求 *) @@ -293,3 +306,5 @@ (** _'《软件基础》'_ 系列的开发,部分由国家科学基金会 (National Science Foundation)在 NSF 科研赞助 1521523 号 _'深度规范科学'_ 下提供支持。 *) + +(* Sat Jan 26 15:14:44 UTC 2019 *) diff --git a/lf-current/PrefaceTest.v b/lf-current/PrefaceTest.v index 06635477..f5216847 100644 --- a/lf-current/PrefaceTest.v +++ b/lf-current/PrefaceTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:14:47 UTC 2019 *) diff --git a/lf-current/ProofObjects.html b/lf-current/ProofObjects.html index e652c790..8cbbc502 100644 --- a/lf-current/ProofObjects.html +++ b/lf-current/ProofObjects.html @@ -43,7 +43,7 @@练习:2 星, optional (implicit_args)
+练习:2 星, standard, optional (implicit_args)
filter 和 map 的定义和应用在很多地方使用了隐式参数。 请将隐式参数外层的花括号替换为圆括号,然后在必要的地方补充显式类型形参并用 Coq 检查你做的是否正确。(本练习并不会打分,你可以在本文件的副本中做它, @@ -1078,7 +1078,7 @@Poly多态与高阶函数
-+ +折叠
+折叠
@@ -1122,7 +1122,7 @@Poly多态与高阶函数
Check (fold andb).
-(* ===> fold andb : list bool -> bool -> bool *)
+(* ===> fold andb : list bool -> bool -> bool *)
Example fold_example1 :
fold mult [1;2;3;4] 1 = 24.
@@ -1148,7 +1148,7 @@Poly多态与高阶函数
-diff --git a/lf-current/Postscript.v b/lf-current/Postscript.v index 4dd76711..f250cfb4 100644 --- a/lf-current/Postscript.v +++ b/lf-current/Postscript.v @@ -19,7 +19,6 @@ --------- ~ ------------------ 软件工程 机械工程/土木工程 - - 归纳定义的集合和关系 - 归纳证明 - 证明对象 *) @@ -81,3 +80,5 @@ 夏令营的课程与相关资料。 https://deepspec.org/event/dsss17/index.html *) + +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/PostscriptTest.v b/lf-current/PostscriptTest.v index 0d13dd89..f949d1cf 100644 --- a/lf-current/PostscriptTest.v +++ b/lf-current/PostscriptTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:15:05 UTC 2019 *) diff --git a/lf-current/Preface.html b/lf-current/Preface.html index 2c7b3895..c49be78f 100644 --- a/lf-current/Preface.html +++ b/lf-current/Preface.html @@ -306,7 +306,7 @@练习:1 星, advanced (fold_types_different)
+练习:1 星, advanced (fold_types_different)
我们观察到 fold 由 X 和 Y 这两个类型变量参数化,形参 f 则是个接受 X 和 Y 并返回 Y 的二元操作符。你能想出一种 X 和 Y 不同时的应用情景吗? @@ -1163,7 +1163,7 @@Poly多态与高阶函数
☐-用函数构造函数
+用函数构造函数
@@ -1198,7 +1198,7 @@Poly多态与高阶函数
Check plus.
-(* ==> nat -> nat -> nat *)
+(* ==> nat -> nat -> nat *)
@@ -1223,7 +1223,7 @@+Poly多态与高阶函数
@@ -1233,7 +1233,7 @@diff --git a/lf-current/Poly.v b/lf-current/Poly.v index e9a1de10..28e7c702 100644 --- a/lf-current/Poly.v +++ b/lf-current/Poly.v @@ -115,9 +115,9 @@ Example test_repeat2 : Proof. reflexivity. Qed. +(** **** 练习:2 星, standard (mumble_grumble) -(** **** 练习:2 星 (mumble_grumble) *) -(** 考虑以下两个归纳定义的类型: *) + 考虑以下两个归纳定义的类型: *) Module MumbleGrumble. @@ -341,8 +341,9 @@ Definition list123''' := [1; 2; 3]. (* ----------------------------------------------------------------- *) (** *** 练习 *) -(** **** 练习:2 星, optional (poly_exercises) *) -(** 下面是一些简单的练习,和 [Lists] 一章中的一样。 +(** **** 练习:2 星, standard, optional (poly_exercises) + + 下面是一些简单的练习,和 [Lists] 一章中的一样。 为了实践多态,请完成下面的证明。 *) Theorem app_nil_r : forall (X:Type), forall l:list X, @@ -361,8 +362,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (more_poly_exercises) *) -(** 这儿有些更有趣的东西... *) +(** **** 练习:2 星, standard, optional (more_poly_exercises) + + 这儿有些更有趣的东西... *) Theorem rev_app_distr: forall X (l1 l2 : list X), rev (l1 ++ l2) = rev l2 ++ rev l1. @@ -428,17 +430,19 @@ Fixpoint combine {X Y : Type} (lx : list X) (ly : list Y) | x :: tx, y :: ty => (x, y) :: (combine tx ty) end. -(** **** 练习:1 星, optional (combine_checks) *) -(** 请尝试在纸上回答以下问题并在 Coq 中检验你的解答: +(** **** 练习:1 星, standard, optional (combine_checks) + + 请尝试在纸上回答以下问题并在 Coq 中检验你的解答: - [combine] 的类型是什么?(即 [Check @combine] 会打印出什么?) - 以下指令会打印出什么? Compute (combine [1;2] [false;false;true;true]). -*) -(** [] *) -(** **** 练习:2 星, recommended (split) *) -(** 函数 [split] 是 [combine] 的右逆(right inverse): + [] *) + +(** **** 练习:2 星, standard, recommended (split) + + 函数 [split] 是 [combine] 的右逆(right inverse): 它接受一个序对的列表并返回一个列表的序对。 在很多函数式语言中,它被称作 [unzip]。 @@ -458,8 +462,9 @@ Proof. (** ** 多态候选 *) (** 现在介绍最后一种多态类型:_'多态候选(Polymorphic Options)'_, - 它推广了上一章中的 [natoption]: *) -(** One last polymorphic type for now: _polymorphic options_, + 它推广了上一章中的 [natoption]: + + One last polymorphic type for now: _polymorphic options_, which generalize [natoption] from the previous chapter. (We put the definition inside a module because the standard library already defines [option] and it's this one that we want to use @@ -492,8 +497,9 @@ Proof. reflexivity. Qed. Example test_nth_error3 : nth_error [true] 2 = None. Proof. reflexivity. Qed. -(** **** 练习:1 星, optional (hd_error_poly) *) -(** 请完成上一章中 [hd_error] 的多态定义,确保它能通过下方的单元测试。 *) +(** **** 练习:1 星, standard, optional (hd_error_poly) + + 请完成上一章中 [hd_error] 的多态定义,确保它能通过下方的单元测试。 *) Definition hd_error {X : Type} (l : list X) : option X (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. @@ -603,8 +609,9 @@ Example test_filter2': = [ [3]; [4]; [8] ]. Proof. reflexivity. Qed. -(** **** 练习:2 星 (filter_even_gt7) *) -(** 使用 [filter](而非 [Fixpoint])来编写 Coq 函数 [filter_even_gt7], +(** **** 练习:2 星, standard (filter_even_gt7) + + 使用 [filter](而非 [Fixpoint])来编写 Coq 函数 [filter_even_gt7], 它接受一个自然数列表作为输入,返回一个只包含大于 [7] 的偶数的列表。 *) Definition filter_even_gt7 (l : list nat) : list nat @@ -619,8 +626,9 @@ Example test_filter_even_gt7_2 : (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (partition) *) -(** 使用 [filter] 编写一个 Coq 函数 [partition]: +(** **** 练习:3 星, standard (partition) + + 使用 [filter] 编写一个 Coq 函数 [partition]: partition : forall X : Type, (X -> bool) -> list X -> list X * list X @@ -679,8 +687,9 @@ Proof. reflexivity. Qed. (* ----------------------------------------------------------------- *) (** *** 习题 *) -(** **** 练习:3 星 (map_rev) *) -(** 请证明 [map] 和 [rev] 可交换。你可能需要定义一个辅助引力 *) +(** **** 练习:3 星, standard (map_rev) + + 请证明 [map] 和 [rev] 可交换。你可能需要定义一个辅助引力 *) Theorem map_rev : forall (X Y : Type) (f : X -> Y) (l : list X), map f (rev l) = rev (map f l). @@ -688,8 +697,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, recommended (flat_map) *) -(** 函数 [map] 通过一个类型为 [X -> Y] 的函数将 [list X] 映射到 [list Y]。 +(** **** 练习:2 星, standard, recommended (flat_map) + + 函数 [map] 通过一个类型为 [X -> Y] 的函数将 [list X] 映射到 [list Y]。 我们可以定义一个类似的函数 [flat_map],它通过一个类型为 [X -> list Y] 的函数 [f] 将 [list X] 映射到 [list Y]。你的定义应当可以“压扁”[f] 的结果,就像这样: @@ -718,13 +728,14 @@ Definition option_map {X Y : Type} (f : X -> Y) (xo : option X) | Some x => Some (f x) end. -(** **** 练习:2 星, optional (implicit_args) *) -(** [filter] 和 [map] 的定义和应用在很多地方使用了隐式参数。 +(** **** 练习:2 星, standard, optional (implicit_args) + + [filter] 和 [map] 的定义和应用在很多地方使用了隐式参数。 请将隐式参数外层的花括号替换为圆括号,然后在必要的地方补充显式类型形参并用 Coq 检查你做的是否正确。(本练习并不会打分,你可以在本文件的_'副本'_中做它, 之后丢掉即可。) -*) -(** [] *) + + [] *) (* ================================================================= *) (** ** 折叠 *) @@ -767,8 +778,9 @@ Example fold_example3 : fold app [[1];[];[2;3];[4]] [] = [1;2;3;4]. Proof. reflexivity. Qed. -(** **** 练习:1 星, advanced (fold_types_different) *) -(** 我们观察到 [fold] 由 [X] 和 [Y] 这_'两个'_类型变量参数化,形参 [f] +(** **** 练习:1 星, advanced (fold_types_different) + + 我们观察到 [fold] 由 [X] 和 [Y] 这_'两个'_类型变量参数化,形参 [f] 则是个接受 [X] 和 [Y] 并返回 [Y] 的二元操作符。你能想出一种 [X] 和 [Y] 不同时的应用情景吗? *) @@ -826,8 +838,9 @@ Proof. reflexivity. Qed. Module Exercises. -(** **** 练习:2 星 (fold_length) *) -(** 列表的很多通用函数都可以通过 [fold] 来实现。例如,下面是 +(** **** 练习:2 星, standard (fold_length) + + 列表的很多通用函数都可以通过 [fold] 来实现。例如,下面是 [length] 的另一种实现: *) Definition fold_length {X : Type} (l : list X) : nat := @@ -836,7 +849,9 @@ Definition fold_length {X : Type} (l : list X) : nat := Example test_fold_length1 : fold_length [4;7;0] = 3. Proof. reflexivity. Qed. -(** 请证明 [fold_length] 的正确性。 *) +(** 请证明 [fold_length] 的正确性。(提示:知道 [reflexivity] 的化简力度比 [simpl] + 更大或许会有所帮助。也就是说,你或许会遇到 [simpl] 无法解决但 [reflexivity] + 可以解决的目标。) *) Theorem fold_length_correct : forall X (l : list X), fold_length l = length l. @@ -844,13 +859,15 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (fold_map) *) -(** 我们也可以用 [fold] 来定义 [map]。请完成下面的 [fold_map]。 *) +(** **** 练习:3 星, standard (fold_map) + + 我们也可以用 [fold] 来定义 [map]。请完成下面的 [fold_map]。 *) Definition fold_map {X Y: Type} (f: X -> Y) (l: list X) : list Y (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. -(** 在 Coq 中写出 [fold_map_correct] 来陈述 [fold_map] 是正确的,然后证明它。 *) +(** 在 Coq 中写出 [fold_map_correct] 来陈述 [fold_map] 是正确的,然后证明它。 + (提示:再次提醒,[reflexivity] 的化简力度比 [simpl] 更强。) *) (* 请在此处解答 *) @@ -858,8 +875,9 @@ Definition fold_map {X Y: Type} (f: X -> Y) (l: list X) : list Y Definition manual_grade_for_fold_map : option (nat*string) := None. (** [] *) -(** **** 练习:2 星, advanced (currying) *) -(** 在 Coq 中,函数 [f : A -> B -> C] 的类型其实是 [A -> (B -> C)]。 +(** **** 练习:2 星, advanced (currying) + + 在 Coq 中,函数 [f : A -> B -> C] 的类型其实是 [A -> (B -> C)]。 也就是说,如果给 [f] 一个类型为 [A] 的值,它就会给你函数 [f' : B -> C]。 如果再给 [f'] 一个类型为 [B] 的值,它就会返回一个类型为 [C] 的值。 这为我们提供了 [plus3] 中的那种偏应用能力。 @@ -906,8 +924,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, advanced (nth_error_informal) *) -(** 回想 [nth_error] 函数的定义: +(** **** 练习:2 星, advanced (nth_error_informal) + + 回想 [nth_error] 函数的定义: Fixpoint nth_error {X : Type} (l : list X) (n : nat) : option X := match l with @@ -1041,3 +1060,4 @@ End Church. End Exercises. +(* Sat Jan 26 15:14:45 UTC 2019 *) diff --git a/lf-current/PolyTest.v b/lf-current/PolyTest.v index d1d460e0..33a8e8d6 100644 --- a/lf-current/PolyTest.v +++ b/lf-current/PolyTest.v @@ -420,3 +420,5 @@ Print Assumptions Exercises.Church.exp_2. idtac "---------- Exercises.Church.exp_3 ---------". Print Assumptions Exercises.Church.exp_3. Abort. + +(* Sat Jan 26 15:14:50 UTC 2019 *) diff --git a/lf-current/Postscript.html b/lf-current/Postscript.html index 72f75190..ca6644df 100644 --- a/lf-current/Postscript.html +++ b/lf-current/Postscript.html @@ -39,7 +39,7 @@Poly多态与高阶函数
@@ -1249,11 +1249,13 @@Poly多态与高阶函数
-请证明 fold_length 的正确性。 +请证明 fold_length 的正确性。(提示:知道 reflexivity 的化简力度比 simpl + 更大或许会有所帮助。也就是说,你或许会遇到 simpl 无法解决但 reflexivity + 可以解决的目标。)-Theorem fold_length_correct : ∀ X (l : list X),
+Theorem fold_length_correct : ∀X (l : list X),
fold_length l = length l.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1263,7 +1265,7 @@Poly多态与高阶函数
-练习:3 星 (fold_map)
+练习:3 星, standard (fold_map)
我们也可以用 fold 来定义 map。请完成下面的 fold_map。@@ -1273,7 +1275,8 @@Poly多态与高阶函数
-在 Coq 中写出 fold_map_correct 来陈述 fold_map 是正确的,然后证明它。 +在 Coq 中写出 fold_map_correct 来陈述 fold_map 是正确的,然后证明它。 + (提示:再次提醒,reflexivity 的化简力度比 simpl 更强。)@@ -1286,7 +1289,7 @@Poly多态与高阶函数
-练习:2 星, advanced (currying)
+练习:2 星, advanced (currying)
在 Coq 中,函数 f : A → B → C 的类型其实是 A → (B → C)。 也就是说,如果给 f 一个类型为 A 的值,它就会给你函数 f' : B → C。 如果再给 f' 一个类型为 B 的值,它就会返回一个类型为 C 的值。 @@ -1336,13 +1339,13 @@Poly多态与高阶函数
Check @prod_curry.
Check @prod_uncurry.
-Theorem uncurry_curry : ∀ (X Y Z : Type)
+Theorem uncurry_curry : ∀(X Y Z : Type)
(f : X → Y → Z)
x y,
prod_curry (prod_uncurry f) x y = f x y.
Proof.
(* 请在此处解答 *) Admitted.
-Theorem curry_uncurry : ∀ (X Y Z : Type)
+Theorem curry_uncurry : ∀(X Y Z : Type)
(f : (X * Y) → Z) (p : X * Y),
prod_uncurry (prod_curry f) p = f p.
Proof.
@@ -1353,7 +1356,7 @@Poly多态与高阶函数
-练习:2 星, advanced (nth_error_informal)
+练习:2 星, advanced (nth_error_informal)
回想 nth_error 函数的定义:@@ -1372,7 +1375,7 @@Poly多态与高阶函数
- ∀ X n l, length l = n → @nth_error X l n = None + ∀X n l, length l = n → @nth_error X l n = None@@ -1397,7 +1400,7 @@Poly多态与高阶函数
Module Church.
-Definition cnat := ∀ X : Type, (X → X) → X → X.
+Definition cnat := ∀X : Type, (X → X) → X → X.
@@ -1443,7 +1446,7 @@Poly多态与高阶函数
reflexivity 证明来确认它们能够通过对应的单元测试。-练习:1 星, advanced (church_succ)
+练习:1 星, advanced (church_succ)
@@ -1466,7 +1469,7 @@Poly多态与高阶函数
-练习:1 星, advanced (church_plus)
+练习:1 星, advanced (church_plus)
@@ -1488,7 +1491,7 @@Poly多态与高阶函数
-练习:2 星, advanced (church_mult)
+练习:2 星, advanced (church_mult)
@@ -1509,7 +1512,7 @@Poly多态与高阶函数
-练习:2 星, advanced (church_exp)
+练习:2 星, advanced (church_exp)
@@ -1537,7 +1540,8 @@Poly多态与高阶函数
End Church.
-End Exercises.
+End Exercises.
+(* Sat Jan 26 15:14:45 UTC 2019 *)
Postscript后记
恭喜,课程终于顺利结束了!-回顾一下
+回顾一下
@@ -117,7 +117,7 @@Postscript后记
+ +(* Sat Jan 26 15:14:46 UTC 2019 *)
Preface前言
@@ -406,20 +419,34 @@
- 安装近期版本的 Coq,它可以从 Coq 主页获得。本书中的文件均已通过了 - Coq 8.8.0 的测试。 + Coq 8.8.1 的测试。
@@ -331,7 +331,20 @@Preface前言
- CoqIDE 是个更加简单的独立 IDE。它随 Coq 一起发布, 所以如果你安装了 Coq,它应该就能用。你也可以从头编译安装它, - 不过在某些平台上还需要额外安装 GUI 之类的库。 + 不过在某些平台上还需要额外安装 GUI 之类的库。 + +
+ + 用户在运行 CoqIDE 时可以考虑关闭“异步”和“错误恢复”模式: + ++ ++coqide -async-proofs off -async-proofs-command-error-resilience off Foo.v & +++ +Preface前言
(如果你是在一门课程中使用本书的,那么你的教授可能会让你使用本地的修改版, - 此时你应当使用它们而非发布版。) + 此时你应当使用它们而非发布版,这样你可以获得所有该学期的本地更新。) ++资源
+ ++ +模拟题
+ ++ + 宾夕法尼亚大学的 CIS500(软件基础)课程提供了大量的考试大纲,可访问 + https://www.seas.upenn.edu/~cis500/current/exams/index.html 获取。 + 近年来书中的记法有所变动,但大部分问题仍与本文对应。-课程视频
+课程视频
- 《逻辑基础》暑期加强班的课程讲义可访问 - https://deepspec.org/event/dsss17/coq_intensive.html 获取。 - 开始的视频清晰度不高,但在之后的课程中会更好。 + 《逻辑基础》夏季加强班(DeepSpec 夏季班系列之一)的课程讲义可访问 + https://deepspec.org/event/dsss17 和 https://deepspec.org/event/dsss18/ + 获取。2017 年的视频清晰度不高,但在之后的课程中会更好。-+鸣谢
+鸣谢
@@ -486,6 +513,10 @@Preface前言
(National Science Foundation)在 NSF 科研赞助 1521523 号 深度规范科学 下提供支持。+ +(* Sat Jan 26 15:14:44 UTC 2019 *)
+ProofObjects柯里-霍华德对应
前文已讨论过 Coq 既可以用 nat、list 等归纳类型及其函数编程,又可 - 以用归纳命题(如 ev)、蕴含式、全称量词等工具证明程序的性质。我们一直 + 以用归纳命题(如 even)、蕴含式、全称量词等工具证明程序的性质。我们一直 以来区别对待此两种用法,在很多情况下确实可以这样。但也有迹象表明在 Coq 中编 程与证明紧密相关。例如,关键字 Inductive 同时用于声明数据类型和命题,以及 → 同时用于描述函数类型和逻辑蕴含式。这可并不是语法上的巧合!事实上,在 Coq @@ -68,22 +68,22 @@ProofObjects柯里-霍华德对应 答曰:类型也!
- 回顾一下 ev 这个性质的形式化定义。 + 回顾一下 even 这个性质的形式化定义。-Print ev.
+Print even.
(* ==>
- Inductive ev : nat -> Prop :=
- | ev_0 : ev 0
- | ev_SS : forall n, ev n -> ev (S (S n)).
+ Inductive even : nat -> Prop :=
+ | ev_0 : even 0
+ | ev_SS : forall n, even n -> even (S (S n)).
*)
-试以另一种方式解读“:”:以“是……的证明”取代“具有……类型”。例如将定义第二行的 - ev_0 : ev 0 读作“ev_0 是 ev 0 的证明”以代替“ev_0 具有 ev 0 类型”。 - +试以另一种方式解读“:”:以“是……的证明”取代“具有……类型”。例如将定义 even + 第二行的 ev_0 : even 0 读作“ev_0 是 [even] 0 的证明”以代替“ev_0 具有 + [even] 0 类型”。此处 : 既在类型层面表达“具有……类型”,又在命题层面表示“证明了……”。这种双关 @@ -105,20 +105,20 @@ProofObjects柯里-霍华德对应 Check ev_SS.
(* ===> ev_SS : forall n,
- ev n ->
- ev (S (S n)) *)
+ even n ->
+ even (S (S n)) *)
-可以将其读作“ev_SS 构造子接受两个参数——数字 n 以及命题 ev n 的证明——并 - 产生 ev (S (S n)) 的证明。” +可以将其读作“ev_SS 构造子接受两个参数——数字 n 以及命题 even n + 的证明——并产生 even (S (S n)) 的证明。”- 现在让我们回顾一下之前有关 ev 的一个证明。 + 现在让我们回顾一下之前有关 even 的一个证明。-Theorem ev_4 : ev 4.@@ -131,7 +131,7 @@
+Theorem ev_4 : even 4.
Proof.
apply ev_SS. apply ev_SS. apply ev_0. Qed.
ProofObjects柯里-霍华德对应 Print ev_4.
(* ===> ev_4 = ev_SS 2 (ev_SS 0 ev_0)
- : ev 4 *)
+ : even 4 *)
@@ -140,15 +140,24 @@ProofObjects柯里-霍华德对应
Check (ev_SS 2 (ev_SS 0 ev_0)).
-(* ===> ev 4 *)
+(* ===> even 4 *)
表达式 ev_SS 2 (ev_SS 0 ev_0) 可视为向构造子 ev_SS 传入参数 2 和 0 - 等参数,以及对应的 ev 2 与 ev 0 之依据所构造的证明。或言之,视 ev_SS + 等参数,以及对应的 even 2 与 even 0 之依据所构造的证明。或言之,视 ev_SS 为“构造证明”之原语,需要给定一个数字,并进一步提供该数为偶数之依据以构造证明。 - 其类型表明了它的功能:[ ∀n, ev n → ev (S (S n)) ];类似地,多态类型 ∀X, - list X 表明可以将 nil 视为从某类型到由该类型元素组成的空列表的函数。 + 其类型表明了它的功能: + ++ ++ ∀n, even n → even (S (S n)) ++ 类似地,多态类型 ∀ X, list X 表明可以将 nil + 视为从某类型到由该类型元素组成的空列表的函数。+ +我们在 Logic 这一章中已经了解到,我们可以使用函数应用 @@ -157,14 +166,14 @@ProofObjects柯里-霍华德对应
-Theorem ev_4': ev 4.
+Theorem ev_4': even 4.
Proof.
apply (ev_SS 2 (ev_SS 0 ev_0)).
Qed.
-Theorem ev_4'' : ev 4.
+Theorem ev_4'' : even 4.
Proof.
Show Proof.
apply ev_SS.
@@ -204,7 +213,7 @@ProofObjects柯里-霍华德对应
-Definition ev_4''' : ev 4 :=@@ -214,32 +223,32 @@
+Definition ev_4''' : even 4 :=
ev_SS 2 (ev_SS 0 ev_0).
ProofObjects柯里-霍华德对应
Print ev_4.
-(* ===> ev_4 = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
+(* ===> ev_4 = ev_SS 2 (ev_SS 0 ev_0) : even 4 *)
Print ev_4'.
-(* ===> ev_4' = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
+(* ===> ev_4' = ev_SS 2 (ev_SS 0 ev_0) : even 4 *)
Print ev_4''.
-(* ===> ev_4'' = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
+(* ===> ev_4'' = ev_SS 2 (ev_SS 0 ev_0) : even 4 *)
Print ev_4'''.
-(* ===> ev_4''' = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
+(* ===> ev_4''' = ev_SS 2 (ev_SS 0 ev_0) : even 4 *)
-练习:2 星 (eight_is_even)
- 写出对应 ev 8 的策略证明和证明对象。 +练习:2 星, standard (eight_is_even)
+ 写出对应 even 8 的策略证明和证明对象。-Theorem ev_8 : ev 8.☐
+Theorem ev_8 : even 8.
Proof.
(* 请在此处解答 *) Admitted.
-Definition ev_8' : ev 8
+Definition ev_8' : even 8
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem ev_plus4 : ∀ n, ev n → ev (4 + n).
+Theorem ev_plus4 : ∀n, even n → even (4 + n).
Proof.
intros n H. simpl.
apply ev_SS.
@@ -272,7 +281,7 @@ProofObjects柯里-霍华德对应
- 我们在寻找一个类型(Type)是 ∀n, ev n → ev (4 + n) 的表达式——也 + 我们在寻找一个类型(Type)是 ∀ n, even n → even (4 + n) 的表达式——也 就是说,一个接受两个参数(一个数字和一个证据)并返回一个证据的 函数(Function)! @@ -282,8 +291,8 @@ProofObjects柯里-霍华德对应
-Definition ev_plus4' : ∀ n, ev n → ev (4 + n) :=@@ -294,17 +303,17 @@
- fun (n : nat) ⇒ fun (H : ev n) ⇒
+Definition ev_plus4' : ∀n, even n → even (4 + n) :=
+ fun (n : nat) ⇒ fun (H : even n) ⇒
ev_SS (S (S n)) (ev_SS n H).
ProofObjects柯里-霍华德对应
-Definition ev_plus4'' (n : nat) (H : ev n)
- : ev (4 + n) :=
+Definition ev_plus4'' (n : nat) (H : even n)
+ : even (4 + n) :=
ev_SS (S (S n)) (ev_SS n H).
Check ev_plus4''.
(* ===>
- : forall n : nat, ev n -> ev (4 + n) *)
+ : forall n : nat, even n -> even (4 + n) *)
当我们将 ev_plus4 证明的命题视为一个函数类型时,我们可以发现一个 - 有趣的现象:第二个参数的类型,ev n,依赖于第一个参数 n 的值。 + 有趣的现象:第二个参数的类型,even n,依赖于第一个参数 n 的值。diff --git a/lf-current/ProofObjects.v b/lf-current/ProofObjects.v index cf830123..88b91854 100644 --- a/lf-current/ProofObjects.v +++ b/lf-current/ProofObjects.v @@ -6,7 +6,7 @@ From LF Require Export IndProp. (** "_'算法是证明的计算性内容。'_" --Robert Harper *) (** 前文已讨论过 Coq 既可以用 [nat]、[list] 等归纳类型及其函数_'编程'_,又可 - 以用归纳命题(如 [ev])、蕴含式、全称量词等工具_'证明'_程序的性质。我们一直 + 以用归纳命题(如 [even])、蕴含式、全称量词等工具_'证明'_程序的性质。我们一直 以来区别对待此两种用法,在很多情况下确实可以这样。但也有迹象表明在 Coq 中编 程与证明紧密相关。例如,关键字 [Inductive] 同时用于声明数据类型和命题,以及 [->] 同时用于描述函数类型和逻辑蕴含式。这可并不是语法上的巧合!事实上,在 Coq @@ -23,24 +23,23 @@ From LF Require Export IndProp. 答曰:类型也! *) -(** 回顾一下 [ev] 这个性质的形式化定义。 *) +(** 回顾一下 [even] 这个性质的形式化定义。 *) -Print ev. +Print even. (* ==> - Inductive ev : nat -> Prop := - | ev_0 : ev 0 - | ev_SS : forall n, ev n -> ev (S (S n)). + Inductive even : nat -> Prop := + | ev_0 : even 0 + | ev_SS : forall n, even n -> even (S (S n)). *) -(** 试以另一种方式解读“[:]”:以“是……的证明”取代“具有……类型”。例如将定义第二行的 - [ev_0 : ev 0] 读作“[ev_0] 是 [ev 0] 的证明”以代替“[ev_0] 具有 [ev 0] 类型”。 - *) +(** 试以另一种方式解读“[:]”:以“是……的证明”取代“具有……类型”。例如将定义 [even] + 第二行的 [ev_0 : even 0] 读作“[ev_0] 是 [[even] 0] 的证明”以代替“[ev_0] 具有 + [[even] 0] 类型”。 *) (** 此处 [:] 既在类型层面表达“具有……类型”,又在命题层面表示“证明了……”。这种双关 称为_'柯里-霍华德同构(Curry-Howard correspondence)'_。它指出了逻辑与计算之 间的深层关联: - 命题 ~ 类型 证明 ~ 数据值 @@ -50,15 +49,15 @@ Print ev. Check ev_SS. (* ===> ev_SS : forall n, - ev n -> - ev (S (S n)) *) + even n -> + even (S (S n)) *) -(** 可以将其读作“[ev_SS] 构造子接受两个参数——数字 [n] 以及命题 [ev n] 的证明——并 - 产生 [ev (S (S n))] 的证明。” *) +(** 可以将其读作“[ev_SS] 构造子接受两个参数——数字 [n] 以及命题 [even n] + 的证明——并产生 [even (S (S n))] 的证明。” *) -(** 现在让我们回顾一下之前有关 [ev] 的一个证明。 *) +(** 现在让我们回顾一下之前有关 [even] 的一个证明。 *) -Theorem ev_4 : ev 4. +Theorem ev_4 : even 4. Proof. apply ev_SS. apply ev_SS. apply ev_0. Qed. @@ -67,24 +66,28 @@ Proof. Print ev_4. (* ===> ev_4 = ev_SS 2 (ev_SS 0 ev_0) - : ev 4 *) + : even 4 *) (** 实际上,我们也可以不借助脚本_'直接'_写出表达式作为证明。 *) Check (ev_SS 2 (ev_SS 0 ev_0)). -(* ===> ev 4 *) +(* ===> even 4 *) (** 表达式 [ev_SS 2 (ev_SS 0 ev_0)] 可视为向构造子 [ev_SS] 传入参数 2 和 0 - 等参数,以及对应的 [ev 2] 与 [ev 0] 之依据所构造的证明。或言之,视 [ev_SS] + 等参数,以及对应的 [even 2] 与 [even 0] 之依据所构造的证明。或言之,视 [ev_SS] 为“构造证明”之原语,需要给定一个数字,并进一步提供该数为偶数之依据以构造证明。 - 其类型表明了它的功能:[[ forall n, ev n -> ev (S (S n)) ]];类似地,多态类型 [forall X, - list X] 表明可以将 [nil] 视为从某类型到由该类型元素组成的空列表的函数。 *) + 其类型表明了它的功能: + + forall n, even n -> even (S (S n)) + + 类似地,多态类型 [forall X, list X] 表明可以将 [nil] + 视为从某类型到由该类型元素组成的空列表的函数。 *) (** 我们在 [Logic] 这一章中已经了解到,我们可以使用函数应用 的语法来实例化引理中的全称量化变量,也可以使用该语法提供引理所要求 的假设。例如: *) -Theorem ev_4': ev 4. +Theorem ev_4': even 4. Proof. apply (ev_SS 2 (ev_SS 0 ev_0)). Qed. @@ -98,8 +101,7 @@ Qed. Coq如何构造该项。为了了解这个过程是如何进行的,在下面的策略证明里, 我们在多个地方使用 [Show Proof] 指令来显示当前证明树的状态。 *) - -Theorem ev_4'' : ev 4. +Theorem ev_4'' : even 4. Proof. Show Proof. apply ev_SS. @@ -120,28 +122,29 @@ Qed. 手动构造想要的证据,如下所示。此处我们可以通过 [Definition] (而不 是 [Theorem])来直接给这个证据一个全局名称。 *) -Definition ev_4''' : ev 4 := +Definition ev_4''' : even 4 := ev_SS 2 (ev_SS 0 ev_0). (** 所有这些构造证明的不同方式,对应的存储在全局环境中的证明是完全一样的。 *) Print ev_4. -(* ===> ev_4 = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *) +(* ===> ev_4 = ev_SS 2 (ev_SS 0 ev_0) : even 4 *) Print ev_4'. -(* ===> ev_4' = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *) +(* ===> ev_4' = ev_SS 2 (ev_SS 0 ev_0) : even 4 *) Print ev_4''. -(* ===> ev_4'' = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *) +(* ===> ev_4'' = ev_SS 2 (ev_SS 0 ev_0) : even 4 *) Print ev_4'''. -(* ===> ev_4''' = ev_SS 2 (ev_SS 0 ev_0) : ev 4 *) +(* ===> ev_4''' = ev_SS 2 (ev_SS 0 ev_0) : even 4 *) + +(** **** 练习:2 星, standard (eight_is_even) -(** **** 练习:2 星 (eight_is_even) *) -(** 写出对应 [ev 8] 的策略证明和证明对象。 *) + 写出对应 [even 8] 的策略证明和证明对象。 *) -Theorem ev_8 : ev 8. +Theorem ev_8 : even 8. Proof. (* 请在此处解答 *) Admitted. -Definition ev_8' : ev 8 +Definition ev_8' : even 8 (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. (** [] *) @@ -158,7 +161,7 @@ Definition ev_8' : ev 8 (** 例如,考虑下列陈述: *) -Theorem ev_plus4 : forall n, ev n -> ev (4 + n). +Theorem ev_plus4 : forall n, even n -> even (4 + n). Proof. intros n H. simpl. apply ev_SS. @@ -168,30 +171,30 @@ Qed. (** 对应 [ev_plus4] 的证明对象是什么? - 我们在寻找一个_'类型(Type)'_是 [forall n, ev n -> ev (4 + n)] 的表达式——也 + 我们在寻找一个_'类型(Type)'_是 [forall n, even n -> even (4 + n)] 的表达式——也 就是说,一个接受两个参数(一个数字和一个证据)并返回一个证据的 _'函数(Function)'_! 它的证据对象: *) -Definition ev_plus4' : forall n, ev n -> ev (4 + n) := - fun (n : nat) => fun (H : ev n) => +Definition ev_plus4' : forall n, even n -> even (4 + n) := + fun (n : nat) => fun (H : even n) => ev_SS (S (S n)) (ev_SS n H). (** 回顾 [fun n => blah] 意味着“一个函数,给定 [n],产生 [blah]”, 并且Coq认为 [4 + n] 和 [S (S (S (S n)))] 是同义词,所以另一种写出 这个定义的方式是: *) -Definition ev_plus4'' (n : nat) (H : ev n) - : ev (4 + n) := +Definition ev_plus4'' (n : nat) (H : even n) + : even (4 + n) := ev_SS (S (S n)) (ev_SS n H). Check ev_plus4''. (* ===> - : forall n : nat, ev n -> ev (4 + n) *) + : forall n : nat, even n -> even (4 + n) *) (** 当我们将 [ev_plus4] 证明的命题视为一个函数类型时,我们可以发现一个 - 有趣的现象:第二个参数的类型,[ev n],依赖于第一个参数 [n] 的_'值'_。 + 有趣的现象:第二个参数的类型,[even n],依赖于第一个参数 [n] 的_'值'_。 虽然这样的_'依赖类型 (Dependent types)'_在传统的编程语言中并不存在, 但是它们对于编程来说有时候非常有用。最近它们在函数式编程社区里的活 @@ -206,11 +209,10 @@ Check ev_plus4''. = nat -> nat *) - (** 例如,考虑下列命题: *) Definition ev_plus2 : Prop := - forall n, forall (E : ev n), ev (n + 2). + forall n, forall (E : even n), even (n + 2). (** 这个命题的一个证明项会是一个拥有两个参数的函数:一个数字[n] 和一个表明[n]是偶数的证据[E]。但是对于这个证据来说,名字[E]并没有 @@ -218,12 +220,12 @@ Definition ev_plus2 : Prop := 义。因此我们可以使用虚拟标志符[_]来替换真实的名字: *) Definition ev_plus2' : Prop := - forall n, forall (_ : ev n), ev (n + 2). + forall n, forall (_ : even n), even (n + 2). (** 或者,等同地,我们可以使用更加熟悉的记号: *) Definition ev_plus2'' : Prop := - forall n, ev n -> ev (n + 2). + forall n, even n -> even (n + 2). (** 总的来说,"[P -> Q]"只是 "[forall (_:P), Q]"的语法糖。 *) @@ -232,7 +234,7 @@ Definition ev_plus2'' : Prop := (** 如果我们可以通过显式地给出项,而不是执行策略脚本,来构造证明,你可 能会好奇我们是否可以通过_'策略'_,而不是显式地给出项,来构造_'程序'_。 - 自然地,答案是可以!*) + 自然地,答案是可以! *) Definition add1 : nat -> nat. intro n. @@ -260,20 +262,19 @@ Compute add1 2. 这个特性主要是在定义拥有依赖类型的函数时非常有用。我们不会在本书中 详细讨论后者。但是它确实表明了Coq里面基本思想的一致性和正交性。 *) - (* ################################################################# *) (** * 逻辑联结词作为归纳类型 *) -(** 归纳定义足够用于表达我们目前为止遇到的大多数的联结词和量词。事实上, - 只有全称量化(因此也包括蕴含式)是Coq内置的,所有其他的都是被归纳 +(** 归纳定义足够用于表达我们目前为止遇到的大多数的联结词。事实上, + 只有全称量化(以及作为特殊情况的蕴含式)是Coq内置的,所有其他的都是被归纳 定义的。在这一节中我们会看到它们的定义。 *) - Module Props. -(** ** 合取 +(* ================================================================= *) +(** ** 合取 *) - 为了证明[P /\ Q]成立,我们必须同时给出[P]和[Q]的证据。因此,我们可 +(** 为了证明[P /\ Q]成立,我们必须同时给出[P]和[Q]的证据。因此,我们可 以合理地将[P /\ Q]的证明对象定义为包含两个证明的元祖:一个是[P]的 证明,另一个是[Q]的证明。即我们拥有如下定义。 *) @@ -294,7 +295,9 @@ Print prod. (** 这个定义能够解释为什么[destruct]和[intros]模式能用于一个合取前提。 情况分析允许我们考虑所有[P /\ Q]可能被证明的方式——只有一种方式(即 - [conj]构造子)。类似地,[split]策略能够用于所有只有一个构造子的归 + [conj]构造子)。 + + 类似地,[split]策略能够用于所有只有一个构造子的归 纳定义命题。特别地,它能够用于[and]: *) Lemma and_comm : forall P Q : Prop, P /\ Q <-> Q /\ P. @@ -311,7 +314,7 @@ Qed. (** 这解释了为什么一直以来我们能够使用策略来操作[and]的归纳定义。我们 也可以使用模式匹配来用它直接构造证明。例如: *) -Definition and_comm'_aux P Q (H : P /\ Q) := +Definition and_comm'_aux P Q (H : P /\ Q) : Q /\ P := match H with | conj HP HQ => conj HQ HP end. @@ -319,18 +322,18 @@ Definition and_comm'_aux P Q (H : P /\ Q) := Definition and_comm' P Q : P /\ Q <-> Q /\ P := conj (and_comm'_aux P Q) (and_comm'_aux Q P). -(** **** 练习:2 星, optional (conj_fact) *) -(** 构造一个证明对象来证明下列命题。 *) +(** **** 练习:2 星, standard, optional (conj_fact) + + 构造一个证明对象来证明下列命题。 *) Definition conj_fact : forall P Q R, P /\ Q -> Q /\ R -> P /\ R (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. (** [] *) +(* ================================================================= *) +(** ** 析取 *) - -(** ** 析取 - - 析取的归纳定义有两个构造子,分别用于析取的两边: *) +(** 析取的归纳定义有两个构造子,分别用于析取的两边: *) Module Or. @@ -345,17 +348,19 @@ End Or. 又一次地,我们可以不使用策略,直接写出涉及[or]的定义的证明对象。 *) -(** **** 练习:2 星, optional (or_commut'') *) -(** 尝试写下[or_commut]的显式证明对象。(不要使用[Print]来偷看我们已经 +(** **** 练习:2 星, standard, optional (or_commut'') + + 尝试写下[or_commut]的显式证明对象。(不要使用[Print]来偷看我们已经 定义的版本!) *) Definition or_comm : forall P Q, P \/ Q -> Q \/ P (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. (** [] *) -(** ** 存在量化 +(* ================================================================= *) +(** ** 存在量化 *) - 为了给出存在量词的证据,我们将一个证据类型[x]和[x]满足性质[P]的证明打包在一起: *) +(** 为了给出存在量词的证据,我们将一个证据类型[x]和[x]满足性质[P]的证明打包在一起: *) Module Ex. @@ -371,19 +376,20 @@ End Ex. (** 我们更加熟悉的类型[exists x, P x]可以转换为一个涉及[ex]的表达式: *) -Check ex (fun n => ev n). -(* ===> exists n : nat, ev n +Check ex (fun n => even n). +(* ===> exists n : nat, even n : Prop *) (** 下面是我们如何定义一个涉及[ex]的显式证明对象: *) -Definition some_nat_is_even : exists n, ev n := - ex_intro ev 4 (ev_SS 2 (ev_SS 0 ev_0)). +Definition some_nat_is_even : exists n, even n := + ex_intro even 4 (ev_SS 2 (ev_SS 0 ev_0)). + +(** **** 练习:2 星, standard, optional (ex_ev_Sn) -(** **** 练习:2 星, optional (ex_ev_Sn) *) -(** 完成下列证明对象的定义: *) + 完成下列证明对象的定义: *) -Definition ex_ev_Sn : ex (fun n => ev (S n)) +Definition ex_ev_Sn : ex (fun n => even (S n)) (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. (** [] *) @@ -401,7 +407,7 @@ Inductive True : Prop := (** [False]也一样的简单——事实上,它是如此简单,以致于第一眼看上去像是一个 语法错误。 *) -Inductive False : Prop :=. +Inductive False : Prop := . (** 也就是说, [False]是一个_'没有'_构造子的归纳类型--即,没有任何方式能 够构造一个它的证明。 *) @@ -426,8 +432,10 @@ Notation "x == y" := (eq x y) (** 我们可以这样理解这个定义,给定一个集合[X],它定义了由[X]的一对值 ([x]和[y])所索引的“[x]与[y]相等”的一_'系列(Family)'_的命题。只有 - 一种方式能够构造该系列中任意成员的证据:将构造子[eq_refl]应用到一 - 个类型[X]和一个值[x:X],产生一个[x]等于[x]的证据。 *) + 一种方式能够构造该系列中成员的证据:将构造子[eq_refl]应用到类型[X] + 和值[x:X],产生一个[x]等于[x]的证据。 + + 其它形如 [eq x y] 的类型中的 [x] 和 [y] 并不相同,因此是非居留的。 *) (** 我们可以使用[eq_refl]来构造证据,比如说,[2 = 2]。那么我们能否使用 它来构造证据[1 + 1 = 2]呢?答案是肯定的。事实上,它就是同一个证据! @@ -457,9 +465,9 @@ Definition four' : 2 + 2 == 1 + 3 := Definition singleton : forall (X:Type) (x:X), []++[x] == x::[] := fun (X:Type) (x:X) => eq_refl [x]. +(** **** 练习:2 星, standard (equality__leibniz_equality) -(** **** 练习:2 星 (equality__leibniz_equality) *) -(** 相等关系的归纳定义隐含了_'Leibniz相等关系(Leibniz equality)'_:当我们 + 相等关系的归纳定义隐含了_'Leibniz相等关系(Leibniz equality)'_:当我们 说“[x]和[y]相等的时候”,我们意味着所有[x]满足的性质[P],对于[y] 来说也满足。 *) @@ -469,8 +477,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:5 星, optional (leibniz_equality__equality) *) -(** 请说明,事实上,相等关系的归纳定义和Leibniz相等关系是 +(** **** 练习:5 星, standard, optional (leibniz_equality__equality) + + 请说明,事实上,相等关系的归纳定义和Leibniz相等关系是 _'等价的(equivalent)'_。 *) Lemma leibniz_equality__equality : forall (X : Type) (x y: X), @@ -482,9 +491,8 @@ Proof. End MyEquality. - (* ================================================================= *) -(** ** 反演, 再一次 *) +(** ** 再论反演 *) (** 我们曾经见过[inversion]被同时用于相等关系前提,和关于被归纳定义的命 题的前提。现在我们明白了实际上它们是同一件事情。那么我们现在可以细 @@ -523,3 +531,4 @@ End MyEquality. 略会将这个事实加入到上下文中。 *) +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/ProofObjectsTest.v b/lf-current/ProofObjectsTest.v index ab66e0df..113a272f 100644 --- a/lf-current/ProofObjectsTest.v +++ b/lf-current/ProofObjectsTest.v @@ -37,7 +37,7 @@ idtac " ". idtac "#> ev_8". idtac "Possible points: 1". -check_type @ev_8 ((ev 8)). +check_type @ev_8 ((even 8)). idtac "Assumptions:". Abort. Print Assumptions ev_8. @@ -46,7 +46,7 @@ idtac " ". idtac "#> ev_8'". idtac "Possible points: 1". -check_type @ev_8' ((ev 8)). +check_type @ev_8' ((even 8)). idtac "Assumptions:". Abort. Print Assumptions ev_8'. @@ -84,3 +84,5 @@ Print Assumptions MyEquality.equality__leibniz_equality. idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:14:56 UTC 2019 *) diff --git a/lf-current/Rel.html b/lf-current/Rel.html index ec968b67..f8ff3562 100644 --- a/lf-current/Rel.html +++ b/lf-current/Rel.html @@ -49,7 +49,7 @@@@ -320,8 +329,8 @@ProofObjects柯里-霍华德对应
- ∀ (x:nat), nat
- = ∀ (_:nat), nat
+ ∀(x:nat), nat
+ = ∀(_:nat), nat
= nat → nat@@ -334,7 +343,7 @@ProofObjects柯里-霍华德对应
Definition ev_plus2 : Prop :=
- ∀ n, ∀ (E : ev n), ev (n + 2).
+ ∀n, ∀(E : even n), even (n + 2).
@@ -346,7 +355,7 @@ProofObjects柯里-霍华德对应
Definition ev_plus2' : Prop :=
- ∀ n, ∀ (_ : ev n), ev (n + 2).
+ ∀n, ∀(_ : even n), even (n + 2).
@@ -355,21 +364,21 @@ProofObjects柯里-霍华德对应
Definition ev_plus2'' : Prop :=
- ∀ n, ev n → ev (n + 2).
+ ∀n, even n → even (n + 2).
-总的来说,"P → Q"只是 "∀(_:P), Q"的语法糖。 +总的来说,"P → Q"只是 "∀ (_:P), Q"的语法糖。-使用策略编程
+使用策略编程
如果我们可以通过显式地给出项,而不是执行策略脚本,来构造证明,你可 能会好奇我们是否可以通过策略,而不是显式地给出项,来构造程序。 - 自然地,答案是可以! + 自然地,答案是可以!@@ -382,7 +391,7 @@ProofObjects柯里-霍华德对应 Print add1.
(* ==>
add1 = fun n : nat => S n
- : nat -> nat
+ : nat -> nat
*)
Compute add1 2.
(* ==> 3 : nat *)
@@ -403,12 +412,12 @@ProofObjects柯里-霍华德对应
-逻辑联结词作为归纳类型
+逻辑联结词作为归纳类型
- 归纳定义足够用于表达我们目前为止遇到的大多数的联结词和量词。事实上, - 只有全称量化(因此也包括蕴含式)是Coq内置的,所有其他的都是被归纳 + 归纳定义足够用于表达我们目前为止遇到的大多数的联结词。事实上, + 只有全称量化(以及作为特殊情况的蕴含式)是Coq内置的,所有其他的都是被归纳 定义的。在这一节中我们会看到它们的定义。@@ -417,12 +426,11 @@ProofObjects柯里-霍华德对应
-@@ -443,18 +451,22 @@合取
- +合取
- 为了证明P ∧ Q成立,我们必须同时给出P和Q的证据。因此,我们可 + 为了证明P ∧ Q成立,我们必须同时给出P和Q的证据。因此,我们可 以合理地将P ∧ Q的证明对象定义为包含两个证明的元祖:一个是P的 证明,另一个是Q的证明。即我们拥有如下定义。ProofObjects柯里-霍华德对应 Print prod.
(* ===>
Inductive prod (X Y : Type) : Type :=
- | pair : X -> Y -> X * Y. *)
+ | pair : X -> Y -> X * Y. *)
这个定义能够解释为什么destruct和intros模式能用于一个合取前提。 情况分析允许我们考虑所有P ∧ Q可能被证明的方式——只有一种方式(即 - conj构造子)。类似地,split策略能够用于所有只有一个构造子的归 + conj构造子)。 + ++ + 类似地,split策略能够用于所有只有一个构造子的归 纳定义命题。特别地,它能够用于and:-Lemma and_comm : ∀ P Q : Prop, P ∧ Q ↔ Q ∧ P.
+Lemma and_comm : ∀P Q : Prop, P ∧ Q ↔ Q ∧ P.
Proof.
intros P Q. split.
- intros [HP HQ]. split.
@@ -472,7 +484,7 @@ProofObjects柯里-霍华德对应
-Definition and_comm'_aux P Q (H : P ∧ Q) :=
+Definition and_comm'_aux P Q (H : P ∧ Q) : Q ∧ P :=
match H with
| conj HP HQ ⇒ conj HQ HP
end.
@@ -481,12 +493,12 @@ProofObjects柯里-霍华德对应
-Definition conj_fact : ∀ P Q R, P ∧ Q → Q ∧ R → P ∧ R@@ -494,12 +506,11 @@
+Definition conj_fact : ∀P Q R, P ∧ Q → Q ∧ R → P ∧ R
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
ProofObjects柯里-霍华德对应
@@ -519,13 +530,13 @@ProofObjects柯里-霍华德对应 又一次地,我们可以不使用策略,直接写出涉及or的定义的证明对象。
-练习:2 星, optional (or_commut'')
+练习:2 星, standard, optional (or_commut'')
尝试写下or_commut的显式证明对象。(不要使用Print来偷看我们已经 定义的版本!)-Definition or_comm : ∀ P Q, P ∨ Q → Q ∨ P@@ -533,18 +544,17 @@
+Definition or_comm : ∀P Q, P ∨ Q → Q ∨ P
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
ProofObjects柯里-霍华德对应
Module Ex.@@ -555,12 +565,12 @@
Inductive ex {A : Type} (P : A → Prop) : Prop :=
-| ex_intro : ∀ x : A, P x → ex P.
+| ex_intro : ∀x : A, P x → ex P.
End Ex.
ProofObjects柯里-霍华德对应 证据类型x和P x的证 明,可以构造ex P的证据的方式。
- 我们更加熟悉的类型∃x, P x可以转换为一个涉及ex的表达式: + 我们更加熟悉的类型∃ x, P x可以转换为一个涉及ex的表达式:-Check ex (fun n ⇒ ev n).@@ -569,17 +579,17 @@
-(* ===> exists n : nat, ev n
+Check ex (fun n ⇒ even n).
+(* ===> exists n : nat, even n
: Prop *)
ProofObjects柯里-霍华德对应
-Definition some_nat_is_even : ∃ n, ev n :=
- ex_intro ev 4 (ev_SS 2 (ev_SS 0 ev_0)).
+Definition some_nat_is_even : ∃n, even n :=
+ ex_intro even 4 (ev_SS 2 (ev_SS 0 ev_0)).
-Definition ex_ev_Sn : ex (fun n ⇒ ev (S n))@@ -587,7 +597,7 @@
+Definition ex_ev_Sn : ex (fun n ⇒ even (S n))
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
ProofObjects柯里-霍华德对应
-Inductive False : Prop :=.
+Inductive False : Prop := .
@@ -622,7 +632,7 @@ProofObjects柯里-霍华德对应
-相等关系
+相等关系
@@ -634,7 +644,7 @@ProofObjects柯里-霍华德对应 Module MyEquality.
Inductive eq {X:Type} : X → X → Prop :=
-| eq_refl : ∀ x, eq x x.
+| eq_refl : ∀x, eq x x.
Notation "x == y" := (eq x y)
(at level 70, no associativity)
: type_scope.
@@ -643,8 +653,12 @@ProofObjects柯里-霍华德对应
我们可以这样理解这个定义,给定一个集合X,它定义了由X的一对值 (x和y)所索引的“x与y相等”的一系列(Family)的命题。只有 - 一种方式能够构造该系列中任意成员的证据:将构造子eq_refl应用到一 - 个类型X和一个值x:X,产生一个x等于x的证据。 + 一种方式能够构造该系列中成员的证据:将构造子eq_refl应用到类型X + 和值x:X,产生一个x等于x的证据。 + ++ + 其它形如 eq x y 的类型中的 x 和 y 并不相同,因此是非居留的。我们可以使用eq_refl来构造证据,比如说,2 = 2。那么我们能否使用 @@ -685,20 +699,20 @@ProofObjects柯里-霍华德对应 Definition four' : 2 + 2 == 1 + 3 :=
eq_refl 4.
-Definition singleton : ∀ (X:Type) (x:X), []++[x] == x::[] :=
+Definition singleton : ∀(X:Type) (x:X), []++[x] == x::[] :=
fun (X:Type) (x:X) ⇒ eq_refl [x].
-练习:2 星 (equality__leibniz_equality)
+练习:2 星, standard (equality__leibniz_equality)
相等关系的归纳定义隐含了Leibniz相等关系(Leibniz equality):当我们 说“x和y相等的时候”,我们意味着所有x满足的性质P,对于y 来说也满足。-Lemma equality__leibniz_equality : ∀ (X : Type) (x y: X),@@ -707,14 +721,14 @@
- x == y → ∀ P:X→Prop, P x → P y.
+Lemma equality__leibniz_equality : ∀(X : Type) (x y: X),
+ x == y → ∀P:X→Prop, P x → P y.
Proof.
(* 请在此处解答 *) Admitted.
ProofObjects柯里-霍华德对应
-练习:5 星, optional (leibniz_equality__equality)
+练习:5 星, standard, optional (leibniz_equality__equality)
请说明,事实上,相等关系的归纳定义和Leibniz相等关系是 等价的(equivalent)。-Lemma leibniz_equality__equality : ∀ (X : Type) (x y: X),@@ -726,7 +740,7 @@
- (∀ P:X→Prop, P x → P y) → x == y.
+Lemma leibniz_equality__equality : ∀(X : Type) (x y: X),
+ (∀P:X→Prop, P x → P y) → x == y.
Proof.
(* 请在此处解答 *) Admitted.
ProofObjects柯里-霍华德对应
-+反演, 再一次
+再论反演
@@ -803,6 +817,10 @@ProofObjects柯里-霍华德对应 的额外的信息:它告诉eq的两个参数必须是一样的。于是inversion策 略会将这个事实加入到上下文中。
+ +(* Sat Jan 26 15:14:46 UTC 2019 *)
+Rel关系的性质
-关系
+关系
@@ -75,9 +75,9 @@Rel关系的性质
Print le.@@ -89,7 +89,7 @@
-(* ====> Inductive le (n : nat) : nat -> Prop :=
+(* ====> Inductive le (n : nat) : nat -> Prop :=
le_n : n <= n
- | le_S : forall m : nat, n <= m -> n <= S m *)
+ | le_S : forall m : nat, n <= m -> n <= S m *)
Check le : nat → nat → Prop.
Check le : relation nat.
Rel关系的性质
-基本性质
+基本性质
@@ -98,7 +98,7 @@Rel关系的性质
如何从一种关系构造出另一种关系等等。例如:-偏函数
+偏函数
@@ -109,7 +109,7 @@Rel关系的性质
Definition partial_function {X: Type} (R: relation X) :=
- ∀ x y1 y2 : X, R x y1 → R x y2 → y1 = y2.
+ ∀x y1 y2 : X, R x y1 → R x y2 → y1 = y2.
@@ -118,7 +118,7 @@Rel关系的性质
Print next_nat.
-(* ====> Inductive next_nat (n : nat) : nat -> Prop :=
+(* ====> Inductive next_nat (n : nat) : nat -> Prop :=
nn : next_nat n (S n) *)
Check next_nat : relation nat.
Theorem next_nat_partial_function :
@@ -141,7 +141,7 @@Rel关系的性质
Theorem le_not_a_partial_function :
- ¬ (partial_function le).
+ ¬(partial_function le).
Proof.
@@ -155,8 +155,8 @@Rel关系的性质
-练习:2 星, optional (total_relation_not_partial)
- 请证明之前定义的 total_relation 不是偏函数。 +练习:2 星, standard, optional (total_relation_not_partial)
+ 请证明 IndProp 一章练习题中定义的 total_relation 不是偏函数。@@ -167,8 +167,8 @@Rel关系的性质
-练习:2 星, optional (empty_relation_partial)
- 请证明之前定义的 empty_relation 是偏函数。 +练习:2 星, standard, optional (empty_relation_partial)
+ 请证明 IndProp 一章练习题中定义的 empty_relation 是偏函数。@@ -179,7 +179,7 @@Rel关系的性质
-自反关系
+自反关系
@@ -188,7 +188,7 @@Rel关系的性质
Definition reflexive {X: Type} (R: relation X) :=
- ∀ a : X, R a a.
+ ∀a : X, R a a.
Theorem le_reflexive :
reflexive le.
@@ -199,7 +199,7 @@Rel关系的性质
-传递关系
+传递关系
@@ -208,7 +208,7 @@Rel关系的性质
Definition transitive {X: Type} (R: relation X) :=
- ∀ a b c : X, (R a b) → (R b c) → (R a c).
+ ∀a b c : X, (R a b) → (R b c) → (R a c).
Theorem le_trans :
transitive le.
@@ -236,7 +236,7 @@Rel关系的性质
-@@ -256,7 +256,7 @@练习:2 星, optional (le_trans_hard_way)
+练习:2 星, standard, optional (le_trans_hard_way)
我们也可以不用 le_trans,直接通过归纳法来证明 lt_trans, 不过这会耗费更多精力。请完成以下定理的证明。Rel关系的性质
@@ -282,7 +282,7 @@Rel关系的性质
-Theorem le_Sn_le : ∀ n m, S n ≤ m → n ≤ m.
+Theorem le_Sn_le : ∀n m, S n ≤ m → n ≤ m.
Proof.
@@ -294,11 +294,11 @@Rel关系的性质
-Theorem le_S_n : ∀ n m,
+Theorem le_S_n : ∀n m,
(S n ≤ S m) → (n ≤ m).
Proof.
(* 请在此处解答 *) Admitted.
@@ -308,7 +308,7 @@Rel关系的性质
-练习:2 星, optional (le_Sn_n_inf)
+练习:2 星, standard, optional (le_Sn_n_inf)
请提写出以下定理的非形式化证明:@@ -332,12 +332,12 @@Rel关系的性质
-Theorem le_Sn_n : ∀ n,@@ -350,7 +350,7 @@
- ¬ (S n ≤ n).
+Theorem le_Sn_n : ∀n,
+ ¬(S n ≤ n).
Proof.
(* 请在此处解答 *) Admitted.
Rel关系的性质
我们先看一些其它的概念,作为在 Coq 中对关系进行操作的练习...-对称关系与反对称关系
+对称关系与反对称关系
@@ -359,16 +359,16 @@Rel关系的性质
Definition symmetric {X: Type} (R: relation X) :=
- ∀ a b : X, (R a b) → (R b a).
+ ∀a b : X, (R a b) → (R b a).
Theorem le_not_symmetric :@@ -382,11 +382,11 @@
- ¬ (symmetric le).
+ ¬(symmetric le).
Proof.
(* 请在此处解答 *) Admitted.
Rel关系的性质
Definition antisymmetric {X: Type} (R: relation X) :=
- ∀ a b : X, (R a b) → (R b a) → a = b.
+ ∀a b : X, (R a b) → (R b a) → a = b.
@@ -400,11 +400,11 @@Rel关系的性质
-Theorem le_step : ∀ n m p,
+Theorem le_step : ∀n m p,
n < m →
m ≤ S p →
n ≤ p.
@@ -416,7 +416,7 @@Rel关系的性质
-Theorem next_nat_closure_is_le : ∀ n m,
+Theorem next_nat_closure_is_le : ∀n m,
(n ≤ m) ↔ ((clos_refl_trans next_nat) n m).
Proof.
intros n m. split.
- - (* -> *)
+ - (* -> *)
intro H. induction H.
+ (* le_n *) apply rt_refl.
+ (* le_S *)
@@ -541,7 +541,7 @@Rel关系的性质
-Lemma rsc_R : ∀ (X:Type) (R:relation X) (x y : X),diff --git a/lf-current/Rel.v b/lf-current/Rel.v index e915757c..be491428 100644 --- a/lf-current/Rel.v +++ b/lf-current/Rel.v @@ -82,17 +82,21 @@ Proof. - apply le_S. apply le_n. } discriminate Nonsense. Qed. -(** **** 练习:2 星, optional (total_relation_not_partial) *) -(** 请证明之前定义的 [total_relation] 不是偏函数。 *) +(** **** 练习:2 星, standard, optional (total_relation_not_partial) -(* 请在此处解答 *) -(** [] *) + 请证明 [IndProp] 一章练习题中定义的 [total_relation] 不是偏函数。 *) -(** **** 练习:2 星, optional (empty_relation_partial) *) -(** 请证明之前定义的 [empty_relation] 是偏函数。 *) +(* 请在此处解答 -(* 请在此处解答 *) -(** [] *) + [] *) + +(** **** 练习:2 星, standard, optional (empty_relation_partial) + + 请证明 [IndProp] 一章练习题中定义的 [empty_relation] 是偏函数。 *) + +(* 请在此处解答 + + [] *) (* ----------------------------------------------------------------- *) (** *** 自反关系 *) @@ -133,8 +137,9 @@ Proof. apply Hnm. apply Hmo. Qed. -(** **** 练习:2 星, optional (le_trans_hard_way) *) -(** 我们也可以不用 [le_trans],直接通过归纳法来证明 [lt_trans], +(** **** 练习:2 星, standard, optional (le_trans_hard_way) + + 我们也可以不用 [le_trans],直接通过归纳法来证明 [lt_trans], 不过这会耗费更多精力。请完成以下定理的证明。 *) Theorem lt_trans' : @@ -147,8 +152,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (lt_trans'') *) -(** 再将此定理证明一遍,不过这次要对 [o] 使用归纳法。 *) +(** **** 练习:2 星, standard, optional (lt_trans'') + + 再将此定理证明一遍,不过这次要对 [o] 使用归纳法。 *) Theorem lt_trans'' : transitive lt. @@ -169,15 +175,16 @@ Proof. - apply H. Qed. -(** **** 练习:1 星, optional (le_S_n) *) +(** **** 练习:1 星, standard, optional (le_S_n) *) Theorem le_S_n : forall n m, (S n <= S m) -> (n <= m). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (le_Sn_n_inf) *) -(** 请提写出以下定理的非形式化证明: +(** **** 练习:2 星, standard, optional (le_Sn_n_inf) + + 请提写出以下定理的非形式化证明: Theorem: For every [n], [~ (S n <= n)] @@ -185,10 +192,11 @@ Proof. 不过在做形式化证明之前请先尝试写出非形式化的证明。 证明: *) - (* 请在此处解答 *) -(** [] *) + (* 请在此处解答 + + [] *) -(** **** 练习:1 星, optional (le_Sn_n) *) +(** **** 练习:1 星, standard, optional (le_Sn_n) *) Theorem le_Sn_n : forall n, ~ (S n <= n). Proof. @@ -206,7 +214,7 @@ Proof. Definition symmetric {X: Type} (R: relation X) := forall a b : X, (R a b) -> (R b a). -(** **** 练习:2 星, optional (le_not_symmetric) *) +(** **** 练习:2 星, standard, optional (le_not_symmetric) *) Theorem le_not_symmetric : ~ (symmetric le). Proof. @@ -218,14 +226,14 @@ Proof. Definition antisymmetric {X: Type} (R: relation X) := forall a b : X, (R a b) -> (R b a) -> a = b. -(** **** 练习:2 星, optional (le_antisymmetric) *) +(** **** 练习:2 星, standard, optional (le_antisymmetric) *) Theorem le_antisymmetric : antisymmetric le. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, optional (le_step) *) +(** **** 练习:2 星, standard, optional (le_step) *) Theorem le_step : forall n m p, n < m -> m <= S p -> @@ -327,7 +335,7 @@ Proof. intros X R x y H. apply rt1n_trans with y. apply H. apply rt1n_refl. Qed. -(** **** 练习:2 星, optional (rsc_trans) *) +(** **** 练习:2 星, standard, optional (rsc_trans) *) Lemma rsc_trans : forall (X:Type) (R: relation X) (x y z : X), clos_refl_trans_1n R x y -> @@ -340,7 +348,7 @@ Proof. (** 接着再用这些事实来证明这两个定义的自反性、 传递性封闭确实定义了同样的关系。 *) -(** **** 练习:3 星, optional (rtc_rsc_coincide) *) +(** **** 练习:3 星, standard, optional (rtc_rsc_coincide) *) Theorem rtc_rsc_coincide : forall (X:Type) (R: relation X) (x y : X), clos_refl_trans R x y <-> clos_refl_trans_1n R x y. @@ -348,3 +356,4 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) +(* Sat Jan 26 15:14:46 UTC 2019 *) diff --git a/lf-current/RelTest.v b/lf-current/RelTest.v index 68e94ed4..eceadf04 100644 --- a/lf-current/RelTest.v +++ b/lf-current/RelTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:14:58 UTC 2019 *) diff --git a/lf-current/Tactics.html b/lf-current/Tactics.html index 7fb686e7..d034af32 100644 --- a/lf-current/Tactics.html +++ b/lf-current/Tactics.html @@ -63,7 +63,7 @@
+Lemma rsc_R : ∀(X:Type) (R:relation X) (x y : X),
R x y → clos_refl_trans_1n R x y.
@@ -552,12 +552,12 @@Rel关系的性质
Lemma rsc_trans :
- ∀ (X:Type) (R: relation X) (x y z : X),
+ ∀(X:Type) (R: relation X) (x y z : X),
clos_refl_trans_1n R x y →
clos_refl_trans_1n R y z →
clos_refl_trans_1n R x z.
@@ -573,18 +573,22 @@Rel关系的性质
传递性封闭确实定义了同样的关系。-练习:3 星, optional (rtc_rsc_coincide)
+练习:3 星, standard, optional (rtc_rsc_coincide)
Theorem rtc_rsc_coincide :☐ +
- ∀ (X:Type) (R: relation X) (x y : X),
+ ∀(X:Type) (R: relation X) (x y : X),
clos_refl_trans R x y ↔ clos_refl_trans_1n R x y.
Proof.
(* 请在此处解答 *) Admitted.
+ +(* Sat Jan 26 15:14:46 UTC 2019 *)
+Tactics更多基本策略
-apply 策略
+apply 策略
@@ -71,7 +71,7 @@Tactics更多基本策略
-Theorem silly1 : ∀ (n m o p : nat),
+Theorem silly1 : ∀(n m o p : nat),
n = m →
[n;o] = [n;p] →
[n;o] = [m;p].
@@ -95,9 +95,9 @@Tactics更多基本策略
-Theorem silly2 : ∀ (n m o p : nat),
+Theorem silly2 : ∀(n m o p : nat),
n = m →
- (∀ (q r : nat), q = r → [q;o] = [r;p]) →
+ (∀(q r : nat), q = r → [q;o] = [r;p]) →
[n;o] = [m;p].
Proof.
intros n m o p eq1 eq2.
@@ -106,16 +106,16 @@Tactics更多基本策略
通常,当我们使用 apply H 时,语句 H 会以一个绑定了某些 - 通用变量(Universal Variables) 的 ∀开始。在 Coq 针对 H + 通用变量(Universal Variables) 的 ∀ 开始。在 Coq 针对 H 的结论匹配当前目标时,它会尝试为这些变量查找适当的值。例如, 当我们在以下证明中执行 apply eq2 时,eq2 中的通用变量 q 会以 n 实例化,而 r 会以 m 实例化。-Theorem silly2a : ∀ (n m : nat),
+Theorem silly2a : ∀(n m : nat),
(n,n) = (m,m) →
- (∀ (q r : nat), (q,q) = (r,r) → [q] = [r]) →
+ (∀(q r : nat), (q,q) = (r,r) → [q] = [r]) →
[n] = [m].
Proof.
intros n m eq1 eq2.
@@ -123,13 +123,13 @@Tactics更多基本策略
Theorem silly_ex :
- (∀ n, evenb n = true → oddb (S n) = true) →
+ (∀n, evenb n = true → oddb (S n) = true) →
oddb 3 = true →
evenb 4 = true.
Proof.
@@ -145,7 +145,7 @@Tactics更多基本策略
-Theorem silly3_firsttry : ∀ (n : nat),
+Theorem silly3_firsttry : ∀(n : nat),
true = (n =? 5) →
(S (S n)) =? 7 = true.
Proof.
@@ -169,13 +169,13 @@Tactics更多基本策略
-练习:3 星 (apply_exercise1)
+练习:3 星, standard (apply_exercise1)
(提示:你可以配合之前定义的引理来使用 apply,不仅限于当前上下文中的前提。 记住 Search 是你的朋友。)-Theorem rev_exercise1 : ∀ (l l' : list nat),
+Theorem rev_exercise1 : ∀(l l' : list nat),
l = rev l' →
l' = rev l.
Proof.
@@ -186,7 +186,7 @@Tactics更多基本策略
-练习:1 星, optional (apply_rewrite)
+练习:1 星, standard, optional (apply_rewrite)
简述 apply 与 rewrite 策略之区别。哪些情况下二者均可有效利用?@@ -197,7 +197,7 @@Tactics更多基本策略
☐-apply with 策略
+apply with 策略
@@ -205,7 +205,7 @@Tactics更多基本策略
-Example trans_eq_example : ∀ (a b c d e f : nat),
+Example trans_eq_example : ∀(a b c d e f : nat),
[a;b] = [c;d] →
[c;d] = [e;f] →
[a;b] = [e;f].
@@ -220,7 +220,7 @@Tactics更多基本策略
-Theorem trans_eq : ∀ (X:Type) (n m o : X),
+Theorem trans_eq : ∀(X:Type) (n m o : X),
n = m → m = o → n = o.
Proof.
intros X n m o eq1 eq2. rewrite → eq1. rewrite → eq2.
@@ -233,7 +233,7 @@Tactics更多基本策略
-Example trans_eq_example' : ∀ (a b c d e f : nat),
+Example trans_eq_example' : ∀(a b c d e f : nat),
[a;b] = [c;d] →
[c;d] = [e;f] →
[a;b] = [e;f].
@@ -260,11 +260,11 @@Tactics更多基本策略
apply trans_eq with [c;d]。-练习:3 星, optional (apply_with_exercise)
+练习:3 星, standard, optional (apply_with_exercise)
-Example trans_eq_exercise : ∀ (n m o p : nat),
+Example trans_eq_exercise : ∀(n m o p : nat),
m = (minustwo o) →
(n + p) = m →
(n + p) = (minustwo o).
@@ -275,7 +275,7 @@Tactics更多基本策略
☐-The injection and discriminate Tactics
+The injection and discriminate Tactics
@@ -322,7 +322,7 @@Tactics更多基本策略
-Theorem S_injective : ∀ (n m : nat),
+Theorem S_injective : ∀(n m : nat),
S n = S m →
n = m.
Proof.
@@ -343,7 +343,7 @@Tactics更多基本策略
-Theorem S_injective' : ∀ (n m : nat),
+Theorem S_injective' : ∀(n m : nat),
S n = S m →
n = m.
Proof.
@@ -369,7 +369,7 @@Tactics更多基本策略
-Theorem injection_ex1 : ∀ (n m o : nat),
+Theorem injection_ex1 : ∀(n m o : nat),
[n; m] = [o; o] →
[n] = [m].
Proof.
@@ -385,7 +385,7 @@Tactics更多基本策略
-Theorem injection_ex2 : ∀ (n m : nat),
+Theorem injection_ex2 : ∀(n m : nat),
[n] = [m] →
n = m.
Proof.
@@ -395,11 +395,11 @@Tactics更多基本策略
-Example injection_ex3 : ∀ (X : Type) (x y z : X) (l j : list X),
+Example injection_ex3 : ∀(X : Type) (x y z : X) (l j : list X),
x :: y :: l = z :: j →
y :: l = x :: j →
x = y.
@@ -431,7 +431,7 @@Tactics更多基本策略
-Theorem eqb_0_l : ∀ n,
+Theorem eqb_0_l : ∀n,
0 =? n = true → n = 0.
Proof.
intros n.
@@ -475,12 +475,12 @@Tactics更多基本策略
-Theorem discriminate_ex1 : ∀ (n : nat),-
+Theorem discriminate_ex1 : ∀(n : nat),
S n = O →
2 + 2 = 5.
Proof.
intros n contra. discriminate contra. Qed.
-Theorem discriminate_ex2 : ∀ (n m : nat),
+Theorem discriminate_ex2 : ∀(n m : nat),
false = true →
[n] = [m].
Proof.
@@ -496,12 +496,12 @@Tactics更多基本策略
练习:1 星 (discriminate_ex3)
+练习:1 星, standard (discriminate_ex3)
Example discriminate_ex3 :
- ∀ (X : Type) (x y z : X) (l j : list X),
+ ∀(X : Type) (x y z : X) (l j : list X),
x :: y :: l = [] →
x = z.
Proof.
@@ -512,19 +512,19 @@Tactics更多基本策略
- 构造子的单射性允许我们论证 ∀(n m : nat), S n = S m → n = m。 + 构造子的单射性允许我们论证 ∀ (n m : nat), S n = S m → n = m。 此蕴含式的交流(converse)是一个更加一般的关于构造子和函数的事实的实例, 在后面的几个地方我们会发现它很方便:-Theorem f_equal : ∀ (A B : Type) (f: A → B) (x y: A),
+Theorem f_equal : ∀(A B : Type) (f: A → B) (x y: A),
x = y → f x = f y.
Proof. intros A B f x y eq. rewrite eq. reflexivity. Qed.
-对前提使用策略
+对前提使用策略
@@ -537,7 +537,7 @@Tactics更多基本策略
-Theorem S_inj : ∀ (n m : nat) (b : bool),
+Theorem S_inj : ∀(n m : nat) (b : bool),
(S n) =? (S m) = b →
n =? m = b.
Proof.
@@ -563,7 +563,7 @@Tactics更多基本策略
-Theorem silly3' : ∀ (n : nat),-
+Theorem silly3' : ∀(n : nat),
(n =? 5 = true → (S (S n)) =? 7 = true) →
true = (n =? 5) →
true = ((S (S n)) =? 7).
@@ -585,12 +585,12 @@Tactics更多基本策略
练习:3 星, recommended (plus_n_n_injective)
+练习:3 星, standard, recommended (plus_n_n_injective)
请在此证明中练习使用“in”形式的变体。(提示:使用 plus_n_Sm。)-Theorem plus_n_n_injective : ∀ n m,
+Theorem plus_n_n_injective : ∀n m,
n + n = m + m →
n = m.
Proof.
@@ -601,7 +601,7 @@Tactics更多基本策略
☐- Theorem double_injective: ∀ n m,
+ Theorem double_injective: ∀n m,
double n = double m → n = m.@@ -640,7 +640,7 @@Tactics更多基本策略
-Theorem double_injective_FAILED : ∀ n m,
+Theorem double_injective_FAILED : ∀n m,
double n = double m →
n = m.
Proof.
@@ -778,7 +778,7 @@Tactics更多基本策略
-Theorem double_injective : ∀ n m,-
+Theorem double_injective : ∀n m,
double n = double m →
n = m.
Proof.
@@ -841,11 +841,11 @@Tactics更多基本策略
练习:2 星 (eqb_true)
+练习:2 星, standard (eqb_true)
-Theorem eqb_true : ∀ n m,
+Theorem eqb_true : ∀n m,
n =? m = true → n = m.
Proof.
(* 请在此处解答 *) Admitted.
@@ -855,7 +855,7 @@Tactics更多基本策略
-练习:2 星, advanced (eqb_true_informal)
+练习:2 星, advanced (eqb_true_informal)
给出一个详细的 eqb_true 的非形式化证明,量词要尽可能明确。@@ -875,7 +875,7 @@Tactics更多基本策略
-Theorem double_injective_take2_FAILED : ∀ n m,
+Theorem double_injective_take2_FAILED : ∀n m,
double n = double m →
n = m.
Proof.
@@ -906,7 +906,7 @@Tactics更多基本策略
-Theorem double_injective_take2 : ∀ n m,
+Theorem double_injective_take2 : ∀n m,
double n = double m →
n = m.
Proof.
@@ -985,7 +985,7 @@Tactics更多基本策略
-Theorem eqb_id_true : ∀ x y,
+Theorem eqb_id_true : ∀x y,
eqb_id x y = true → x = y.
Proof.
intros [m] [n]. simpl. intros H.
@@ -995,12 +995,12 @@Tactics更多基本策略
-练习:3 星, recommended (gen_dep_practice)
+练习:3 星, standard, recommended (gen_dep_practice)
通过对 l 进行归纳来证明它。-Theorem nth_error_after_last: ∀ (n : nat) (X : Type) (l : list X),
+Theorem nth_error_after_last: ∀(n : nat) (X : Type) (l : list X),
length l = n →
nth_error l n = None.
Proof.
@@ -1010,7 +1010,7 @@Tactics更多基本策略
☐-展开定义
+展开定义
@@ -1028,7 +1028,7 @@Tactics更多基本策略
-Lemma square_mult : ∀ n m, square (n * m) = square n * square m.
+Lemma square_mult : ∀n m, square (n * m) = square n * square m.
Proof.
intros n m.
simpl.
@@ -1080,7 +1080,7 @@Tactics更多基本策略
-Fact silly_fact_1 : ∀ m, foo m + 1 = foo (m + 1) + 1.
+Fact silly_fact_1 : ∀m, foo m + 1 = foo (m + 1) + 1.
Proof.
intros m.
simpl.
@@ -1105,7 +1105,7 @@Tactics更多基本策略
-Fact silly_fact_2_FAILED : ∀ m, bar m + 1 = bar (m + 1) + 1.
+Fact silly_fact_2_FAILED : ∀m, bar m + 1 = bar (m + 1) + 1.
Proof.
intros m.
simpl. (* 啥也没做! *)
@@ -1126,7 +1126,7 @@Tactics更多基本策略
-Fact silly_fact_2 : ∀ m, bar m + 1 = bar (m + 1) + 1.
+Fact silly_fact_2 : ∀m, bar m + 1 = bar (m + 1) + 1.
Proof.
intros m.
destruct m eqn:E.
@@ -1144,7 +1144,7 @@Tactics更多基本策略
-Fact silly_fact_2' : ∀ m, bar m + 1 = bar (m + 1) + 1.
+Fact silly_fact_2' : ∀m, bar m + 1 = bar (m + 1) + 1.
Proof.
intros m.
unfold bar.
@@ -1163,7 +1163,7 @@Tactics更多基本策略
-对复合表达式使用 destruct
+对复合表达式使用 destruct
@@ -1181,7 +1181,7 @@Tactics更多基本策略
if n =? 3 then false
else if n =? 5 then false
else false.
-Theorem sillyfun_false : ∀ (n : nat),
+Theorem sillyfun_false : ∀(n : nat),
sillyfun n = false.
Proof.
intros n. unfold sillyfun.
@@ -1205,7 +1205,7 @@Tactics更多基本策略
e 都会被替换成 c。-练习:3 星, optional (combine_split)
+练习:3 星, standard, optional (combine_split)
以下是 Poly 一章中出现过的 split 函数的实现:@@ -1226,7 +1226,7 @@Tactics更多基本策略
-Theorem combine_split : ∀ X Y (l : list (X * Y)) l1 l2,
+Theorem combine_split : ∀X Y (l : list (X * Y)) l1 l2,
split l = (l1, l2) →
combine l1 l2 = l.
Proof.
@@ -1264,7 +1264,7 @@Tactics更多基本策略
-Theorem sillyfun1_odd_FAILED : ∀ (n : nat),
+Theorem sillyfun1_odd_FAILED : ∀(n : nat),
sillyfun1 n = true →
oddb n = true.
Proof.
@@ -1293,7 +1293,7 @@Tactics更多基本策略
-Theorem sillyfun1_odd : ∀ (n : nat),
+Theorem sillyfun1_odd : ∀(n : nat),
sillyfun1 n = true →
oddb n = true.
Proof.
@@ -1314,12 +1314,12 @@Tactics更多基本策略
Theorem bool_fn_applied_thrice :
- ∀ (f : bool → bool) (b : bool),
+ ∀(f : bool → bool) (b : bool),
f (f (f b)) = f b.
Proof.
(* 请在此处解答 *) Admitted.
@@ -1328,7 +1328,7 @@Tactics更多基本策略
☐-diff --git a/lf-current/Tactics.v b/lf-current/Tactics.v index 7c19cbf8..809c4f4e 100644 --- a/lf-current/Tactics.v +++ b/lf-current/Tactics.v @@ -54,8 +54,9 @@ Proof. intros n m eq1 eq2. apply eq2. apply eq1. Qed. -(** **** 练习:2 星, optional (silly_ex) *) -(** 请完成以下证明,不要使用 [simpl]。 *) +(** **** 练习:2 星, standard, optional (silly_ex) + + 请完成以下证明,不要使用 [simpl]。 *) Theorem silly_ex : (forall n, evenb n = true -> oddb (S n) = true) -> @@ -81,8 +82,9 @@ Proof. simpl. (** (此处的 [simpl] 是可选的,因为 [apply] 会在需要时先进行化简。) *) apply H. Qed. -(** **** 练习:3 星 (apply_exercise1) *) -(** (_'提示'_:你可以配合之前定义的引理来使用 [apply],不仅限于当前上下文中的前提。 +(** **** 练习:3 星, standard (apply_exercise1) + + (_'提示'_:你可以配合之前定义的引理来使用 [apply],不仅限于当前上下文中的前提。 记住 [Search] 是你的朋友。) *) Theorem rev_exercise1 : forall (l l' : list nat), @@ -92,11 +94,13 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星, optional (apply_rewrite) *) -(** 简述 [apply] 与 [rewrite] 策略之区别。哪些情况下二者均可有效利用? *) +(** **** 练习:1 星, standard, optional (apply_rewrite) -(* 请在此处解答 *) -(** [] *) + 简述 [apply] 与 [rewrite] 策略之区别。哪些情况下二者均可有效利用? *) + +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * [apply with] 策略 *) @@ -143,7 +147,7 @@ Proof. 一般足够聪明来确定我们给出的实例。我们也可以写成: [apply trans_eq with [c;d]]。 *) -(** **** 练习:3 星, optional (apply_with_exercise) *) +(** **** 练习:3 星, standard, optional (apply_with_exercise) *) Example trans_eq_exercise : forall (n m o p : nat), m = (minustwo o) -> (n + p) = m -> @@ -236,7 +240,7 @@ Proof. injection H as Hnm. rewrite Hnm. reflexivity. Qed. -(** **** 练习:1 星 (injection_ex3) *) +(** **** 练习:1 星, standard (injection_ex3) *) Example injection_ex3 : forall (X : Type) (x y z : X) (l j : list X), x :: y :: l = z :: j -> y :: l = x :: j -> @@ -306,7 +310,7 @@ Proof. then the nonsensical conclusion would follow. We'll explore the principle of explosion of more detail in the next chapter. *) -(** **** 练习:1 星 (discriminate_ex3) *) +(** **** 练习:1 星, standard (discriminate_ex3) *) Example discriminate_ex3 : forall (X : Type) (x y z : X) (l j : list X), x :: y :: l = [] -> @@ -366,8 +370,9 @@ Proof. 它们使用的应该是正向推理。通常,Coq 习惯上倾向于使用反向推理, 但在某些情况下,正向推理更易于思考。 *) -(** **** 练习:3 星, recommended (plus_n_n_injective) *) -(** 请在此证明中练习使用“in”形式的变体。(提示:使用 [plus_n_Sm]。) *) +(** **** 练习:3 星, standard, recommended (plus_n_n_injective) + + 请在此证明中练习使用“in”形式的变体。(提示:使用 [plus_n_Sm]。) *) Theorem plus_n_n_injective : forall n m, n + n = m + m -> @@ -512,15 +517,16 @@ Proof. (** 以下练习需要同样的模式。 *) -(** **** 练习:2 星 (eqb_true) *) +(** **** 练习:2 星, standard (eqb_true) *) Theorem eqb_true : forall n m, n =? m = true -> n = m. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, advanced (eqb_true_informal) *) -(** 给出一个详细的 [eqb_true] 的非形式化证明,量词要尽可能明确。 *) +(** **** 练习:2 星, advanced (eqb_true_informal) + + 给出一个详细的 [eqb_true] 的非形式化证明,量词要尽可能明确。 *) (* 请在此处解答 *) @@ -617,8 +623,9 @@ Proof. rewrite H'. reflexivity. Qed. -(** **** 练习:3 星, recommended (gen_dep_practice) *) -(** 通过对 [l] 进行归纳来证明它。 *) +(** **** 练习:3 星, standard, recommended (gen_dep_practice) + + 通过对 [l] 进行归纳来证明它。 *) Theorem nth_error_after_last: forall (n : nat) (X : Type) (l : list X), length l = n -> @@ -762,8 +769,9 @@ Proof. [c],[destruct e] 都会生成一个子目标,其中(即目标和上下文中)所有的 [e] 都会被替换成 [c]。*) -(** **** 练习:3 星, optional (combine_split) *) -(** 以下是 [Poly] 一章中出现过的 [split] 函数的实现: *) +(** **** 练习:3 星, standard, optional (combine_split) + + 以下是 [Poly] 一章中出现过的 [split] 函数的实现: *) Fixpoint split {X Y : Type} (l : list (X*Y)) : (list X) * (list Y) := @@ -791,8 +799,9 @@ Proof. When [destruct]ing compound expressions, however, the information recorded by the [eqn:] can actually be critical: if we leave it out, then [destruct] can sometimes erase information we need to - complete a proof. *) -(** 例如,假设函数 [sillyfun1] 定义如下: *) + complete a proof. + + 例如,假设函数 [sillyfun1] 定义如下: *) Definition sillyfun1 (n : nat) : bool := if n =? 3 then true @@ -846,7 +855,7 @@ Proof. rewrite -> Heqe5. reflexivity. + (* e5 = false *) discriminate eq. Qed. -(** **** 练习:2 星 (destruct_eqn_practice) *) +(** **** 练习:2 星, standard (destruct_eqn_practice) *) Theorem bool_fn_applied_thrice : forall (f : bool -> bool) (b : bool), f (f (f b)) = f b. @@ -911,23 +920,25 @@ Proof. (* ################################################################# *) (** * 附加练习 *) -(** **** 练习:3 星 (eqb_sym) *) +(** **** 练习:3 星, standard (eqb_sym) *) Theorem eqb_sym : forall (n m : nat), (n =? m) = (m =? n). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, advanced, optional (eqb_sym_informal) *) -(** 根据前面你对该引理的形式化证明,给出与它对应的非形式化证明: +(** **** 练习:3 星, advanced, optional (eqb_sym_informal) + + 根据前面你对该引理的形式化证明,给出与它对应的非形式化证明: 定理:对于任何自然数 [n] [m],[n =? m = m =? n]. 证明: *) - (* 请在此处解答 *) -(** [] *) + (* 请在此处解答 -(** **** 练习:3 星, optional (eqb_trans) *) + [] *) + +(** **** 练习:3 星, standard, optional (eqb_trans) *) Theorem eqb_trans : forall n m p, n =? m = true -> m =? p = true -> @@ -936,8 +947,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, advanced (split_combine) *) -(** 在前面的练习中,我们证明了对于所有序对的列表,[combine] 是 [split] +(** **** 练习:3 星, advanced (split_combine) + + 在前面的练习中,我们证明了对于所有序对的列表,[combine] 是 [split] 的反函数。你如何形式化陈述 [split] 是 [combine] 的反函数?何时此性质成立? 请完成下面 [split_combine_statement] 的定义,其性质指出 [split] @@ -958,8 +970,9 @@ Proof. Definition manual_grade_for_split_combine : option (nat*string) := None. (** [] *) -(** **** 练习:3 星, advanced (filter_exercise) *) -(** 本练习有点难度。为你的归纳假设的形式花点心思。 *) +(** **** 练习:3 星, advanced (filter_exercise) + + 本练习有点难度。为你的归纳假设的形式花点心思。 *) Theorem filter_exercise : forall (X : Type) (test : X -> bool) (x : X) (l lf : list X), @@ -969,8 +982,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced, recommended (forall_exists_challenge) *) -(** 定义两个递归的 [Fixpoints],[forallb] 和 [existsb]。 +(** **** 练习:4 星, advanced, recommended (forall_exists_challenge) + + 定义两个递归的 [Fixpoints],[forallb] 和 [existsb]。 第一个检查列表中的每一个元素是否均满足给定的断言: forallb oddb [1;3;5;7;9] = true @@ -1036,3 +1050,4 @@ Proof. (* 请在此处解答 *) Admitted. +(* Sat Jan 26 15:14:45 UTC 2019 *) diff --git a/lf-current/TacticsTest.v b/lf-current/TacticsTest.v index 569d2907..cb7b2e5a 100644 --- a/lf-current/TacticsTest.v +++ b/lf-current/TacticsTest.v @@ -218,3 +218,5 @@ Print Assumptions filter_exercise. idtac "---------- existsb_existsb' ---------". Print Assumptions existsb_existsb'. Abort. + +(* Sat Jan 26 15:14:51 UTC 2019 *) diff --git a/lf-current/common/css/sf.css b/lf-current/common/css/sf.css index be9fcb10..12d4abc1 100644 --- a/lf-current/common/css/sf.css +++ b/lf-current/common/css/sf.css @@ -489,6 +489,9 @@ tr.infrulemiddle hr { color: rgb(0%,0%,0%); } +.nowrap { + white-space: nowrap; +} /* TOC */ diff --git a/lf-current/common/css/slides.css b/lf-current/common/css/slides.css index 0f1fc55a..b9d0327d 100644 --- a/lf-current/common/css/slides.css +++ b/lf-current/common/css/slides.css @@ -34,5 +34,7 @@ h1.libtitle { line-height: 34px; } - +body { + background: white; +} diff --git a/lf-current/coqindex.html b/lf-current/coqindex.html index 9e0faf77..3262ae1a 100644 --- a/lf-current/coqindex.html +++ b/lf-current/coqindex.html @@ -60,7 +60,7 @@复习
+复习
@@ -1469,15 +1469,15 @@Tactics更多基本策略
-Theorem eqb_sym : ∀ (n m : nat),
+Theorem eqb_sym : ∀(n m : nat),
(n =? m) = (m =? n).
Proof.
(* 请在此处解答 *) Admitted.
@@ -1487,7 +1487,7 @@Tactics更多基本策略
-练习:3 星, advanced, optional (eqb_sym_informal)
+练习:3 星, advanced, optional (eqb_sym_informal)
根据前面你对该引理的形式化证明,给出与它对应的非形式化证明:@@ -1506,11 +1506,11 @@Tactics更多基本策略
-练习:3 星, optional (eqb_trans)
+练习:3 星, standard, optional (eqb_trans)
-Theorem eqb_trans : ∀ n m p,
+Theorem eqb_trans : ∀n m p,
n =? m = true →
m =? p = true →
n =? p = true.
@@ -1522,7 +1522,7 @@Tactics更多基本策略
-练习:3 星, advanced (split_combine)
+练习:3 星, advanced (split_combine)
在前面的练习中,我们证明了对于所有序对的列表,combine 是 split 的反函数。你如何形式化陈述 split 是 combine 的反函数?何时此性质成立? @@ -1550,12 +1550,12 @@Tactics更多基本策略
-练习:3 星, advanced (filter_exercise)
+练习:3 星, advanced (filter_exercise)
本练习有点难度。为你的归纳假设的形式花点心思。-Theorem filter_exercise : ∀ (X : Type) (test : X → bool)☐ +
+Theorem filter_exercise : ∀(X : Type) (test : X → bool)
(x : X) (l lf : list X),
filter test l = x :: lf →
test x = true.
@@ -1567,7 +1567,7 @@Tactics更多基本策略
-练习:4 星, advanced, recommended (forall_exists_challenge)
+练习:4 星, advanced, recommended (forall_exists_challenge)
定义两个递归的 Fixpoints,forallb 和 existsb。 第一个检查列表中的每一个元素是否均满足给定的断言: @@ -1629,12 +1629,16 @@Tactics更多基本策略
Proof. (* 请在此处解答 *) Admitted.
Definition existsb' {X : Type} (test : X → bool) (l : list X) : bool
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem existsb_existsb' : ∀ (X : Type) (test : X → bool) (l : list X),
+Theorem existsb_existsb' : ∀(X : Type) (test : X → bool) (l : list X),
existsb test l = existsb' test l.
Proof. (* 请在此处解答 *) Admitted.
+ +(* Sat Jan 26 15:14:45 UTC 2019 *)
+Z : _ -(1231 entries) +(1238 entries) Notation Index @@ -92,7 +92,7 @@Z : _ -(82 entries) +(68 entries) Module Index @@ -123,7 +123,7 @@Y Z _ -(24 entries) +(25 entries) Library Index @@ -185,7 +185,7 @@Y Z _ -(350 entries) +(359 entries) Constructor Index @@ -216,7 +216,7 @@Y Z _ -(207 entries) +(211 entries) - Axiom Index @@ -278,38 +278,7 @@Y Z _ -(74 entries) -- Abbreviation Index -A -B -C -D -E -F -G -H -I -J -K -L -M -N -O -P -Q -R -S -T -U -V -W -X -Y -Z -_ -(4 entries) +(76 entries) Definition Index @@ -340,7 +309,7 @@Y Z _ -(470 entries) +(479 entries)
@@ -387,6 +356,12 @@Global Index
AExp.aevalR_first_try.E_AMult [constructor, in LF.Imp]
AExp.aevalR_first_try.E_ANum [constructor, in LF.Imp]
AExp.aevalR_first_try.E_APlus [constructor, in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead [module, in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.aevalR [inductive, in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_AMinus [constructor, in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_AMult [constructor, in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_ANum [constructor, in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_APlus [constructor, in LF.Imp]
AExp.aevalR_first_try.:type_scope:x_'\\'_x [notation, in LF.Imp]
AExp.aeval_iff_aevalR [lemma, in LF.Imp]
AExp.aeval_iff_aevalR' [lemma, in LF.Imp]
@@ -413,6 +388,7 @@Global Index
AExp.foo' [lemma, in LF.Imp]
AExp.In10 [lemma, in LF.Imp]
AExp.In10' [lemma, in LF.Imp]
+AExp.manual_grade_for_beval_rules [definition, in LF.Imp]
AExp.optimize_0plus [definition, in LF.Imp]
AExp.optimize_0plus_b [definition, in LF.Imp]
AExp.optimize_0plus_b_sound [lemma, in LF.Imp]
@@ -499,8 +475,8 @@Global Index
black [constructor, in LF.Basics]
BLe [constructor, in LF.Imp]
bleaf [constructor, in LF.IndPrinciples]
-blue [constructor, in LF.Basics]
blue [constructor, in LF.IndPrinciples]
+blue [constructor, in LF.Basics]
BNot [constructor, in LF.Imp]
bool [inductive, in LF.Basics]
boollist [inductive, in LF.Poly]
@@ -526,12 +502,12 @@Global Index
BreakImp.while_break_true [lemma, in LF.Imp]
BreakImp.while_continue [lemma, in LF.Imp]
BreakImp.while_stops_on_break [lemma, in LF.Imp]
-BreakImp.::x_'/'_x_'\\'_x_'/'_x [notation, in LF.Imp]
BreakImp.::x_'::='_x [notation, in LF.Imp]
BreakImp.::x_';;'_x [notation, in LF.Imp]
+BreakImp.::x_'=['_x_']=>'_x_'/'_x [notation, in LF.Imp]
BreakImp.::'BREAK' [notation, in LF.Imp]
-BreakImp.::'IFB'_x_'THEN'_x_'ELSE'_x_'FI' [notation, in LF.Imp]
BreakImp.::'SKIP' [notation, in LF.Imp]
+BreakImp.::'TEST'_x_'THEN'_x_'ELSE'_x_'FI' [notation, in LF.Imp]
BreakImp.::'WHILE'_x_'DO'_x_'END' [notation, in LF.Imp]
BTrue [constructor, in LF.Imp]
byntree [inductive, in LF.IndPrinciples]
@@ -543,8 +519,8 @@Global Index
ceval [inductive, in LF.Imp]
ceval'_example1 [definition, in LF.Auto]
ceval_and_ceval_step_coincide [lemma, in LF.ImpCEvalFun]
-ceval_deterministic [lemma, in LF.Auto]
ceval_deterministic [lemma, in LF.Imp]
+ceval_deterministic [lemma, in LF.Auto]
ceval_deterministic' [lemma, in LF.Auto]
ceval_deterministic' [lemma, in LF.ImpCEvalFun]
ceval_deterministic'' [lemma, in LF.Auto]
@@ -618,13 +594,14 @@Global Index
E
eauto_example [definition, in LF.Auto]
eg1 [definition, in LF.ImpParser]
+eg2 [definition, in LF.ImpParser]
empty [definition, in LF.Maps]
EmptySet [constructor, in LF.IndProp]
EmptyStr [constructor, in LF.IndProp]
empty_is_empty [lemma, in LF.IndProp]
empty_matches_eps [lemma, in LF.IndProp]
empty_nomatch_ne [lemma, in LF.IndProp]
-empty_state [definition, in LF.Extraction]
+empty_st [definition, in LF.Imp]
eqb [definition, in LF.Basics]
eqbP [lemma, in LF.IndProp]
eqbP_practice [lemma, in LF.IndProp]
@@ -646,24 +623,26 @@Global Index
eqb_true [lemma, in LF.Tactics]
eqb_0_l [lemma, in LF.Tactics]
equivalence [definition, in LF.Rel]
-ev [inductive, in LF.IndProp]
+even [inductive, in LF.IndProp]
evenb [definition, in LF.Basics]
evenb_double [lemma, in LF.Logic]
evenb_double_conv [lemma, in LF.Logic]
evenb_S [lemma, in LF.Induction]
+even' [inductive, in LF.IndProp]
+even'_ev [lemma, in LF.IndProp]
+even'_sum [constructor, in LF.IndProp]
+even'_0 [constructor, in LF.IndProp]
+even'_2 [constructor, in LF.IndProp]
even5_nonsense [lemma, in LF.IndProp]
even_bool_prop [lemma, in LF.Logic]
even_1000 [definition, in LF.Logic]
even_1000' [definition, in LF.Logic]
even_1000'' [definition, in LF.Logic]
+even_42_bool [definition, in LF.Logic]
+even_42_prop [definition, in LF.Logic]
evSS_ev [lemma, in LF.IndProp]
evSS_ev [lemma, in LF.IndProp]
evSS_ev' [lemma, in LF.IndProp]
-ev' [inductive, in LF.IndProp]
-ev'_ev [lemma, in LF.IndProp]
-ev'_sum [constructor, in LF.IndProp]
-ev'_0 [constructor, in LF.IndProp]
-ev'_2 [constructor, in LF.IndProp]
ev_double [lemma, in LF.IndProp]
ev_even [lemma, in LF.IndProp]
ev_even_firsttry [lemma, in LF.IndProp]
@@ -693,6 +672,10 @@Global Index
ev_8' [definition, in LF.ProofObjects]
examplemap [definition, in LF.Maps]
examplemap' [definition, in LF.Maps]
+examplepmap [definition, in LF.Maps]
+example_aexp [definition, in LF.Imp]
+example_bexp [definition, in LF.Imp]
+example_empty [definition, in LF.Maps]
excluded_middle [definition, in LF.Logic]
excluded_middle_irrefutable [lemma, in LF.Logic]
Exercises [module, in LF.Poly]
@@ -777,13 +760,13 @@Global Index
function_equality_ex2 [definition, in LF.Logic]
f_equal [lemma, in LF.Tactics]
G
-green [constructor, in LF.IndPrinciples]
green [constructor, in LF.Basics]
+green [constructor, in LF.IndPrinciples]
H
hd_error [definition, in LF.Poly]
I
-Id [constructor, in LF.Lists]
id [inductive, in LF.Lists]
+Id [constructor, in LF.Lists]
identity_fn_applied_twice [lemma, in LF.Basics]
iff_refl [lemma, in LF.Logic]
iff_reflect [lemma, in LF.IndProp]
@@ -809,6 +792,12 @@Global Index
In_example_2 [definition, in LF.Logic]
In_map [lemma, in LF.Logic]
In_map_iff [lemma, in LF.Logic]
+in_not_nil [lemma, in LF.Logic]
+in_not_nil_42 [lemma, in LF.Logic]
+in_not_nil_42_take2 [lemma, in LF.Logic]
+in_not_nil_42_take3 [lemma, in LF.Logic]
+in_not_nil_42_take4 [lemma, in LF.Logic]
+in_not_nil_42_take5 [lemma, in LF.Logic]
in_re_match [lemma, in LF.IndProp]
in_split [lemma, in LF.IndProp]
isAlpha [definition, in LF.ImpParser]
@@ -887,7 +876,6 @@Global Index
manual_grade_for_pal_pal_app_rev_pal_rev [definition, in LF.IndProp]
manual_grade_for_plus_comm_informal [definition, in LF.Induction]
manual_grade_for_split_combine [definition, in LF.Tactics]
-manual_grade_for_subsequence [definition, in LF.IndProp]
manual_grade_for_XtimesYinZ_spec [definition, in LF.Imp]
many [definition, in LF.ImpParser]
many_helper [definition, in LF.ImpParser]
@@ -945,7 +933,7 @@Global Index
MyEquality.:type_scope:x_'=='_x [notation, in LF.ProofObjects]
MyIff [module, in LF.Logic]
MyIff.iff [definition, in LF.Logic]
-MyIff.:type_scope:x_'<->'_x [notation, in LF.Logic]
+->'_x">MyIff.:type_scope:x_'<->'_x [notation, in LF.Logic]
mynil [definition, in LF.Poly]
mynil [definition, in LF.Poly]
mynil' [definition, in LF.Poly]
@@ -954,8 +942,8 @@Global Index
MyNot.:type_scope:'~'_x [notation, in LF.Logic]
N
nandb [definition, in LF.Basics]
-NatList [module, in LF.Lists]
natlist [inductive, in LF.IndPrinciples]
+NatList [module, in LF.Lists]
NatList.add [definition, in LF.Lists]
NatList.alternate [definition, in LF.Lists]
NatList.app [definition, in LF.Lists]
@@ -1106,6 +1094,8 @@Global Index
nostutter [inductive, in LF.IndProp]
not_both_true_and_false [lemma, in LF.Logic]
not_equiv_false [lemma, in LF.IndProp]
+not_even_1001 [definition, in LF.Logic]
+not_even_1001' [definition, in LF.Logic]
not_exists_dist [lemma, in LF.Logic]
not_False [lemma, in LF.Logic]
not_implies_our_not [lemma, in LF.Logic]
@@ -1192,11 +1182,11 @@Global Index
plus_comm3 [lemma, in LF.Logic]
plus_comm3_take2 [lemma, in LF.Logic]
plus_comm3_take3 [lemma, in LF.Logic]
+plus_eqb_example [lemma, in LF.Logic]
plus_fact [definition, in LF.Logic]
plus_fact_is_true [lemma, in LF.Logic]
plus_id_example [lemma, in LF.Basics]
plus_id_exercise [lemma, in LF.Basics]
-plus_leb_compat_l [abbreviation, in LF.Induction]
plus_lt [lemma, in LF.IndProp]
plus_n_n_injective [lemma, in LF.Tactics]
plus_n_O [lemma, in LF.Induction]
@@ -1258,8 +1248,8 @@Global Index
P_m0r' [definition, in LF.IndPrinciples]
R
R [module, in LF.IndProp]
-red [constructor, in LF.IndPrinciples]
red [constructor, in LF.Basics]
+red [constructor, in LF.IndPrinciples]
reflect [inductive, in LF.IndProp]
ReflectF [constructor, in LF.IndProp]
ReflectT [constructor, in LF.IndProp]
@@ -1302,12 +1292,12 @@Global Index
Repeat.E_Skip [constructor, in LF.Auto]
Repeat.E_WhileFalse [constructor, in LF.Auto]
Repeat.E_WhileTrue [constructor, in LF.Auto]
-Repeat.::x_'/'_x_'\\'_x [notation, in LF.Auto]
Repeat.::x_'::='_x [notation, in LF.Auto]
Repeat.::x_';'_x [notation, in LF.Auto]
-Repeat.::'IFB'_x_'THEN'_x_'ELSE'_x_'FI' [notation, in LF.Auto]
+Repeat.::x_'=['_x_']=>'_x [notation, in LF.Auto]
Repeat.::'REPEAT'_x_'UNTIL'_x_'END' [notation, in LF.Auto]
Repeat.::'SKIP' [notation, in LF.Auto]
+Repeat.::'TEST'_x_'THEN'_x_'ELSE'_x_'FI' [notation, in LF.Auto]
Repeat.::'WHILE'_x_'DO'_x_'END' [notation, in LF.Auto]
restricted_excluded_middle [lemma, in LF.Logic]
restricted_excluded_middle_eq [lemma, in LF.Logic]
@@ -1383,6 +1373,10 @@Global Index
string_of_list [definition, in LF.ImpParser]
st12 [definition, in LF.Auto]
st21 [definition, in LF.Auto]
+subseq [inductive, in LF.IndProp]
+subseq_app [lemma, in LF.IndProp]
+subseq_refl [lemma, in LF.IndProp]
+subseq_trans [lemma, in LF.IndProp]
subtract_slowly [definition, in LF.Imp]
subtract_slowly_body [definition, in LF.Imp]
subtract_3_from_5_slowly [definition, in LF.Imp]
@@ -1399,7 +1393,6 @@Global Index
S_injective [lemma, in LF.Tactics]
S_injective' [lemma, in LF.Tactics]
S_nbeq_0 [lemma, in LF.Induction]
-S_neqb_0 [abbreviation, in LF.Induction]
T
Tactics [library]
testParsing [definition, in LF.ImpParser]
@@ -1534,71 +1527,54 @@Global Index
yes [constructor, in LF.IndPrinciples]
yesno [inductive, in LF.IndPrinciples]
Z
-Z [definition, in LF.Imp]
Z [constructor, in LF.Basics]
+Z [definition, in LF.Imp]
zero_nbeq_plus_1 [lemma, in LF.Basics]
zero_nbeq_S [lemma, in LF.Induction]
-zero_neqb_plus_1 [abbreviation, in LF.Basics]
-zero_neqb_S [abbreviation, in LF.Induction]
zero_not_one [lemma, in LF.Logic]
-zero_not_one' [lemma, in LF.Logic]
zero_or_succ [lemma, in LF.Logic]
:
-:aexp_scope:x_'*'_x [notation, in LF.Imp]
-:aexp_scope:x_'+'_x [notation, in LF.Imp]
-:aexp_scope:x_'-'_x [notation, in LF.Imp]
-:bexp_scope:x_'&&'_x [notation, in LF.Imp]
-:bexp_scope:x_'<='_x [notation, in LF.Imp]
-:bexp_scope:x_'='_x [notation, in LF.Imp]
-:bexp_scope:'!'_x [notation, in LF.Imp]
-:com_scope:x_'::='_x [notation, in LF.Imp]
-:com_scope:x_';;'_x [notation, in LF.Imp]
-:com_scope:'IFB'_x_'THEN'_x_'ELSE'_x_'FI' [notation, in LF.Imp]
-:com_scope:'SKIP' [notation, in LF.Imp]
-:com_scope:'WHILE'_x_'DO'_x_'END' [notation, in LF.Imp]
+:imp_scope:x_'&&'_x [notation, in LF.Imp]
+:imp_scope:x_'*'_x [notation, in LF.Imp]
+:imp_scope:x_'+'_x [notation, in LF.Imp]
+:imp_scope:x_'-'_x [notation, in LF.Imp]
+:imp_scope:x_'::='_x [notation, in LF.Imp]
+:imp_scope:x_';;'_x [notation, in LF.Imp]
+:imp_scope:x_'<='_x [notation, in LF.Imp]
+:imp_scope:x_'='_x [notation, in LF.Imp]
+:imp_scope:'SKIP' [notation, in LF.Imp]
+:imp_scope:'TEST'_x_'THEN'_x_'ELSE'_x_'FI' [notation, in LF.Imp]
+:imp_scope:'WHILE'_x_'DO'_x_'END' [notation, in LF.Imp]
+:imp_scope:'~'_x [notation, in LF.Imp]
:nat_scope:x_'*'_x [notation, in LF.Basics]
:nat_scope:x_'*'_x [notation, in LF.Basics]
:nat_scope:x_'+'_x [notation, in LF.Basics]
:nat_scope:x_'+'_x [notation, in LF.Basics]
:nat_scope:x_'-'_x [notation, in LF.Basics]
-:nat_scope:x_'<=?'_x [notation, in LF.Basics]
:nat_scope:x_'<=?'_x [notation, in LF.ImpParser]
+:nat_scope:x_'<=?'_x [notation, in LF.Basics]
:nat_scope:x_''_x [notation, in LF.Basics]
:nat_scope:x_'=?'_x [notation, in LF.Basics]
:type_scope:x_'*'_x [notation, in LF.Poly]
+->'_x">::x_'!->'_x [notation, in LF.Imp]
+->'_x_';'_x">::x_'!->'_x_';'_x [notation, in LF.Maps]
::x_'&&'_x [notation, in LF.Basics]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Maps]
--->'_x_'}'">::x_'&'_'{'_x_'-->'_x_'}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [notation, in LF.Maps]
--->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_'}}' [notation, in LF.Maps]
--->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_'}}' [notation, in LF.Maps]
::x_'++'_x [notation, in LF.Poly]
-::x_'/'_x_'\\'_x [notation, in LF.Imp]
::x_'::'_x [notation, in LF.Poly]
::x_'<'_x [notation, in LF.IndProp]
::x_'<='_x [notation, in LF.IndPrinciples]
+::x_'=['_x_']=>'_x [notation, in LF.Imp]
::x_'=~'_x [notation, in LF.IndProp]
+⊢>'_x">::x_'⊢>'_x [notation, in LF.Maps]
+⊢>'_x_';'_x">::x_'⊢>'_x_';'_x [notation, in LF.Maps]
::x_'||'_x [notation, in LF.Basics]
-::'DO'_'('_x_','_x_')'_'<--'_x_';'_x_'OR'_x [notation, in LF.ImpParser]
-::'DO'_'('_x_','_x_')'_'<=='_x_';'_x [notation, in LF.ImpParser]
::'LETOPT'_x_'<=='_x_'IN'_x [notation, in LF.ImpCEvalFun]
+::'TRY'_''''_x_'<-'_x_';;'_x_'OR'_x [notation, in LF.ImpParser]
+::''''_x_'<-'_x_';;'_x [notation, in LF.ImpParser]
+->'_x">::'''_'''_'!->'_x [notation, in LF.Maps]
::'('_x_','_x_')' [notation, in LF.Poly]
::'['_x_';'_'..'_';'_x_']' [notation, in LF.Poly]
::'['_']' [notation, in LF.Poly]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Imp]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Imp]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Imp]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Imp]
--->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_'}' [notation, in LF.Imp]
--->'_x_'}'">::'{'_x_'-->'_x_'}' [notation, in LF.Imp]
--->'_x_'}'">::'{'_'-->'_x_'}' [notation, in LF.Maps]
Notation Index
A
@@ -1607,16 +1583,16 @@Notation Index
AExp.aevalR_first_try.:type_scope:x_'\\'_x [in LF.Imp]
AExp.:type_scope:x_'\\'_x [in LF.Imp]
B
-BreakImp.::x_'/'_x_'\\'_x_'/'_x [in LF.Imp]
BreakImp.::x_'::='_x [in LF.Imp]
BreakImp.::x_';;'_x [in LF.Imp]
+BreakImp.::x_'=['_x_']=>'_x_'/'_x [in LF.Imp]
BreakImp.::'BREAK' [in LF.Imp]
-BreakImp.::'IFB'_x_'THEN'_x_'ELSE'_x_'FI' [in LF.Imp]
BreakImp.::'SKIP' [in LF.Imp]
+BreakImp.::'TEST'_x_'THEN'_x_'ELSE'_x_'FI' [in LF.Imp]
BreakImp.::'WHILE'_x_'DO'_x_'END' [in LF.Imp]
M
MyEquality.:type_scope:x_'=='_x [in LF.ProofObjects]
-MyIff.:type_scope:x_'<->'_x [in LF.Logic]
+->'_x">MyIff.:type_scope:x_'<->'_x [in LF.Logic]
MyNot.:type_scope:'~'_x [in LF.Logic]
N
NatList.::x_'++'_x [in LF.Lists]
@@ -1627,69 +1603,55 @@Notation Index
P
Playground.::x_'<='_x [in LF.IndProp]
R
-Repeat.::x_'/'_x_'\\'_x [in LF.Auto]
Repeat.::x_'::='_x [in LF.Auto]
Repeat.::x_';'_x [in LF.Auto]
-Repeat.::'IFB'_x_'THEN'_x_'ELSE'_x_'FI' [in LF.Auto]
+Repeat.::x_'=['_x_']=>'_x [in LF.Auto]
Repeat.::'REPEAT'_x_'UNTIL'_x_'END' [in LF.Auto]
Repeat.::'SKIP' [in LF.Auto]
+Repeat.::'TEST'_x_'THEN'_x_'ELSE'_x_'FI' [in LF.Auto]
Repeat.::'WHILE'_x_'DO'_x_'END' [in LF.Auto]
:
-:aexp_scope:x_'*'_x [in LF.Imp]
-:aexp_scope:x_'+'_x [in LF.Imp]
-:aexp_scope:x_'-'_x [in LF.Imp]
-:bexp_scope:x_'&&'_x [in LF.Imp]
-:bexp_scope:x_'<='_x [in LF.Imp]
-:bexp_scope:x_'='_x [in LF.Imp]
-:bexp_scope:'!'_x [in LF.Imp]
-:com_scope:x_'::='_x [in LF.Imp]
-:com_scope:x_';;'_x [in LF.Imp]
-:com_scope:'IFB'_x_'THEN'_x_'ELSE'_x_'FI' [in LF.Imp]
-:com_scope:'SKIP' [in LF.Imp]
-:com_scope:'WHILE'_x_'DO'_x_'END' [in LF.Imp]
+:imp_scope:x_'&&'_x [in LF.Imp]
+:imp_scope:x_'*'_x [in LF.Imp]
+:imp_scope:x_'+'_x [in LF.Imp]
+:imp_scope:x_'-'_x [in LF.Imp]
+:imp_scope:x_'::='_x [in LF.Imp]
+:imp_scope:x_';;'_x [in LF.Imp]
+:imp_scope:x_'<='_x [in LF.Imp]
+:imp_scope:x_'='_x [in LF.Imp]
+:imp_scope:'SKIP' [in LF.Imp]
+:imp_scope:'TEST'_x_'THEN'_x_'ELSE'_x_'FI' [in LF.Imp]
+:imp_scope:'WHILE'_x_'DO'_x_'END' [in LF.Imp]
+:imp_scope:'~'_x [in LF.Imp]
:nat_scope:x_'*'_x [in LF.Basics]
:nat_scope:x_'*'_x [in LF.Basics]
:nat_scope:x_'+'_x [in LF.Basics]
:nat_scope:x_'+'_x [in LF.Basics]
:nat_scope:x_'-'_x [in LF.Basics]
-:nat_scope:x_'<=?'_x [in LF.Basics]
:nat_scope:x_'<=?'_x [in LF.ImpParser]
+:nat_scope:x_'<=?'_x [in LF.Basics]
:nat_scope:x_''_x [in LF.Basics]
:nat_scope:x_'=?'_x [in LF.Basics]
:type_scope:x_'*'_x [in LF.Poly]
+->'_x">::x_'!->'_x [in LF.Imp]
+->'_x_';'_x">::x_'!->'_x_';'_x [in LF.Maps]
::x_'&&'_x [in LF.Basics]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_'}'">::x_'&'_'{'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Maps]
--->'_x_'}'">::x_'&'_'{'_x_'-->'_x_'}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}}' [in LF.Maps]
--->'_x_';'_x_'-->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_';'_x_'-->'_x_'}}' [in LF.Maps]
--->'_x_'}}'">::x_'&'_'{{'_x_'-->'_x_'}}' [in LF.Maps]
::x_'++'_x [in LF.Poly]
-::x_'/'_x_'\\'_x [in LF.Imp]
::x_'::'_x [in LF.Poly]
::x_'<'_x [in LF.IndProp]
::x_'<='_x [in LF.IndPrinciples]
+::x_'=['_x_']=>'_x [in LF.Imp]
::x_'=~'_x [in LF.IndProp]
+⊢>'_x">::x_'⊢>'_x [in LF.Maps]
+⊢>'_x_';'_x">::x_'⊢>'_x_';'_x [in LF.Maps]
::x_'||'_x [in LF.Basics]
-::'DO'_'('_x_','_x_')'_'<--'_x_';'_x_'OR'_x [in LF.ImpParser]
-::'DO'_'('_x_','_x_')'_'<=='_x_';'_x [in LF.ImpParser]
::'LETOPT'_x_'<=='_x_'IN'_x [in LF.ImpCEvalFun]
+::'TRY'_''''_x_'<-'_x_';;'_x_'OR'_x [in LF.ImpParser]
+::''''_x_'<-'_x_';;'_x [in LF.ImpParser]
+->'_x">::'''_'''_'!->'_x [in LF.Maps]
::'('_x_','_x_')' [in LF.Poly]
::'['_x_';'_'..'_';'_x_']' [in LF.Poly]
::'['_']' [in LF.Poly]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Imp]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Imp]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Imp]
--->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Imp]
--->'_x_';'_x_'-->'_x_'}'">::'{'_x_'-->'_x_';'_x_'-->'_x_'}' [in LF.Imp]
--->'_x_'}'">::'{'_x_'-->'_x_'}' [in LF.Imp]
--->'_x_'}'">::'{'_'-->'_x_'}' [in LF.Maps]
Module Index
A
@@ -1697,6 +1659,7 @@Module Index
aevalR_extended [in LF.Imp]
AExp [in LF.Imp]
AExp.aevalR_first_try [in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead [in LF.Imp]
B
BreakImp [in LF.Imp]
E
@@ -1803,8 +1766,8 @@Lemma Index
BreakImp.while_stops_on_break [in LF.Imp]
C
ceval_and_ceval_step_coincide [in LF.ImpCEvalFun]
-ceval_deterministic [in LF.Auto]
ceval_deterministic [in LF.Imp]
+ceval_deterministic [in LF.Auto]
ceval_deterministic' [in LF.Auto]
ceval_deterministic' [in LF.ImpCEvalFun]
ceval_deterministic'' [in LF.Auto]
@@ -1858,12 +1821,12 @@Lemma Index
evenb_double [in LF.Logic]
evenb_double_conv [in LF.Logic]
evenb_S [in LF.Induction]
+even'_ev [in LF.IndProp]
even5_nonsense [in LF.IndProp]
even_bool_prop [in LF.Logic]
evSS_ev [in LF.IndProp]
evSS_ev [in LF.IndProp]
evSS_ev' [in LF.IndProp]
-ev'_ev [in LF.IndProp]
ev_double [in LF.IndProp]
ev_even [in LF.IndProp]
ev_even_firsttry [in LF.IndProp]
@@ -1910,6 +1873,12 @@Lemma Index
In_app_iff [in LF.Logic]
In_map [in LF.Logic]
In_map_iff [in LF.Logic]
+in_not_nil [in LF.Logic]
+in_not_nil_42 [in LF.Logic]
+in_not_nil_42_take2 [in LF.Logic]
+in_not_nil_42_take3 [in LF.Logic]
+in_not_nil_42_take4 [in LF.Logic]
+in_not_nil_42_take5 [in LF.Logic]
in_re_match [in LF.IndProp]
in_split [in LF.IndProp]
L
@@ -2028,6 +1997,7 @@Lemma Index
plus_comm3 [in LF.Logic]
plus_comm3_take2 [in LF.Logic]
plus_comm3_take3 [in LF.Logic]
+plus_eqb_example [in LF.Logic]
plus_fact_is_true [in LF.Logic]
plus_id_example [in LF.Basics]
plus_id_exercise [in LF.Basics]
@@ -2094,6 +2064,9 @@Lemma Index
star_app [in LF.IndProp]
star_app [in LF.IndProp]
star_ne [in LF.IndProp]
+subseq_app [in LF.IndProp]
+subseq_refl [in LF.IndProp]
+subseq_trans [in LF.IndProp]
succ_inj [in LF.Logic]
s_compile_correct [in LF.Imp]
S_inj [in LF.Tactics]
@@ -2121,7 +2094,6 @@Lemma Index
zero_nbeq_plus_1 [in LF.Basics]
zero_nbeq_S [in LF.Induction]
zero_not_one [in LF.Logic]
-zero_not_one' [in LF.Logic]
zero_or_succ [in LF.Logic]
Constructor Index
@@ -2151,6 +2123,10 @@Constructor Index
AExp.aevalR_first_try.E_AMult [in LF.Imp]
AExp.aevalR_first_try.E_ANum [in LF.Imp]
AExp.aevalR_first_try.E_APlus [in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_AMinus [in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_AMult [in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_ANum [in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.E_APlus [in LF.Imp]
AExp.AMinus [in LF.Imp]
AExp.AMult [in LF.Imp]
AExp.ANum [in LF.Imp]
@@ -2184,8 +2160,8 @@Constructor Index
black [in LF.Basics]
BLe [in LF.Imp]
bleaf [in LF.IndPrinciples]
-blue [in LF.Basics]
blue [in LF.IndPrinciples]
+blue [in LF.Basics]
BNot [in LF.Imp]
bool_cons [in LF.Poly]
bool_nil [in LF.Poly]
@@ -2217,9 +2193,9 @@Constructor Index
E
EmptySet [in LF.IndProp]
EmptyStr [in LF.IndProp]
-ev'_sum [in LF.IndProp]
-ev'_0 [in LF.IndProp]
-ev'_2 [in LF.IndProp]
+even'_sum [in LF.IndProp]
+even'_0 [in LF.IndProp]
+even'_2 [in LF.IndProp]
ev_SS [in LF.IndProp]
ev_0 [in LF.IndProp]
E_Ass [in LF.Imp]
@@ -2233,8 +2209,8 @@Constructor Index
false [in LF.Basics]
friday [in LF.Basics]
G
-green [in LF.IndPrinciples]
green [in LF.Basics]
+green [in LF.IndPrinciples]
I
Id [in LF.Lists]
L
@@ -2296,8 +2272,8 @@Constructor Index
Props.Or.or_introl [in LF.ProofObjects]
Props.Or.or_intror [in LF.ProofObjects]
R
-red [in LF.IndPrinciples]
red [in LF.Basics]
+red [in LF.IndPrinciples]
ReflectF [in LF.IndProp]
ReflectT [in LF.IndProp]
Repeat.CAsgn [in LF.Auto]
@@ -2366,6 +2342,7 @@Inductive Index
aexp [in LF.Imp]
AExp.aevalR [in LF.Imp]
AExp.aevalR_first_try.aevalR [in LF.Imp]
+AExp.aevalR_first_try.TooHardToRead.aevalR [in LF.Imp]
AExp.aexp [in LF.Imp]
AExp.bevalR [in LF.Imp]
AExp.bexp [in LF.Imp]
@@ -2390,8 +2367,8 @@Inductive Index
D
day [in LF.Basics]
E
-ev [in LF.IndProp]
-ev' [in LF.IndProp]
+even [in LF.IndProp]
+even' [in LF.IndProp]
exp_match [in LF.IndProp]
ExSet [in LF.IndPrinciples]
F
@@ -2443,6 +2420,7 @@Inductive Index
S
sinstr [in LF.Imp]
square_of [in LF.IndProp]
+subseq [in LF.IndProp]
T
tree [in LF.IndPrinciples]
W
@@ -2450,21 +2428,13 @@Inductive Index
Y
yesno [in LF.IndPrinciples]
-Abbreviation Index
-P
-plus_leb_compat_l [in LF.Induction]
-S
-S_neqb_0 [in LF.Induction]
-Z
-zero_neqb_plus_1 [in LF.Basics]
-zero_neqb_S [in LF.Induction]
-
Definition Index
A
add1 [in LF.ProofObjects]
aeval [in LF.Imp]
AExp.aeval [in LF.Imp]
AExp.beval [in LF.Imp]
+AExp.manual_grade_for_beval_rules [in LF.Imp]
AExp.optimize_0plus [in LF.Imp]
AExp.optimize_0plus_b [in LF.Imp]
AExp.silly_presburger_example [in LF.Imp]
@@ -2527,8 +2497,9 @@Definition Index
E
eauto_example [in LF.Auto]
eg1 [in LF.ImpParser]
+eg2 [in LF.ImpParser]
empty [in LF.Maps]
-empty_state [in LF.Extraction]
+empty_st [in LF.Imp]
eqb [in LF.Basics]
eqb_id [in LF.Lists]
eqb_list [in LF.Logic]
@@ -2538,6 +2509,8 @@Definition Index
even_1000 [in LF.Logic]
even_1000' [in LF.Logic]
even_1000'' [in LF.Logic]
+even_42_bool [in LF.Logic]
+even_42_prop [in LF.Logic]
ev_plus2 [in LF.ProofObjects]
ev_plus2' [in LF.ProofObjects]
ev_plus2'' [in LF.ProofObjects]
@@ -2547,6 +2520,10 @@Definition Index
ev_8' [in LF.ProofObjects]
examplemap [in LF.Maps]
examplemap' [in LF.Maps]
+examplepmap [in LF.Maps]
+example_aexp [in LF.Imp]
+example_bexp [in LF.Imp]
+example_empty [in LF.Maps]
excluded_middle [in LF.Logic]
Exercises.Church.cnat [in LF.Poly]
Exercises.Church.exp [in LF.Poly]
@@ -2655,7 +2632,6 @@Definition Index
manual_grade_for_pal_pal_app_rev_pal_rev [in LF.IndProp]
manual_grade_for_plus_comm_informal [in LF.Induction]
manual_grade_for_split_combine [in LF.Tactics]
-manual_grade_for_subsequence [in LF.IndProp]
manual_grade_for_XtimesYinZ_spec [in LF.Imp]
many [in LF.ImpParser]
many_helper [in LF.ImpParser]
@@ -2759,6 +2735,8 @@Definition Index
nat_to_bin [in LF.Induction]
negb [in LF.Basics]
next_weekday [in LF.Basics]
+not_even_1001 [in LF.Logic]
+not_even_1001' [in LF.Logic]
no_whiles [in LF.Imp]
nth_error [in LF.Poly]
O
@@ -2982,7 +2960,7 @@Definition Index
Z : _ -(1231 entries) +(1238 entries) Notation Index @@ -3014,7 +2992,7 @@Definition Index
Z : _ -(82 entries) +(68 entries) Module Index @@ -3045,7 +3023,7 @@Definition Index
Y Z _ -(24 entries) +(25 entries) Library Index @@ -3107,7 +3085,7 @@Definition Index
Y Z _ -(350 entries) +(359 entries) Constructor Index @@ -3138,7 +3116,7 @@Definition Index
Y Z _ -(207 entries) +(211 entries) - Axiom Index @@ -3200,38 +3178,7 @@Definition Index
Y Z _ -(74 entries) -- Abbreviation Index -A -B -C -D -E -F -G -H -I -J -K -L -M -N -O -P -Q -R -S -T -U -V -W -X -Y -Z -_ -(4 entries) +(76 entries) Definition Index @@ -3262,7 +3209,7 @@Definition Index
Y Z _ -(470 entries) +(479 entries)
@@ -84,7 +86,7 @@
版本 5.6 (07 Dec 2018, Coq 8.8.0)
+版本 5.7 (26 Jan 2019, Coq 8.8.1)
前言 (Preface)下载 Coq 文件 -
课程视频 + + 资源 + -对授课员的要求 + 对授课员的要求 -译本 + 译本 -鸣谢 + 鸣谢 @@ -127,59 +137,59 @@Coq 函数式编程 (Basics<
@@ -188,16 +198,16 @@
- 页首 -
- 引言 +
- 引言
-- 数据与函数 +
- 数据与函数
-- 基于化简的证明 +
- 基于化简的证明
-- 基于改写的证明 +
- 基于改写的证明
-- 利用情况分析来证明 +
- 利用情况分析来证明
-- 关于记法的更多内容 (可选) +
- 关于记法的更多内容 (可选)
-- 不动点 Fixpoint 和结构化递归 (可选) +
- 不动点 Fixpoint 和结构化递归 (可选)
-- 更多练习 +
- 更多练习
归纳证明 (Induction
@@ -206,45 +216,45 @@
- 页首 -
- 归纳法证明 +
- 归纳法证明
-- 证明里的证明 +
- 证明里的证明
-- 形式化证明 vs. 非形式化证明 +
- 形式化证明 vs. 非形式化证明
-- 更多练习 +
- 更多练习
使用结构化的数据 (Lis
@@ -253,48 +263,48 @@
- 页首 -
- 数值序对 +
- 数值序对
-- 数值列表 +
- 数值列表
-- 有关列表的论证 +
- 有关列表的论证
-- Options 可选类型 +
- Options 可选类型
-- 偏映射(Partial Maps) +
- 偏映射(Partial Maps)
多态与高阶函数 (Poly @@ -303,31 +313,31 @@
更多基本策略 (Tactics
@@ -336,47 +346,47 @@
- 页首 -
- apply 策略 +
- apply 策略
-- apply with 策略 +
- apply with 策略
-- The injection and discriminate Tactics +
- The injection and discriminate Tactics
-- 对前提使用策略 +
- 对前提使用策略
-- 变换归纳原理 +
- 变换归纳原理
-- 展开定义 +
- 展开定义
-- 对复合表达式使用 destruct +
- 对复合表达式使用 destruct
-- 复习 +
- 复习
-- 附加练习 +
- 附加练习
Coq 中的逻辑系统 (Logic
- 页首 -
- 逻辑联结词 +
- 逻辑联结词
-- 使用命题编程 +
- 使用命题编程
-- 对参数应用定理 +
- 对参数应用定理
-- Coq vs. 集合论 +
- Coq vs. 集合论
@@ -389,42 +399,49 @@归纳定义的命题 (IndP
- 页首 -
- 归纳定义的命题 +
- 归纳定义的命题 + + +
+- 在证明中使用证据
-- 归纳关系 +
- 归纳关系
-- 案例学习:正则表达式 +
- 案例学习:正则表达式
-- 案例学习:改进互映 +
- 案例学习:改进互映
-- 额外练习 +
- 额外练习
@@ -437,16 +454,16 @@全映射与偏映射 (Maps @@ -455,38 +472,38 @@
柯里-霍华德对应 (<
- 页首 -
- 证明脚本 +
- 证明脚本
-- 量词,蕴含式,函数 +
- 量词,蕴含式,函数
-- 使用策略编程 +
- 使用策略编程
-- 逻辑联结词作为归纳类型 +
- 逻辑联结词作为归纳类型
--
- 合取 +
- 合取
-- 析取 +
- 析取
-- 存在量化 +
- 存在量化
-- True和False +
- True和False
- 相等关系 +
- 相等关系
@@ -499,28 +516,28 @@归纳原理 (IndPrin
- 页首 -
- 基础 +
- 基础
-- 多态 +
- 多态
-- 归纳假设 +
- 归纳假设
-- 深入 induction 策略 +
- 深入 induction 策略
-- Prop 中的归纳原理 +
- Prop 中的归纳原理
-- 形式化 vs. 非形式化的归纳证明 +
- 形式化 vs. 非形式化的归纳证明
@@ -533,13 +550,13 @@关系的性质 (Rel)
@@ -548,109 +565,115 @@简单的指令式程序 (Imp
@@ -659,20 +682,20 @@
- 页首 -
- 算术和布尔表达式 +
- 算术和布尔表达式
-- Coq 自动化 +
- Coq 自动化
-- 求值作为关系 +
- 求值作为关系
-- 带变量的表达式 +
- 带变量的表达式
-- 指令 +
- 指令
-- 求值指令 +
- 求值指令
-- 对 Imp 进行推理 +
- 对 Imp 进行推理
-- 附加练习 +
- 附加练习
用 Coq 实现词法分析和语法分析 &nbs
@@ -681,16 +704,16 @@Imp 的求值函数 (Im
@@ -699,19 +722,19 @@从 Coq 中提取 ML (Ex
@@ -720,13 +743,13 @@更多的自动化 (Auto)<
@@ -121,8 +121,7 @@
- 页首 -
- auto 策略 +
- auto 策略
-- 搜索前提 +
- 搜索前提
@@ -739,13 +762,13 @@@@ -109,10 +109,10 @@后记 (Postscript)<
@@ -754,7 +777,7 @@diff --git a/plf-current/Bib.v b/plf-current/Bib.v index 0c809497..68d614f2 100644 --- a/plf-current/Bib.v +++ b/plf-current/Bib.v @@ -39,3 +39,4 @@ (** $Date$ *) +(* Sat Jan 26 15:15:47 UTC 2019 *) diff --git a/plf-current/BibTest.v b/plf-current/BibTest.v index 25fd4cbc..f6459e11 100644 --- a/plf-current/BibTest.v +++ b/plf-current/BibTest.v @@ -43,3 +43,5 @@ idtac "********** Standard **********". idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:16:51 UTC 2019 *) diff --git a/plf-current/Equiv.html b/plf-current/Equiv.html index d2e7f5c6..7be279c3 100644 --- a/plf-current/Equiv.html +++ b/plf-current/Equiv.html @@ -35,16 +35,16 @@参考文献 (Bib)
diff --git a/plf-current/.coqdeps.d b/plf-current/.coqdeps.d index 4e9b4ab2..42aa23bd 100644 --- a/plf-current/.coqdeps.d +++ b/plf-current/.coqdeps.d @@ -6,18 +6,18 @@ Preface.vo Preface.glob Preface.v.beautified: Preface.v Preface.vio: Preface.v Equiv.vo Equiv.glob Equiv.v.beautified: Equiv.v Maps.vo Imp.vo Equiv.vio: Equiv.v Maps.vio Imp.vio -Hoare.vo Hoare.glob Hoare.v.beautified: Hoare.v Imp.vo Maps.vo -Hoare.vio: Hoare.v Imp.vio Maps.vio -Hoare2.vo Hoare2.glob Hoare2.v.beautified: Hoare2.v Maps.vo Imp.vo Hoare.vo -Hoare2.vio: Hoare2.v Maps.vio Imp.vio Hoare.vio +Hoare.vo Hoare.glob Hoare.v.beautified: Hoare.v Maps.vo Imp.vo +Hoare.vio: Hoare.v Maps.vio Imp.vio +Hoare2.vo Hoare2.glob Hoare2.v.beautified: Hoare2.v Maps.vo Hoare.vo Imp.vo +Hoare2.vio: Hoare2.v Maps.vio Hoare.vio Imp.vio HoareAsLogic.vo HoareAsLogic.glob HoareAsLogic.v.beautified: HoareAsLogic.v Imp.vo Hoare.vo HoareAsLogic.vio: HoareAsLogic.v Imp.vio Hoare.vio Smallstep.vo Smallstep.glob Smallstep.v.beautified: Smallstep.v Maps.vo Imp.vo Smallstep.vio: Smallstep.v Maps.vio Imp.vio Types.vo Types.glob Types.v.beautified: Types.v Maps.vo Imp.vo Smallstep.vo Types.vio: Types.v Maps.vio Imp.vio Smallstep.vio -Stlc.vo Stlc.glob Stlc.v.beautified: Stlc.v Maps.vo Smallstep.vo Types.vo -Stlc.vio: Stlc.v Maps.vio Smallstep.vio Types.vio +Stlc.vo Stlc.glob Stlc.v.beautified: Stlc.v Maps.vo Smallstep.vo +Stlc.vio: Stlc.v Maps.vio Smallstep.vio StlcProp.vo StlcProp.glob StlcProp.v.beautified: StlcProp.v Maps.vo Types.vo Stlc.vo Smallstep.vo StlcProp.vio: StlcProp.v Maps.vio Types.vio Stlc.vio Smallstep.vio MoreStlc.vo MoreStlc.glob MoreStlc.v.beautified: MoreStlc.v Maps.vo Types.vo Smallstep.vo Stlc.vo @@ -40,8 +40,8 @@ UseTactics.vo UseTactics.glob UseTactics.v.beautified: UseTactics.v Maps.vo Imp. UseTactics.vio: UseTactics.v Maps.vio Imp.vio Types.vio Smallstep.vio LibTactics.vio Stlc.vio Equiv.vio References.vio Hoare.vio Sub.vio UseAuto.vo UseAuto.glob UseAuto.v.beautified: UseAuto.v Maps.vo Smallstep.vo Stlc.vo LibTactics.vo Imp.vo StlcProp.vo References.vo Sub.vo UseAuto.vio: UseAuto.v Maps.vio Smallstep.vio Stlc.vio LibTactics.vio Imp.vio StlcProp.vio References.vio Sub.vio -PE.vo PE.glob PE.v.beautified: PE.v Maps.vo Imp.vo Smallstep.vo -PE.vio: PE.v Maps.vio Imp.vio Smallstep.vio +PE.vo PE.glob PE.v.beautified: PE.v Maps.vo Smallstep.vo Imp.vo +PE.vio: PE.v Maps.vio Smallstep.vio Imp.vio Postscript.vo Postscript.glob Postscript.v.beautified: Postscript.v Postscript.vio: Postscript.v Bib.vo Bib.glob Bib.v.beautified: Bib.v diff --git a/plf-current/Bib.html b/plf-current/Bib.html index 84269b25..e178cb55 100644 --- a/plf-current/Bib.html +++ b/plf-current/Bib.html @@ -36,7 +36,7 @@+Bib参考文献
-本卷中出现的引用
+本卷中出现的引用
@@ -91,6 +91,10 @@Bib参考文献
++ +(* Sat Jan 26 15:15:47 UTC 2019 *)
Equiv程序的等价关系 Set Warnings "-notation-overridden,-parsing".
-Require Import Coq.Bool.Bool.
-Require Import Coq.Arith.Arith.
-Require Import Coq.Init.Nat.
-Require Import Coq.Arith.PeanoNat. Import Nat.
-Require Import Coq.Arith.EqNat.
-Require Import Coq.omega.Omega.
-Require Import Coq.Lists.List.
-Require Import Coq.Logic.FunctionalExtensionality.
-Import ListNotations.
From PLF Require Import Maps.
+From Coq Require Import Bool.Bool.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Init.Nat.
+From Coq Require Import Arith.PeanoNat. Import Nat.
+From Coq Require Import Arith.EqNat.
+From Coq Require Import omega.Omega.
+From Coq Require Import Lists.List.
+From Coq Require Import Logic.FunctionalExtensionality.
+Import ListNotations.
From PLF Require Import Imp.
Equiv程序的等价关系 Definition aequiv (a1 a2 : aexp) : Prop :=
- ∀ (st:state),
+ ∀(st : state),
aeval st a1 = aeval st a2.
Definition bequiv (b1 b2 : bexp) : Prop :=
- ∀ (st:state),
+ ∀(st : state),
beval st b1 = beval st b2.
Equiv程序的等价关系
-Theorem aequiv_example:
- aequiv (X - X) 0.
+Theorem aequiv_example: aequiv (X - X) 0.
Proof.
@@ -131,8 +130,7 @@Equiv程序的等价关系
-Theorem bequiv_example:
- bequiv (X - X = 0) true.
+Theorem bequiv_example: bequiv (X - X = 0)%imp true.
Proof.
@@ -153,8 +151,8 @@Equiv程序的等价关系 Definition cequiv (c1 c2 : com) : Prop :=
- ∀ (st st' : state),
- (c1 / st \\ st') ↔ (c2 / st \\ st').
+ ∀(st st' : state),
+ (st =[ c1 ]⇒ st') ↔ (st =[ c2 ]⇒ st').
@@ -166,15 +164,15 @@Equiv程序的等价关系
-Theorem skip_left: ∀ c,
+Theorem skip_left : ∀c,
cequiv
- (SKIP;; c)
- c.
+ (SKIP;; c)
+ c.
Proof.
(* 课上已完成 *)
intros c st st'.
split; intros H.
- - (* -> *)
+ - (* -> *)
inversion H; subst.
inversion H2. subst.
assumption.
@@ -186,12 +184,12 @@Equiv程序的等价关系
-Theorem skip_right: ∀ c,
+Theorem skip_right : ∀c,
cequiv
(c ;; SKIP)
c.
@@ -203,20 +201,20 @@Equiv程序的等价关系
- 同样,下面是一个优化 IFB 的简单程序变换: + 同样,下面是一个优化 TEST 的简单程序变换:-Theorem IFB_true_simple: ∀ c1 c2,
+Theorem TEST_true_simple : ∀c1 c2,
cequiv
- (IFB BTrue THEN c1 ELSE c2 FI)
+ (TEST true THEN c1 ELSE c2 FI)
c1.
Proof.
intros c1 c2.
split; intros H.
- - (* -> *)
+ - (* -> *)
inversion H; subst. assumption. inversion H5.
- (* <- *)
apply E_IfTrue. reflexivity. assumption. Qed.
@@ -224,8 +222,8 @@Equiv程序的等价关系
-当然,人类程序员是不会写把断言(guard)直接写成 BTrue 的条件分支的。 - 有趣的是当断言等价于真的情况: 定理:若 b 等价于 BTrue,则 IFB b THEN c1 ELSE c2 FI 等价于 c1。 +当然,人类程序员是不会写把断言(guard)直接写成 true 的条件分支的。 + 不过当断言等价于真的情况时就会写出来: 定理:若 b 等价于 BTrue,则 TEST b THEN c1 ELSE c2 FI 等价于 c1。证明: @@ -233,27 +231,27 @@Equiv程序的等价关系
-
- (→) 我们必须证明,对于所有的 st 和 st',若 IFB b - THEN c1 ELSE c2 FI / st \\ st' 则 c1 / st \\ st'。 +
- (→) 我们必须证明,对于所有的 st 和 st',若 st =[ + TEST b THEN c1 ELSE c2 FI ]⇒ st' 则 st =[ c1 ]⇒ st'。
- 能够应用于 IFB b THEN c1 ELSE c2 FI / st \\ st' 的证明规则只有两条: + 能够应用于 st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st' 的证明规则只有两条: E_IfTrue 和 E_IfFalse。-
@@ -287,17 +285,17 @@- 假设 IFB b THEN c1 ELSE c2 FI / st \\ st' 证明自 E_IfTrue - 这条证明规则。若使用证明规则 E_IfTrue 其必备的前提条件 c1 / st \\ st' +
- 假设 st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st' 证明自 E_IfTrue + 这条证明规则。若使用证明规则 E_IfTrue 其必备的前提条件 st =[ c1 ]⇒ st' 必为真,而这正好是我们的证明所需要的条件。
-- 另一方面, 假设 IFB b THEN c1 ELSE c2 FI / st \\ st' 证明自 - E_IfFalse。我们能得知 beval st b = false 和 c2 / st \\ st'。 +
- 另一方面, 假设 st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st' 证明自 + E_IfFalse。我们能得知 beval st b = false 和 st =[ c2 ]⇒ st'。
-@@ -269,14 +267,14 @@Equiv程序的等价关系
- (<-) 我们必须证明,对于所有 st 和 st',若 c1 / st \\ st' +
- (<-) 我们必须证明,对于所有 st 和 st',若st =[ c1 ]⇒ st' 则 IFB b THEN c1 ELSE c2 FI / st \\ st'。
已知 b 等价于 BTrue,我们知道 beval st b = beval st BTrue = true。 - 结合 c1 / st \\ st' 这条假设,我们能应用 E_IfTrue 来证明出 IFB b THEN - c1 ELSE c2 FI / st \\ st'。 ☐ + 结合 st =[ c1 ]⇒ st' 这条假设,我们能应用 E_IfTrue 来证明 + st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'。 ☐Equiv程序的等价关系
-Theorem IFB_true: ∀ b c1 c2,
- bequiv b BTrue →
- cequiv
- (IFB b THEN c1 ELSE c2 FI)
- c1.
+Theorem TEST_true: ∀b c1 c2,
+ bequiv b BTrue →
+ cequiv
+ (TEST b THEN c1 ELSE c2 FI)
+ c1.
Proof.
intros b c1 c2 Hb.
split; intros H.
- - (* -> *)
+ - (* -> *)
inversion H; subst.
+ (* b 求值为 true *)
assumption.
@@ -313,14 +311,14 @@Equiv程序的等价关系
-Theorem IFB_false: ∀ b c1 c2,
- bequiv b BFalse →
+Theorem TEST_false : ∀b c1 c2,
+ bequiv b BFalse →
cequiv
- (IFB b THEN c1 ELSE c2 FI)
+ (TEST b THEN c1 ELSE c2 FI)
c2.
Proof.
(* 请在此处解答 *) Admitted.
@@ -330,15 +328,15 @@Equiv程序的等价关系
-练习:3 星 (swap_if_branches)
+练习:3 星, standard (swap_if_branches)
证明我们可以通过对断言取反来交换 IF 的两个分支-Theorem swap_if_branches: ∀ b e1 e2,@@ -353,7 +351,7 @@
+Theorem swap_if_branches : ∀b e1 e2,
cequiv
- (IFB b THEN e1 ELSE e2 FI)
- (IFB BNot b THEN e2 ELSE e1 FI).
+ (TEST b THEN e1 ELSE e2 FI)
+ (TEST BNot b THEN e2 ELSE e1 FI).
Proof.
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系
-Theorem WHILE_false : ∀ b c,- 引理:若 b 等价于 BTrue,则无法出现 (WHILE b DO c END) / - st \\ st' 的情况。 + 引理:若 b 等价于 BTrue,则无法出现 + st =[ WHILE b DO c END ]⇒ st' 的情况。
+Theorem WHILE_false : ∀b c,
bequiv b BFalse →
cequiv
(WHILE b DO c END)
@@ -362,7 +360,7 @@Equiv程序的等价关系 Proof.
intros b c Hb. split; intros H.
- - (* -> *)
+ - (* -> *)
inversion H; subst.
+ (* E_WhileFalse *)
apply E_Skip.
@@ -390,48 +388,49 @@Equiv程序的等价关系
- 证明:假设 (WHILE b DO c END) / st \\ st'。我们将证明通过对 - (WHILE b DO c END) / st \\ st' 使用归纳法会导出矛盾。 + 证明:假设 st =[ WHILE b DO c END ]⇒ st'。我们将证明通过对 + st =[ WHILE b DO c END ]⇒ st' 使用归纳法会导出矛盾。需要考虑只有 + E_WhileFalse 和 E_WhileTrue 两种情况,其它情况则矛盾。-
+ 1. beval st b = true, + 2. 存在某个 st0 使得 st =[ c ]⇒ st0 且 + st0 =[ WHILE b DO c END ]⇒ st', + 3. 以及我们给出了导致矛盾的归纳假设 st0 =[ WHILE b DO c END ]⇒ st', +- 假设 (WHILE b DO c END) / st \\ st' 使用规则 E_WhileFalse 证明。 +
- 假设 st =[ WHILE b DO c END ]⇒ st' 使用规则 E_WhileFalse 证明。 那么根据假设得出 beval st b = false。但它与 b 等价于 BTrue 矛盾。
-- 假设 (WHILE b DO c END) / st \\ st' 使用规则 E_WhileTrue证明。 - 那么我们就给出了一个和 (WHILE b DO c END) / st \\ st' 矛盾的假设, - 它刚好就是我们要证明的那个! - -
+- 假设 st =[ WHILE b DO c END ]⇒ st' 使用规则 E_WhileTrue证明。 + 我们必有: - -
-- 由于只有以上几条规则可用于证明 (WHILE b DO c END) / st \\ st', - 因此归纳时的其它情况可直接得出矛盾。 ☐
+ + 我们根据 2 和 3 会得到矛盾。 ☐-Lemma WHILE_true_nonterm : ∀ b c st st',
+Lemma WHILE_true_nonterm : ∀b c st st',
bequiv b BTrue →
- ~( (WHILE b DO c END) / st \\ st' ).
+ ~( st =[ WHILE b DO c END ]⇒ st' ).
Proof.
(* 课上已完成 *)
intros b c st st' Hb.
intros H.
- remember (WHILE b DO c END) as cw eqn:Heqcw.
+ remember (WHILE b DO c END)%imp as cw eqn:Heqcw.
induction H;
(* 大多数证明规则无法应用,我们可通过反演(inversion)来去除它们: *)
inversion Heqcw; subst; clear Heqcw.
@@ -445,7 +444,7 @@Equiv程序的等价关系
-练习:2 星, optional (WHILE_true_nonterm_informal)
+练习:2 星, standard, optional (WHILE_true_nonterm_informal)
试解释 WHILE_true_nonterm 的含义。@@ -454,12 +453,12 @@Equiv程序的等价关系☐
-练习:2 星, recommended (WHILE_true)
+练习:2 星, standard, recommended (WHILE_true)
请证明以下定理。提示:你可能需要使用 WHILE_true_nonterm 。-Theorem WHILE_true: ∀ b c,
+Theorem WHILE_true : ∀b c,
bequiv b true →
cequiv
(WHILE b DO c END)
@@ -477,17 +476,17 @@Equiv程序的等价关系
-Theorem loop_unrolling: ∀ b c,
+Theorem loop_unrolling : ∀b c,
cequiv
(WHILE b DO c END)
- (IFB b THEN (c ;; WHILE b DO c END) ELSE SKIP FI).
+ (TEST b THEN (c ;; WHILE b DO c END) ELSE SKIP FI).
Proof.
(* 课上已完成 *)
intros b c st st'.
split; intros Hce.
- - (* -> *)
+ - (* -> *)
inversion Hce; subst.
+ (* 不执行循环 *)
apply E_IfFalse. assumption. apply E_Skip.
@@ -506,11 +505,11 @@Equiv程序的等价关系
-Theorem seq_assoc : ∀ c1 c2 c3,
+Theorem seq_assoc : ∀c1 c2 c3,
cequiv ((c1;;c2);;c3) (c1;;(c2;;c3)).
Proof.
(* 请在此处解答 *) Admitted.
@@ -520,38 +519,37 @@Equiv程序的等价关系
- 证明涉及赋值的程序属性经常会用到函数的外延公理。 + 证明涉及赋值的程序的属性经常会用到这一事实,即程序状态会根据其外延性 + (如 x !-> m x ; m 和 m 是相等的映射)来对待。-Theorem identity_assignment : ∀ (X:string),
+Theorem identity_assignment : ∀x,
cequiv
- (X ::= X)
+ (x ::= x)
SKIP.
Proof.
- intros. split; intro H.
- - (* -> *)
- inversion H; subst. simpl.
- replace (st & { X --> st X }) with st.
- + constructor.
- + apply functional_extensionality. intro.
- rewrite t_update_same; reflexivity.
- - (* <- *)
- replace st' with (st' & { X --> aeval st' X }).
- + inversion H. subst. apply E_Ass. reflexivity.
- + apply functional_extensionality. intro.
- rewrite t_update_same. reflexivity.
+ intros.
+ split; intro H; inversion H; subst.
+ - (* -> *)
+ rewrite t_update_same.
+ apply E_Skip.
+ - (* <- *)
+ assert (Hx : st' =[ x ::= x ]⇒ (x !-> st' x ; st')).
+ { apply E_Ass. reflexivity. }
+ rewrite t_update_same in Hx.
+ apply Hx.
Qed.
-Theorem assign_aequiv : ∀ (X:string) e,@@ -560,7 +558,7 @@
- aequiv X e →
- cequiv SKIP (X ::= e).
+Theorem assign_aequiv : ∀(x : string) e,
+ aequiv x e →
+ cequiv SKIP (x ::= e).
Proof.
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系
-练习:2 星 (equiv_classes)
+练习:2 星, standard (equiv_classes)
@@ -581,43 +579,43 @@Equiv程序的等价关系 Definition prog_a : com :=
- WHILE ! (X ≤ 0) DO
+ (WHILE ~(X ≤ 0) DO
X ::= X + 1
- END.
+ END)%imp.
Definition prog_b : com :=
- IFB X = 0 THEN
+ (TEST X = 0 THEN
X ::= X + 1;;
Y ::= 1
ELSE
Y ::= 0
FI;;
X ::= X - Y;;
- Y ::= 0.
+ Y ::= 0)%imp.
Definition prog_c : com :=
- SKIP.
+ SKIP%imp.
Definition prog_d : com :=
- WHILE ! (X = 0) DO
+ (WHILE ~(X = 0) DO
X ::= (X * Y) + 1
- END.
+ END)%imp.
Definition prog_e : com :=
- Y ::= 0.
+ (Y ::= 0)%imp.
Definition prog_f : com :=
- Y ::= X + 1;;
- WHILE ! (X = Y) DO
+ (Y ::= X + 1;;
+ WHILE ~(X = Y) DO
Y ::= X + 1
- END.
+ END)%imp.
Definition prog_g : com :=
- WHILE true DO
+ (WHILE true DO
SKIP
- END.
+ END)%imp.
Definition prog_h : com :=
- WHILE ! (X = X) DO
+ (WHILE ~(X = X) DO
X ::= X + 1
- END.
+ END)%imp.
Definition prog_i : com :=
- WHILE ! (X = Y) DO
+ (WHILE ~(X = Y) DO
X ::= Y + 1
- END.
+ END)%imp.
Definition equiv_classes : list (list com)
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
(* 请勿修改下面这一行: *)
@@ -645,7 +643,7 @@Equiv程序的等价关系
-Lemma refl_aequiv : ∀ (a : aexp), aequiv a a.
+Lemma refl_aequiv : ∀(a : aexp), aequiv a a.
Proof.
@@ -653,7 +651,7 @@Equiv程序的等价关系
-Lemma sym_aequiv : ∀ (a1 a2 : aexp),
+Lemma sym_aequiv : ∀(a1 a2 : aexp),
aequiv a1 a2 → aequiv a2 a1.
@@ -662,7 +660,7 @@Equiv程序的等价关系
-Lemma trans_aequiv : ∀ (a1 a2 a3 : aexp),
+Lemma trans_aequiv : ∀(a1 a2 a3 : aexp),
aequiv a1 a2 → aequiv a2 a3 → aequiv a1 a3.
@@ -672,7 +670,7 @@Equiv程序的等价关系
-Lemma refl_bequiv : ∀ (b : bexp), bequiv b b.
+Lemma refl_bequiv : ∀(b : bexp), bequiv b b.
Proof.
@@ -680,7 +678,7 @@Equiv程序的等价关系
-Lemma sym_bequiv : ∀ (b1 b2 : bexp),
+Lemma sym_bequiv : ∀(b1 b2 : bexp),
bequiv b1 b2 → bequiv b2 b1.
@@ -689,7 +687,7 @@Equiv程序的等价关系
-Lemma trans_bequiv : ∀ (b1 b2 b3 : bexp),
+Lemma trans_bequiv : ∀(b1 b2 b3 : bexp),
bequiv b1 b2 → bequiv b2 b3 → bequiv b1 b3.
@@ -699,7 +697,7 @@Equiv程序的等价关系
-Lemma refl_cequiv : ∀ (c : com), cequiv c c.
+Lemma refl_cequiv : ∀(c : com), cequiv c c.
Proof.
@@ -707,20 +705,20 @@Equiv程序的等价关系
-Lemma sym_cequiv : ∀ (c1 c2 : com),
+Lemma sym_cequiv : ∀(c1 c2 : com),
cequiv c1 c2 → cequiv c2 c1.
Proof.
unfold cequiv. intros c1 c2 H st st'.
- assert (c1 / st \\ st' ↔ c2 / st \\ st') as H'.
+ assert (st =[ c1 ]⇒ st' ↔ st =[ c2 ]⇒ st') as H'.
{ (* Proof of assertion *) apply H. }
apply iff_sym. assumption.
Qed.
-Lemma iff_trans : ∀ (P1 P2 P3 : Prop),
+Lemma iff_trans : ∀(P1 P2 P3 : Prop),
(P1 ↔ P2) → (P2 ↔ P3) → (P1 ↔ P3).
@@ -733,13 +731,13 @@@@ -761,7 +759,7 @@Equiv程序的等价关系
-Lemma trans_cequiv : ∀ (c1 c2 c3 : com),
+Lemma trans_cequiv : ∀(c1 c2 c3 : com),
cequiv c1 c2 → cequiv c2 c3 → cequiv c1 c3.
Proof.
unfold cequiv. intros c1 c2 c3 H12 H23 st st'.
- apply iff_trans with (c2 / st \\ st'). apply H12. apply H23. Qed.
+ apply iff_trans with (st =[ c2 ]⇒ st'). apply H12. apply H23. Qed.
Equiv程序的等价关系
- cequiv (i ::= a1) (i ::= a1') +cequiv (x ::= a1) (x ::= a1') @@ -679,8 +686,8 @@ @@ -796,15 +794,15 @@
Equiv程序的等价关系
-Theorem CAss_congruence : ∀ i a1 a1',
+Theorem CAss_congruence : ∀x a1 a1',
aequiv a1 a1' →
- cequiv (CAss i a1) (CAss i a1').
+ cequiv (CAss x a1) (CAss x a1').
Proof.证明: 假设 b1 等价于 b1' 且 c1 等价于 c1'。我们必须证明, - 对于每个 st 和 st',WHILE b1 DO c1 END / st \\ st' 当且仅当 - WHILE b1' DO c1' END / st \\ st'。我们把两个方向分开考虑。 + 对于每个 st 和 st',st =[ WHILE b1 DO c1 END ]⇒ st' 当且仅当 + st =[ WHILE b1' DO c1' END ]⇒ st'。我们把两个方向分开考虑。
- intros i a1 a2 Heqv st st'.
+ intros x a1 a2 Heqv st st'.
split; intros Hceval.
- - (* -> *)
+ - (* -> *)
inversion Hceval. subst. apply E_Ass.
rewrite Heqv. reflexivity.
- (* <- *)
@@ -824,14 +822,14 @@Equiv程序的等价关系
-
- (→) 我们通过对 WHILE b1 DO c1 END / st \\ st' 使用归纳法证明 - WHILE b1 DO c1 END / st \\ st' 蕴含 WHILE b1' DO c1' END / st \\ st'。 +
- (→) 我们通过对 st =[ WHILE b1 DO c1 END ]⇒ st' 使用归纳法证明 + st =[ WHILE b1 DO c1 END ]⇒ st' 蕴含 st =[ WHILE b1' DO c1' END ]⇒ st'。 只有推导的最后所使用的规则为 E_WhileFalse 或 E_WhileTrue 时才需要进行特别讨论。 @@ -841,21 +839,21 @@
Equiv程序的等价关系 E_WhileFalse:此时我们拥有假设的必备条件 beval st b1 = false 和 st = st'。但是,由于 b1 和 b1' 等价,我们有 beval st b1' = false,然后应用 E-WhileFalse 得出我们需要的 - WHILE b1' DO c1' END / st \\ st'。 + st =[ WHILE b1' DO c1' END ]⇒ st'。
- E_WhileTrue:此时我们拥有假设的必备条件 beval st b1 = true,以及 - 对于某些状态 st'0 的 c1 / st \\ st'0 和 WHILE b1 DO c1 END / st'0 - \\ st',还有归纳假设 WHILE b1' DO c1' END / st'0 \\ st'。 + 对于某些状态 st'0 的 st =[ c1 ]⇒ st'0 和 st'0 =[ WHILE b1 DO c1 + END ]⇒ st',还有归纳假设 st'0 =[ WHILE b1' DO c1' END ]⇒ st'。
- 由于 c1 和 c1' 等价,我们有 c1' / st \\ st'0; + 由于 c1 和 c1' 等价,我们有 st =[ c1' ]⇒ st'0; 由于 b1 和 b1' 等价,我们有 beval st b1' = true。现在应用 - E-WhileTrue,得出我们所需的 WHILE b1' DO c1' END / st \\ st'。 + E-WhileTrue,得出我们所需的 st =[ WHILE b1' DO c1' END ]⇒ st'。@@ -871,7 +869,7 @@Equiv程序的等价关系
-Theorem CWhile_congruence : ∀ b1 b1' c1 c1',@@ -1025,33 +1027,34 @@
+Theorem CWhile_congruence : ∀b1 b1' c1 c1',
bequiv b1 b1' → cequiv c1 c1' →
cequiv (WHILE b1 DO c1 END) (WHILE b1' DO c1' END).
Proof.
@@ -879,8 +877,8 @@Equiv程序的等价关系unfold bequiv,cequiv.
intros b1 b1' c1 c1' Hb1e Hc1e st st'.
split; intros Hce.
- - (* -> *)
- remember (WHILE b1 DO c1 END) as cwhile
+ - (* -> *)
+ remember (WHILE b1 DO c1 END)%imp as cwhile
eqn:Heqcwhile.
induction Hce; inversion Heqcwhile; subst.
+ (* E_WhileFalse *)
@@ -893,7 +891,7 @@Equiv程序的等价关系(* 执行之后的循环 *)
apply IHHce2. reflexivity.
- (* <- *)
- remember (WHILE b1' DO c1' END) as c'while
+ remember (WHILE b1' DO c1' END)%imp as c'while
eqn:Heqc'while.
induction Hce; inversion Heqc'while; subst.
+ (* E_WhileFalse *)
@@ -908,29 +906,33 @@Equiv程序的等价关系
-Theorem CSeq_congruence : ∀ c1 c1' c2 c2',@@ -999,13 +1001,13 @@
+Theorem CSeq_congruence : ∀c1 c1' c2 c2',
cequiv c1 c1' → cequiv c2 c2' →
cequiv (c1;;c2) (c1';;c2').
++Proof.☐ - + +
(* 请在此处解答 *) Admitted.
-Theorem CIf_congruence : ∀ b b' c1 c1' c2 c2',@@ -947,7 +949,7 @@
+Theorem CIf_congruence : ∀b b' c1 c1' c2 c2',
bequiv b b' → cequiv c1 c1' → cequiv c2 c2' →
- cequiv (IFB b THEN c1 ELSE c2 FI)
- (IFB b' THEN c1' ELSE c2' FI).
+ cequiv (TEST b THEN c1 ELSE c2 FI)
+ (TEST b' THEN c1' ELSE c2' FI).
Proof.
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系cequiv
(* 程序 1: *)
(X ::= 0;;
- IFB X = 0
+ TEST X = 0
THEN
Y ::= 0
ELSE
@@ -955,7 +957,7 @@Equiv程序的等价关系FI)
(* 程序 1: *)
(X ::= 0;;
- IFB X = 0
+ TEST X = 0
THEN
Y ::= X - X (* <--- 这里不同 *)
ELSE
@@ -963,12 +965,12 @@Equiv程序的等价关系FI).
Proof.
apply CSeq_congruence.
- apply refl_cequiv.
- apply CIf_congruence.
- apply refl_bequiv.
- apply CAss_congruence. unfold aequiv. simpl.
- symmetry. apply minus_diag.
- apply refl_cequiv.
+ - apply refl_cequiv.
+ - apply CIf_congruence.
+ + apply refl_bequiv.
+ + apply CAss_congruence. unfold aequiv. simpl.
+ * symmetry. apply minus_diag.
+ + apply refl_cequiv.
Qed.
Equiv程序的等价关系 Definition atrans_sound (atrans : aexp → aexp) : Prop :=
- ∀ (a : aexp),
+ ∀(a : aexp),
aequiv a (atrans a).
Definition btrans_sound (btrans : bexp → bexp) : Prop :=
- ∀ (b : bexp),
+ ∀(b : bexp),
bequiv b (btrans b).
Definition ctrans_sound (ctrans : com → com) : Prop :=
- ∀ (c : com),
+ ∀(c : com),
cequiv c (ctrans c).
Equiv程序的等价关系Fixpoint fold_constants_aexp (a : aexp) : aexp :=
match a with
| ANum n ⇒ ANum n
- | AId i ⇒ AId i
+ | AId x ⇒ AId x
| APlus a1 a2 ⇒
- match (fold_constants_aexp a1, fold_constants_aexp a2)
+ match (fold_constants_aexp a1,
+ fold_constants_aexp a2)
with
| (ANum n1, ANum n2) ⇒ ANum (n1 + n2)
| (a1', a2') ⇒ APlus a1' a2'
end
| AMinus a1 a2 ⇒
- match (fold_constants_aexp a1, fold_constants_aexp a2)
+ match (fold_constants_aexp a1,
+ fold_constants_aexp a2)
with
| (ANum n1, ANum n2) ⇒ ANum (n1 - n2)
| (a1', a2') ⇒ AMinus a1' a2'
end
| AMult a1 a2 ⇒
- match (fold_constants_aexp a1, fold_constants_aexp a2)
+ match (fold_constants_aexp a1,
+ fold_constants_aexp a2)
with
| (ANum n1, ANum n2) ⇒ ANum (n1 * n2)
| (a1', a2') ⇒ AMult a1' a2'
end
end.
-(* 解析下面的示例时要用 *)
-Local Open Scope aexp_scope.
-Local Open Scope bexp_scope.
Example fold_aexp_ex1 :
- fold_constants_aexp ((1 + 2) * X) = (3 * X).
--+ fold_constants_aexp ((1 + 2) * X)@@ -1064,9 +1067,9 @@
+ = (3 * X)%imp.
++Proof. reflexivity. Qed.
Equiv程序的等价关系 Example fold_aexp_ex2 :
- fold_constants_aexp (X - ((0 * 6) + Y)) = (X - (0 + Y)).
--+ fold_constants_aexp (X - ((0 * 6) + Y))%imp = (X - (0 + Y))%imp.@@ -1082,14 +1085,16 @@
++Proof. reflexivity. Qed.
Equiv程序的等价关系BTrue ⇒ BTrue
| BFalse ⇒ BFalse
| BEq a1 a2 ⇒
- match (fold_constants_aexp a1, fold_constants_aexp a2) with
+ match (fold_constants_aexp a1,
+ fold_constants_aexp a2) with
| (ANum n1, ANum n2) ⇒
if n1 =? n2 then BTrue else BFalse
| (a1', a2') ⇒
BEq a1' a2'
end
| BLe a1 a2 ⇒
- match (fold_constants_aexp a1, fold_constants_aexp a2) with
+ match (fold_constants_aexp a1,
+ fold_constants_aexp a2) with
| (ANum n1, ANum n2) ⇒
if n1 <=? n2 then BTrue else BFalse
| (a1', a2') ⇒
@@ -1102,7 +1107,8 @@Equiv程序的等价关系b1' ⇒ BNot b1'
end
| BAnd b1 b2 ⇒
- match (fold_constants_bexp b1, fold_constants_bexp b2) with
+ match (fold_constants_bexp b1,
+ fold_constants_bexp b2) with
| (BTrue, BTrue) ⇒ BTrue
| (BTrue, BFalse) ⇒ BFalse
| (BFalse, BTrue) ⇒ BFalse
@@ -1111,18 +1117,19 @@Equiv程序的等价关系end
end.
Example fold_bexp_ex1 :
- fold_constants_bexp (true && ! (false && true)) = true.
--+ fold_constants_bexp (true && ~(false && true))%imp- 以下形式化的定义描述了如何在算术表达式中, - 将某个变量的所有引用都替换成另一个表达式: + 以下形式化的定义描述了如何在算术表达式 a 中, + 将某个变量 x 的所有引用都替换成另一个表达式 u :
+ = true.
++Proof. reflexivity. Qed.
Example fold_bexp_ex2 :
- fold_constants_bexp ((X = Y) && (0 = (2 - (1 + 1)))) =
- ((X = Y) && true).
--+ fold_constants_bexp ((X = Y) && (0 = (2 - (1 + 1))))%imp@@ -1132,19 +1139,20 @@
+ = ((X = Y) && true)%imp.
++Proof. reflexivity. Qed.
Equiv程序的等价关系
+Open Scope imp.
Fixpoint fold_constants_com (c : com) : com :=
match c with
| SKIP ⇒
SKIP
- | i ::= a ⇒
- CAss i (fold_constants_aexp a)
+ | x ::= a ⇒
+ x ::= (fold_constants_aexp a)
| c1 ;; c2 ⇒
(fold_constants_com c1) ;; (fold_constants_com c2)
- | IFB b THEN c1 ELSE c2 FI ⇒
+ | TEST b THEN c1 ELSE c2 FI ⇒
match fold_constants_bexp b with
- | BTrue ⇒ fold_constants_com c1
+ | BTrue ⇒ fold_constants_com c1
| BFalse ⇒ fold_constants_com c2
- | b' ⇒ IFB b' THEN fold_constants_com c1
+ | b' ⇒ TEST b' THEN fold_constants_com c1
ELSE fold_constants_com c2 FI
end
| WHILE b DO c END ⇒
@@ -1153,40 +1161,31 @@Equiv程序的等价关系BFalse ⇒ SKIP
| b' ⇒ WHILE b' DO (fold_constants_com c) END
end
- end.
+ end.
+Close Scope imp.
Example fold_com_ex1 :
fold_constants_com
(* 原程序: *)
(X ::= 4 + 5;;
Y ::= X - 3;;
- IFB (X - Y) = (2 + 4) THEN
- SKIP
- ELSE
- Y ::= 0
- FI;;
- IFB 0 ≤ (4 - (2 + 1))
- THEN
- Y ::= 0
- ELSE
- SKIP
- FI;;
+ TEST (X - Y) = (2 + 4) THEN SKIP
+ ELSE Y ::= 0 FI;;
+ TEST 0 ≤ (4 - (2 + 1)) THEN Y ::= 0
+ ELSE SKIP FI;;
WHILE Y = 0 DO
X ::= X + 1
- END)
+ END)%imp
= (* 常量折叠后: *)
(X ::= 9;;
Y ::= X - 3;;
- IFB (X - Y) = 6 THEN
- SKIP
- ELSE
- Y ::= 0
- FI;;
+ TEST (X - Y) = 6 THEN SKIP
+ ELSE Y ::= 0 FI;;
Y ::= 0;;
WHILE Y = 0 DO
X ::= X + 1
- END).
--+ END)%imp.@@ -1205,8 +1204,8 @@
++Proof. reflexivity. Qed.
Equiv程序的等价关系Theorem fold_constants_aexp_sound :
atrans_sound fold_constants_aexp.
--+- 本例证毕。 ☐ - + 本例证毕。 ☐ @@ -1432,7 +1430,7 @@+Proof.
unfold atrans_sound. intros a. unfold aequiv. intros st.
induction a; simpl;
@@ -1224,7 +1223,7 @@Equiv程序的等价关系
-证明:我们必须证明对于所有的布尔表达式 b,b 都等价于 - fold_constants_bexp。我们对 b 使用归纳法。这里只给出了 b + fold_constants_bexp b。我们对 b 使用归纳法。这里只给出了 b 形如 BEq a1 a2 的情况。练习:3 星, optional (fold_bexp_Eq_informal)
+练习:3 星, standard, optional (fold_bexp_Eq_informal)
下面是布尔表达式常量折叠中 BEq 情况的可靠性的证明。 请认真读完它再和之后的形式化证明作比较,然后补充完 BLe 情况的形式化证明 (尽量不看之前 BEq 情况的证明)。 @@ -1236,7 +1235,7 @@Equiv程序的等价关系
@@ -1378,8 +1377,7 @@Equiv程序的等价关系
Equiv程序的等价关系
-练习:3 星 (fold_constants_com_sound)
+练习:3 星, standard (fold_constants_com_sound)
完成以下证明的 WHILE 情况。@@ -1446,7 +1444,7 @@@@ -1563,29 +1561,29 @@Equiv程序的等价关系(* ::= *) apply CAss_congruence.
apply fold_constants_aexp_sound.
- (* ;; *) apply CSeq_congruence; assumption.
- - (* IFB *)
+ - (* TEST *)
assert (bequiv b (fold_constants_bexp b)). {
apply fold_constants_bexp_sound. }
destruct (fold_constants_bexp b) eqn:Heqb;
@@ -1455,10 +1453,10 @@Equiv程序的等价关系fold_constants_bexp_sound 来得出证明。) *)
+ (* b 总为真 *)
apply trans_cequiv with c1; try assumption.
- apply IFB_true; assumption.
+ apply TEST_true; assumption.
+ (* b 总为假 *)
apply trans_cequiv with c2; try assumption.
- apply IFB_false; assumption.
+ apply TEST_false; assumption.
- (* WHILE *)
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系
-Fixpoint subst_aexp (i : string) (u : aexp) (a : aexp) : aexp :=
+Fixpoint subst_aexp (x : string) (u : aexp) (a : aexp) : aexp :=
match a with
| ANum n ⇒
ANum n
- | AId i' ⇒
- if eqb_string i i' then u else AId i'
+ | AId x' ⇒
+ if eqb_string x x' then u else AId x'
| APlus a1 a2 ⇒
- APlus (subst_aexp i u a1) (subst_aexp i u a2)
+ APlus (subst_aexp x u a1) (subst_aexp x u a2)
| AMinus a1 a2 ⇒
- AMinus (subst_aexp i u a1) (subst_aexp i u a2)
+ AMinus (subst_aexp x u a1) (subst_aexp x u a2)
| AMult a1 a2 ⇒
- AMult (subst_aexp i u a1) (subst_aexp i u a2)
+ AMult (subst_aexp x u a1) (subst_aexp x u a2)
end.
Example subst_aexp_ex :
- subst_aexp X (42 + 53) (Y + X)
- = (Y + (42 + 53)).
--+ subst_aexp X (42 + 53) (Y + X)%imp@@ -1596,31 +1594,31 @@
+ = (Y + (42 + 53))%imp.
++Proof. reflexivity. Qed.
Equiv程序的等价关系
-Definition subst_equiv_property := ∀ i1 i2 a1 a2,
- cequiv (i1 ::= a1;; i2 ::= a2)
- (i1 ::= a1;; i2 ::= subst_aexp i1 a1 a2).
+Definition subst_equiv_property := ∀x1 x2 a1 a2,
+ cequiv (x1 ::= a1;; x2 ::= a2)
+ (x1 ::= a1;; x2 ::= subst_aexp x1 a1 a2).
遗憾的是, 这个性质并不总是成立 — 即,它并不是对所有的 - i1、i2、a1 和 a2 都成立。 + x1、x2、a1 和 a2 都成立。- cequiv (i1 ::= a1;; i2 ::= a2)- 我们使用反证法来证明这一点。假设对于所有的 i1、i2、a1 + 我们使用反证法来证明这一点。假设对于所有的 x1、x2、a1 和 a2,我们有
- (i1 ::= a1;; i2 ::= subst_aexp i1 a1 a2). + cequiv (x1 ::= a1;; x2 ::= a2)
+ (x1 ::= a1;; x2 ::= subst_aexp x1 a1 a2).- cequiv (i1 ::= a1;; i2 ::= a2)@@ -1629,7 +1627,7 @@
- (i1 ::= a1;; i2 ::= subst_aexp i1 a1 a2). + cequiv (x1 ::= a1;; x2 ::= a2)
+ (x1 ::= a1;; x2 ::= subst_aexp x1 a1 a2).Equiv程序的等价关系
- X ::= X + 1;; Y ::= X + X ::= X + 1;; Y ::= X@@ -1638,12 +1636,11 @@Equiv程序的等价关系
- (X ::= X + 1;; Y ::= X)- 其中 st1 = { X --> 1; Y --> 1 }。 + 其中 st1 = (Y !-> 1 ; X !-> 1).
- / { --> 0 } \\ st1, + empty_st =[ X ::= X + 1;; Y ::= X ]⇒ st1,@@ -1664,8 +1661,7 @@Equiv程序的等价关系
- (X ::= X + 1;; Y ::= X + 1@@ -1674,77 +1670,76 @@
- / { --> 0 } \\ st1. + empty_st =[ X ::= X + 1;; Y ::= X + 1 ]⇒ st1.Equiv程序的等价关系
- (X ::= X + 1;; Y ::= X + 1)- 其中 st2 = { X --> 1; Y --> 2 }。但由于 ceval 是确定性的,而 - st1 ≠ st2 ,这就造成了矛盾! ☐ + 其中 st2 = (Y !-> 2 ; X !-> 1)。但由于 ceval 是确定性的,而 + st1 ≠ st2 ,这就造成了矛盾! ☐
- / { --> 0 } \\ st2, + empty_st =[ X ::= X + 1;; Y ::= X + 1 ]⇒ st2,Theorem subst_inequiv :
- ¬ subst_equiv_property.
--+ ¬subst_equiv_property.
++Proof.
unfold subst_equiv_property.
intros Contra.
(* 这里有个反例:假设 subst_equiv_property
成立能够让我们证明以下两个程序等价... *)
remember (X ::= X + 1;;
- Y ::= X)
+ Y ::= X)%imp
as c1.
remember (X ::= X + 1;;
- Y ::= X + 1)
+ Y ::= X + 1)%imp
as c2.
assert (cequiv c1 c2) by (subst; apply Contra).
- (* ...让我们证明 c2 能够在两个不同的状态下停机:
- st1 = {X --> 1; Y --> 1}
- st2 = {X --> 1; Y --> 2}. *)
- remember {X --> 1 ; Y --> 1} as st1.
- remember {X --> 1 ; Y --> 2} as st2.
- assert (H1: c1 / { --> 0 } \\ st1);
- assert (H2: c2 / { --> 0 } \\ st2);
+ (* ...我们来证明 c2 能够在两个不同的状态下停机:
+ st1 = (Y !-> 1 ; X !-> 1)
+ st2 = (Y !-> 2 ; X !-> 1). *)
+ remember (Y !-> 1 ; X !-> 1) as st1.
+ remember (Y !-> 2 ; X !-> 1) as st2.
+ assert (H1 : empty_st =[ c1 ]⇒ st1);
+ assert (H2 : empty_st =[ c2 ]⇒ st2);
try (subst;
- apply E_Seq with (st' := {X --> 1});
+ apply E_Seq with (st' := (X !-> 1));
apply E_Ass; reflexivity).
apply H in H1.
(* 最后,因为程序求值的确定性而产生矛盾。 *)
- assert (Hcontra: st1 = st2)
- by (apply (ceval_deterministic c2 { --> 0 }); assumption).
- assert (Hcontra': st1 Y = st2 Y)
+ assert (Hcontra : st1 = st2)
+ by (apply (ceval_deterministic c2 empty_st); assumption).
+ assert (Hcontra' : st1 Y = st2 Y)
by (rewrite Hcontra; reflexivity).
subst. inversion Hcontra'. Qed.
-练习:4 星, optional (better_subst_equiv)
+练习:4 星, standard, optional (better_subst_equiv)
之前我们思考的等价关系也不全是妄言 — 只要再增加一个条件, 即变量 X 不在第一个赋值语句的右边出现,它就是正确的了。-Inductive var_not_used_in_aexp (X:string) : aexp → Prop :=@@ -1761,13 +1756,13 @@
- | VNUNum: ∀ n, var_not_used_in_aexp X (ANum n)
- | VNUId: ∀ Y, X ≠ Y → var_not_used_in_aexp X (AId Y)
- | VNUPlus: ∀ a1 a2,
- var_not_used_in_aexp X a1 →
- var_not_used_in_aexp X a2 →
- var_not_used_in_aexp X (APlus a1 a2)
- | VNUMinus: ∀ a1 a2,
- var_not_used_in_aexp X a1 →
- var_not_used_in_aexp X a2 →
- var_not_used_in_aexp X (AMinus a1 a2)
- | VNUMult: ∀ a1 a2,
- var_not_used_in_aexp X a1 →
- var_not_used_in_aexp X a2 →
- var_not_used_in_aexp X (AMult a1 a2).
-Lemma aeval_weakening : ∀ i st a ni,
- var_not_used_in_aexp i a →
- aeval (st & { i --> ni }) a = aeval st a.
+Inductive var_not_used_in_aexp (x : string) : aexp → Prop :=
+ | VNUNum : ∀n, var_not_used_in_aexp x (ANum n)
+ | VNUId : ∀y, x ≠ y → var_not_used_in_aexp x (AId y)
+ | VNUPlus : ∀a1 a2,
+ var_not_used_in_aexp x a1 →
+ var_not_used_in_aexp x a2 →
+ var_not_used_in_aexp x (APlus a1 a2)
+ | VNUMinus : ∀a1 a2,
+ var_not_used_in_aexp x a1 →
+ var_not_used_in_aexp x a2 →
+ var_not_used_in_aexp x (AMinus a1 a2)
+ | VNUMult : ∀a1 a2,
+ var_not_used_in_aexp x a1 →
+ var_not_used_in_aexp x a2 →
+ var_not_used_in_aexp x (AMult a1 a2).
+Lemma aeval_weakening : ∀x st a ni,
+ var_not_used_in_aexp x a →
+ aeval (x !-> ni ; st) a = aeval st a.
Proof.
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系
-练习:3 星 (inequiv_exercise)
+练习:3 星, standard (inequiv_exercise)
证明无限循环不等价于 SKIPTheorem inequiv_exercise:@@ -1841,58 +1836,61 @@
- ¬ cequiv (WHILE true DO SKIP END) SKIP.
+ ¬cequiv (WHILE true DO SKIP END) SKIP.
Proof.
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系CSeq : com → com → com
| CIf : bexp → com → com → com
| CWhile : bexp → com → com
- | CHavoc : string → com. (* <---- 新增的 *)
+ | CHavoc : string → com. (* <--- 新增 *)
Notation "'SKIP'" :=
- CSkip.
+ CSkip : imp_scope.
Notation "X '::=' a" :=
- (CAss X a) (at level 60).
+ (CAss X a) (at level 60) : imp_scope.
Notation "c1 ;; c2" :=
- (CSeq c1 c2) (at level 80, right associativity).
+ (CSeq c1 c2) (at level 80, right associativity) : imp_scope.
Notation "'WHILE' b 'DO' c 'END'" :=
- (CWhile b c) (at level 80, right associativity).
-Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" :=
- (CIf e1 e2 e3) (at level 80, right associativity).
-Notation "'HAVOC' l" := (CHavoc l) (at level 60).
+ (CWhile b c) (at level 80, right associativity) : imp_scope.
+Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" :=
+ (CIf e1 e2 e3) (at level 80, right associativity) : imp_scope.
+Notation "'HAVOC' l" :=
+ (CHavoc l) (at level 60) : imp_scope.
-练习:2 星 (himp_ceval)
+练习:2 星, standard (himp_ceval)
现在,我们必须扩展操作语义。前面我们已经提过了 ceval 关系的模版, 指定了大步语义。为了形式化 HAVOC 指令的行为,我们还需要在 ceval 的定义中添加哪些规则?-Reserved Notation "c1 '/' st '\\' st'"
- (at level 40, st at level 39).
+Reserved Notation "st '=[' c ']⇒' st'" (at level 40).
+Open Scope imp_scope.
Inductive ceval : com → state → state → Prop :=
- | E_Skip : ∀ st : state, SKIP / st \\ st
- | E_Ass : ∀ (st : state) (a1 : aexp) (n : nat) (X : string),
+ | E_Skip : ∀st,
+ st =[ SKIP ]⇒ st
+ | E_Ass : ∀st a1 n x,
aeval st a1 = n →
- (X ::= a1) / st \\ st & { X --> n }
- | E_Seq : ∀ (c1 c2 : com) (st st' st'' : state),
- c1 / st \\ st' →
- c2 / st' \\ st'' →
- (c1 ;; c2) / st \\ st''
- | E_IfTrue : ∀ (st st' : state) (b1 : bexp) (c1 c2 : com),
- beval st b1 = true →
- c1 / st \\ st' →
- (IFB b1 THEN c1 ELSE c2 FI) / st \\ st'
- | E_IfFalse : ∀ (st st' : state) (b1 : bexp) (c1 c2 : com),
- beval st b1 = false →
- c2 / st \\ st' →
- (IFB b1 THEN c1 ELSE c2 FI) / st \\ st'
- | E_WhileFalse : ∀ (b1 : bexp) (st : state) (c1 : com),
- beval st b1 = false →
- (WHILE b1 DO c1 END) / st \\ st
- | E_WhileTrue : ∀ (st st' st'' : state) (b1 : bexp) (c1 : com),
- beval st b1 = true →
- c1 / st \\ st' →
- (WHILE b1 DO c1 END) / st' \\ st'' →
- (WHILE b1 DO c1 END) / st \\ st''
+ st =[ x ::= a1 ]⇒ (x !-> n ; st)
+ | E_Seq : ∀c1 c2 st st' st'',
+ st =[ c1 ]⇒ st' →
+ st' =[ c2 ]⇒ st'' →
+ st =[ c1 ;; c2 ]⇒ st''
+ | E_IfTrue : ∀st st' b c1 c2,
+ beval st b = true →
+ st =[ c1 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_IfFalse : ∀st st' b c1 c2,
+ beval st b = false →
+ st =[ c2 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_WhileFalse : ∀b st c,
+ beval st b = false →
+ st =[ WHILE b DO c END ]⇒ st
+ | E_WhileTrue : ∀st st' st'' b c,
+ beval st b = true →
+ st =[ c ]⇒ st' →
+ st' =[ WHILE b DO c END ]⇒ st'' →
+ st =[ WHILE b DO c END ]⇒ st''
(* 请在此处解答 *)
- where "c1 '/' st '\\' st'" := (ceval c1 st st').
+ where "st =[ c ]⇒ st'" := (ceval c st st').
+Close Scope imp_scope.
@@ -1900,11 +1898,11 @@-Equiv程序的等价关系
-Example havoc_example1 : (HAVOC X) / { --> 0 } \\ { X --> 0 }.
+Example havoc_example1 : empty_st =[ (HAVOC X)%imp ]⇒ (X !-> 0).
Proof.
(* 请在此处解答 *) Admitted.
Example havoc_example2 :
- (SKIP;; HAVOC Z) / { --> 0 } \\ { Z --> 42 }.
+ empty_st =[ (SKIP;; HAVOC Z)%imp ]⇒ (Z !-> 42).
Proof.
(* 请在此处解答 *) Admitted.
(* 请勿修改下面这一行: *)
@@ -1919,23 +1917,23 @@Equiv程序的等价关系
-Definition cequiv (c1 c2 : com) : Prop := ∀ st st' : state,
- c1 / st \\ st' ↔ c2 / st \\ st'.
+Definition cequiv (c1 c2 : com) : Prop := ∀st st' : state,
+ st =[ c1 ]⇒ st' ↔ st =[ c2 ]⇒ st'.
Definition pXY :=
- HAVOC X;; HAVOC Y.
+ (HAVOC X;; HAVOC Y)%imp.
Definition pYX :=
- HAVOC Y;; HAVOC X.
+ (HAVOC Y;; HAVOC X)%imp.
@@ -1952,15 +1950,15 @@Equiv程序的等价关系
-练习:4 星, optional (havoc_copy)
+练习:4 星, standard, optional (havoc_copy)
以下两个程序是否等价?Definition ptwice :=
- HAVOC X;; HAVOC Y.
+ (HAVOC X;; HAVOC Y)%imp.
Definition pcopy :=
- HAVOC X;; Y ::= X.
+ (HAVOC X;; Y ::= X)%imp.
@@ -1991,14 +1989,14 @@Equiv程序的等价关系 Definition p1 : com :=
- WHILE ! (X = 0) DO
+ (WHILE ¬(X = 0) DO
HAVOC Y;;
X ::= X + 1
- END.
+ END)%imp.
Definition p2 : com :=
- WHILE ! (X = 0) DO
+ (WHILE ¬(X = 0) DO
SKIP
- END.
+ END)%imp.
@@ -2007,11 +2005,11 @@@@ -2058,18 +2056,18 @@Equiv程序的等价关系
-Lemma p1_may_diverge : ∀ st st', st X ≠ 0 →@@ -2040,15 +2038,15 @@
- ¬ p1 / st \\ st'.
+Lemma p1_may_diverge : ∀st st', st X ≠ 0 →
+ ¬st =[ p1 ]⇒ st'.
Proof. (* 请在此处解答 *) Admitted.
-Lemma p2_may_diverge : ∀ st st', st X ≠ 0 →
- ¬ p2 / st \\ st'.
+Lemma p2_may_diverge : ∀st st', st X ≠ 0 →
+ ¬st =[ p2 ]⇒ st'.
Proof.
(* 请在此处解答 *) Admitted.
Equiv程序的等价关系 Definition p3 : com :=
- Z ::= 1;;
- WHILE ! (X = 0) DO
+ (Z ::= 1;;
+ WHILE ~(X = 0) DO
HAVOC X;;
HAVOC Z
- END.
+ END)%imp.
Definition p4 : com :=
- X ::= 0;;
- Z ::= 1.
-Theorem p3_p4_inequiv : ¬ cequiv p3 p4.
+ (X ::= 0;;
+ Z ::= 1)%imp.
+Theorem p3_p4_inequiv : ¬cequiv p3 p4.
Proof. (* 请在此处解答 *) Admitted.
Equiv程序的等价关系
练习:5 星, advanced, optional (p5_p6_equiv)
证明以下指令等价。(提示:正如我们之前提到的,我们为 Himp 定义的 - cequiv 只考虑了可能的停机配置的集合:对于两个程序而言, - 当且仅当给定了相同的起始状态 st,且可能的停机状态的集合相同时,二者才等价。 + cequiv 只考虑了可能的停机配置的集合:对于两个拥有相同起始状态 st + 的程序而言,当且仅当二者可能的停机状态的集合相同时,二者才等价。 若 p5 停机,那么最终状态应当是什么?反过来说,p5 总是会停机吗?)Definition p5 : com :=@@ -2085,7 +2083,7 @@
- WHILE ! (X = 1) DO
+ (WHILE ~(X = 1) DO
HAVOC X
- END.
+ END)%imp.
Definition p6 : com :=
- X ::= 1.
+ (X ::= 1)%imp.
Theorem p5_p6_equiv : cequiv p5 p6.
Proof. (* 请在此处解答 *) Admitted.
Equiv程序的等价关系
练习:4 星, optional (for_while_equiv)
+练习:4 星, standard, optional (for_while_equiv)
此练习是 Imp 一章中可选练习 add_for_loop 的扩展, 就是那个让你扩展出类似 C 风格的 for 循环指令的练习。请证明指令: @@ -2121,12 +2119,12 @@Equiv程序的等价关系
-练习:3 星, optional (swap_noninterfering_assignments)
+练习:3 星, standard, optional (swap_noninterfering_assignments)
(提示:这里你需要 functional_extensionality。)-Theorem swap_noninterfering_assignments: ∀ l1 l2 a1 a2,☐ +
+Theorem swap_noninterfering_assignments: ∀l1 l2 a1 a2,
l1 ≠ l2 →
var_not_used_in_aexp l1 a2 →
var_not_used_in_aexp l2 a1 →
@@ -2149,12 +2147,22 @@Equiv程序的等价关系
-Definition capprox (c1 c2 : com) : Prop := ∀ (st st' : state),
- c1 / st \\ st' → c2 / st \\ st'.
+Definition capprox (c1 c2 : com) : Prop := ∀(st st' : state),
+ st =[ c1 ]⇒ st' → st =[ c2 ]⇒ st'.
-例如,程序 c1 = WHILE !(X = 1) DO X ::= X - 1 END +例如,程序 + +@@ -2187,12 +2197,16 @@+ ++ c1 = WHILE ~(X = 1) DO近似于 c2 = X ::= 1,但是 c2 不近似于 c1,因为 c1 不会在 X = 0 时停机,而 c2 会。如果两个程序互相近似,那么它们等价。
+ X ::= X - 1
+ END ++ +@@ -2163,9 +2171,11 @@Equiv程序的等价关系
-Definition c3 : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted.@@ -2176,7 +2186,7 @@
-Definition c4 : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem c3_c4_different : ¬ capprox c3 c4 ∧ ¬ capprox c4 c3.
+Definition c3 : com
+ (* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
+Definition c4 : com
+ (* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
+Theorem c3_c4_different : ¬capprox c3 c4 ∧ ¬capprox c4 c3.
Proof. (* 请在此处解答 *) Admitted.
Equiv程序的等价关系Definition cmin : com
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem cmin_minimal : ∀ c, capprox cmin c.
+Theorem cmin_minimal : ∀c, capprox cmin c.
Proof. (* 请在此处解答 *) Admitted.
Equiv程序的等价关系Definition zprop (c : com) : Prop
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem zprop_preserving : ∀ c c',
+Theorem zprop_preserving : ∀c c',
zprop c → capprox c c' → zprop c'.
Proof. (* 请在此处解答 *) Admitted.
+ +(* Sat Jan 26 15:15:43 UTC 2019 *)diff --git a/plf-current/Equiv.v b/plf-current/Equiv.v index 48d4c5b6..d329f69b 100644 --- a/plf-current/Equiv.v +++ b/plf-current/Equiv.v @@ -1,16 +1,16 @@ (** * Equiv: 程序的等价关系 *) Set Warnings "-notation-overridden,-parsing". -Require Import Coq.Bool.Bool. -Require Import Coq.Arith.Arith. -Require Import Coq.Init.Nat. -Require Import Coq.Arith.PeanoNat. Import Nat. -Require Import Coq.Arith.EqNat. -Require Import Coq.omega.Omega. -Require Import Coq.Lists.List. -Require Import Coq.Logic.FunctionalExtensionality. -Import ListNotations. From PLF Require Import Maps. +From Coq Require Import Bool.Bool. +From Coq Require Import Arith.Arith. +From Coq Require Import Init.Nat. +From Coq Require Import Arith.PeanoNat. Import Nat. +From Coq Require Import Arith.EqNat. +From Coq Require Import omega.Omega. +From Coq Require Import Lists.List. +From Coq Require Import Logic.FunctionalExtensionality. +Import ListNotations. From PLF Require Import Imp. (** *** 一些关于习题的建议: @@ -48,23 +48,21 @@ From PLF Require Import Imp. 我们就说他们的_'行为等价(behaviorally equivalent)'_。 *) Definition aequiv (a1 a2 : aexp) : Prop := - forall (st:state), + forall (st : state), aeval st a1 = aeval st a2. Definition bequiv (b1 b2 : bexp) : Prop := - forall (st:state), + forall (st : state), beval st b1 = beval st b2. (** 下面是一些算术和布尔表达式等价的简单例子。 *) -Theorem aequiv_example: - aequiv (X - X) 0. +Theorem aequiv_example: aequiv (X - X) 0. Proof. intros st. simpl. omega. Qed. -Theorem bequiv_example: - bequiv (X - X = 0) true. +Theorem bequiv_example: bequiv (X - X = 0)%imp true. Proof. intros st. unfold beval. rewrite aequiv_example. reflexivity. @@ -79,17 +77,17 @@ Qed. Definition cequiv (c1 c2 : com) : Prop := forall (st st' : state), - (c1 / st \\ st') <-> (c2 / st \\ st'). + (st =[ c1 ]=> st') <-> (st =[ c2 ]=> st'). (* ================================================================= *) (** ** 简单示例 *) (** 下面是一些指令等价的例子,我们首先从包含 [SKIP] 的简单程序变换开始: *) -Theorem skip_left: forall c, +Theorem skip_left : forall c, cequiv - (SKIP;; c) - c. + (SKIP;; c) + c. Proof. (* 课上已完成 *) intros c st st'. @@ -104,10 +102,11 @@ Proof. assumption. Qed. -(** **** 练习:2 星 (skip_right) *) -(** 请证明在某条指令之后添加 [SKIP] 后,两程序会等价 *) +(** **** 练习:2 星, standard (skip_right) -Theorem skip_right: forall c, + 请证明在某条指令之后添加 [SKIP] 后,两程序会等价 *) + +Theorem skip_right : forall c, cequiv (c ;; SKIP) c. @@ -115,11 +114,11 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** 同样,下面是一个优化 [IFB] 的简单程序变换: *) +(** 同样,下面是一个优化 [TEST] 的简单程序变换: *) -Theorem IFB_true_simple: forall c1 c2, +Theorem TEST_true_simple : forall c1 c2, cequiv - (IFB BTrue THEN c1 ELSE c2 FI) + (TEST true THEN c1 ELSE c2 FI) c1. Proof. intros c1 c2. @@ -129,44 +128,44 @@ Proof. - (* <- *) apply E_IfTrue. reflexivity. assumption. Qed. -(** 当然,人类程序员是不会写把断言(guard)直接写成 [BTrue] 的条件分支的。 - 有趣的是当断言_'等价于'_真的情况: *) -(** _'定理'_:若 [b] 等价于 [BTrue],则 [IFB b THEN c1 ELSE c2 FI] 等价于 [c1]。 *) -(** +(** 当然,人类程序员是不会写把断言(guard)直接写成 [true] 的条件分支的。 + 不过当断言_'等价于真'_的情况时就会写出来: + + _'定理'_:若 [b] 等价于 [BTrue],则 [TEST b THEN c1 ELSE c2 FI] 等价于 [c1]。 _'证明'_: - - ([->]) 我们必须证明,对于所有的 [st] 和 [st'],若 [IFB b - THEN c1 ELSE c2 FI / st \\ st'] 则 [c1 / st \\ st']。 + - ([->]) 我们必须证明,对于所有的 [st] 和 [st'],若 [st =[ + TEST b THEN c1 ELSE c2 FI ]=> st'] 则 [st =[ c1 ]=> st']。 - 能够应用于 [IFB b THEN c1 ELSE c2 FI / st \\ st'] 的证明规则只有两条: + 能够应用于 [st =[ TEST b THEN c1 ELSE c2 FI ]=> st'] 的证明规则只有两条: [E_IfTrue] 和 [E_IfFalse]。 - - 假设 [IFB b THEN c1 ELSE c2 FI / st \\ st'] 证明自 [E_IfTrue] - 这条证明规则。若使用证明规则 [E_IfTrue] 其必备的前提条件 [c1 / st \\ st'] + - 假设 [st =[ TEST b THEN c1 ELSE c2 FI ]=> st'] 证明自 [E_IfTrue] + 这条证明规则。若使用证明规则 [E_IfTrue] 其必备的前提条件 [st =[ c1 ]=> st'] 必为真,而这正好是我们的证明所需要的条件。 - - 另一方面, 假设 [IFB b THEN c1 ELSE c2 FI / st \\ st'] 证明自 - [E_IfFalse]。我们能得知 [beval st b = false] 和 [c2 / st \\ st']。 + - 另一方面, 假设 [st =[ TEST b THEN c1 ELSE c2 FI ]=> st'] 证明自 + [E_IfFalse]。我们能得知 [beval st b = false] 和 [st =[ c2 ]=> st']。 之前提到 [b] 等价于 [BTrue], 即对于所有 [st],有 [beval st b = beval st BTrue]。具体来说就是 [beval st b = true] 成立,因而 [beval st BTrue = true] 成立。然而,之前假设 [E_IfFalse] 必备的前提条件 [beval st b = false] 也成立,这就构成了一组矛盾,因此不可能使用了 [E_IfFalse] 这条证明规则。 - - ([<-]) 我们必须证明,对于所有 [st] 和 [st'],若 [c1 / st \\ st'] + - ([<-]) 我们必须证明,对于所有 [st] 和 [st'],若[st =[ c1 ]=> st'] 则 [IFB b THEN c1 ELSE c2 FI / st \\ st']。 已知 [b] 等价于 [BTrue],我们知道 [beval st b] = [beval st BTrue] = [true]。 - 结合 [c1 / st \\ st'] 这条假设,我们能应用 [E_IfTrue] 来证明出 [IFB b THEN - c1 ELSE c2 FI / st \\ st']。 [] + 结合 [st =[ c1 ]=> st'] 这条假设,我们能应用 [E_IfTrue] 来证明 + [st =[ TEST b THEN c1 ELSE c2 FI ]=> st']。 [] 下面是这个证明的形式化版本: *) -Theorem IFB_true: forall b c1 c2, - bequiv b BTrue -> - cequiv - (IFB b THEN c1 ELSE c2 FI) - c1. +Theorem TEST_true: forall b c1 c2, + bequiv b BTrue -> + cequiv + (TEST b THEN c1 ELSE c2 FI) + c1. Proof. intros b c1 c2 Hb. split; intros H. @@ -183,23 +182,24 @@ Proof. unfold bequiv in Hb. simpl in Hb. rewrite Hb. reflexivity. Qed. -(** **** 练习:2 星, recommended (IFB_false) *) -Theorem IFB_false: forall b c1 c2, - bequiv b BFalse -> +(** **** 练习:2 星, standard, recommended (TEST_false) *) +Theorem TEST_false : forall b c1 c2, + bequiv b BFalse -> cequiv - (IFB b THEN c1 ELSE c2 FI) + (TEST b THEN c1 ELSE c2 FI) c2. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (swap_if_branches) *) -(** 证明我们可以通过对断言取反来交换 IF 的两个分支 *) +(** **** 练习:3 星, standard (swap_if_branches) + + 证明我们可以通过对断言取反来交换 IF 的两个分支 *) -Theorem swap_if_branches: forall b e1 e2, +Theorem swap_if_branches : forall b e1 e2, cequiv - (IFB b THEN e1 ELSE e2 FI) - (IFB BNot b THEN e2 ELSE e1 FI). + (TEST b THEN e1 ELSE e2 FI) + (TEST BNot b THEN e2 ELSE e1 FI). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -227,40 +227,45 @@ Proof. rewrite Hb. reflexivity. Qed. -(** **** 练习:2 星, advanced, optional (WHILE_false_informal) *) -(** 写出 [WHILE_false] 的非形式化证明。 +(** **** 练习:2 星, advanced, optional (WHILE_false_informal) + + 写出 [WHILE_false] 的非形式化证明。 (* 请在此处解答 *) -*) -(** [] *) + + [] *) (** 为了证明第二个定理,我们需要一个辅助引理:[WHILE] 循环在其断言等价于 [BTrue] 时不会停机。 *) -(** _'引理'_:若 [b] 等价于 [BTrue],则无法出现 [(WHILE b DO c END) / - st \\ st'] 的情况。 +(** _'引理'_:若 [b] 等价于 [BTrue],则无法出现 + [st =[ WHILE b DO c END ]=> st'] 的情况。 - _'证明'_:假设 [(WHILE b DO c END) / st \\ st']。我们将证明通过对 - [(WHILE b DO c END) / st \\ st'] 使用归纳法会导出矛盾。 + _'证明'_:假设 [st =[ WHILE b DO c END ]=> st']。我们将证明通过对 + [st =[ WHILE b DO c END ]=> st'] 使用归纳法会导出矛盾。需要考虑只有 + [E_WhileFalse] 和 [E_WhileTrue] 两种情况,其它情况则矛盾。 - - 假设 [(WHILE b DO c END) / st \\ st'] 使用规则 [E_WhileFalse] 证明。 + - 假设 [st =[ WHILE b DO c END ]=> st'] 使用规则 [E_WhileFalse] 证明。 那么根据假设得出 [beval st b = false]。但它与 [b] 等价于 [BTrue] 矛盾。 - - 假设 [(WHILE b DO c END) / st \\ st'] 使用规则 [E_WhileTrue]证明。 - 那么我们就给出了一个和 [(WHILE b DO c END) / st \\ st'] 矛盾的假设, - 它刚好就是我们要证明的那个! + - 假设 [st =[ WHILE b DO c END ]=> st'] 使用规则 [E_WhileTrue]证明。 + 我们必有: + + 1. [beval st b = true], + 2. 存在某个 [st0] 使得 [st =[ c ]=> st0] 且 + [st0 =[ WHILE b DO c END ]=> st'], + 3. 以及我们给出了导致矛盾的归纳假设 [st0 =[ WHILE b DO c END ]=> st'], - - 由于只有以上几条规则可用于证明 [(WHILE b DO c END) / st \\ st'], - 因此归纳时的其它情况可直接得出矛盾。 [] *) + 我们根据 2 和 3 会得到矛盾。 [] *) Lemma WHILE_true_nonterm : forall b c st st', bequiv b BTrue -> - ~( (WHILE b DO c END) / st \\ st' ). + ~( st =[ WHILE b DO c END ]=> st' ). Proof. (* 课上已完成 *) intros b c st st' Hb. intros H. - remember (WHILE b DO c END) as cw eqn:Heqcw. + remember (WHILE b DO c END)%imp as cw eqn:Heqcw. induction H; (* 大多数证明规则无法应用,我们可通过反演(inversion)来去除它们: *) inversion Heqcw; subst; clear Heqcw. @@ -272,17 +277,19 @@ Proof. - (* E_WhileTrue *) (* 直接使用 IH *) apply IHceval2. reflexivity. Qed. -(** **** 练习:2 星, optional (WHILE_true_nonterm_informal) *) -(** 试解释 [WHILE_true_nonterm] 的含义。 +(** **** 练习:2 星, standard, optional (WHILE_true_nonterm_informal) + + 试解释 [WHILE_true_nonterm] 的含义。 (* 请在此处解答 *) -*) -(** [] *) -(** **** 练习:2 星, recommended (WHILE_true) *) -(** 请证明以下定理。_'提示'_:你可能需要使用 [WHILE_true_nonterm] 。 *) + [] *) + +(** **** 练习:2 星, standard, recommended (WHILE_true) -Theorem WHILE_true: forall b c, + 请证明以下定理。_'提示'_:你可能需要使用 [WHILE_true_nonterm] 。 *) + +Theorem WHILE_true : forall b c, bequiv b true -> cequiv (WHILE b DO c END) @@ -294,10 +301,10 @@ Proof. (** 关于 [WHILE] 指令的更有趣的事实是,任何数量的循环体的副本在不改变意义 的情况下均可被“展开”。循环展开在实际的编译器中是种常见的变换。 *) -Theorem loop_unrolling: forall b c, +Theorem loop_unrolling : forall b c, cequiv (WHILE b DO c END) - (IFB b THEN (c ;; WHILE b DO c END) ELSE SKIP FI). + (TEST b THEN (c ;; WHILE b DO c END) ELSE SKIP FI). Proof. (* 课上已完成 *) intros b c st st'. @@ -318,43 +325,42 @@ Proof. + (* 不执行循环 *) inversion H5; subst. apply E_WhileFalse. assumption. Qed. -(** **** 练习:2 星, optional (seq_assoc) *) +(** **** 练习:2 星, standard, optional (seq_assoc) *) Theorem seq_assoc : forall c1 c2 c3, cequiv ((c1;;c2);;c3) (c1;;(c2;;c3)). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** 证明涉及赋值的程序属性经常会用到函数的外延公理。 *) +(** 证明涉及赋值的程序的属性经常会用到这一事实,即程序状态会根据其外延性 + (如 [x !-> m x ; m] 和 [m] 是相等的映射)来对待。 *) -Theorem identity_assignment : forall (X:string), +Theorem identity_assignment : forall x, cequiv - (X ::= X) + (x ::= x) SKIP. Proof. - intros. split; intro H. - - (* -> *) - inversion H; subst. simpl. - replace (st & { X --> st X }) with st. - + constructor. - + apply functional_extensionality. intro. - rewrite t_update_same; reflexivity. - - (* <- *) - replace st' with (st' & { X --> aeval st' X }). - + inversion H. subst. apply E_Ass. reflexivity. - + apply functional_extensionality. intro. - rewrite t_update_same. reflexivity. + intros. + split; intro H; inversion H; subst. + - (* -> *) + rewrite t_update_same. + apply E_Skip. + - (* <- *) + assert (Hx : st' =[ x ::= x ]=> (x !-> st' x ; st')). + { apply E_Ass. reflexivity. } + rewrite t_update_same in Hx. + apply Hx. Qed. -(** **** 练习:2 星, recommended (assign_aequiv) *) -Theorem assign_aequiv : forall (X:string) e, - aequiv X e -> - cequiv SKIP (X ::= e). +(** **** 练习:2 星, standard, recommended (assign_aequiv) *) +Theorem assign_aequiv : forall (x : string) e, + aequiv x e -> + cequiv SKIP (x ::= e). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星 (equiv_classes) *) +(** **** 练习:2 星, standard (equiv_classes) *) (** 给定下列程序,请按照它们在 [Imp] 中是否等价将这些程序分组。 你的答案应该是一个列表的列表,其中每个子列表都表示一组等价的程序。 @@ -366,51 +372,51 @@ Proof. 请在 [equiv_classes] 的定义下方写出你的答案。 *) Definition prog_a : com := - WHILE ! (X <= 0) DO + (WHILE ~(X <= 0) DO X ::= X + 1 - END. + END)%imp. Definition prog_b : com := - IFB X = 0 THEN + (TEST X = 0 THEN X ::= X + 1;; Y ::= 1 ELSE Y ::= 0 FI;; X ::= X - Y;; - Y ::= 0. + Y ::= 0)%imp. Definition prog_c : com := - SKIP. + SKIP%imp. Definition prog_d : com := - WHILE ! (X = 0) DO + (WHILE ~(X = 0) DO X ::= (X * Y) + 1 - END. + END)%imp. Definition prog_e : com := - Y ::= 0. + (Y ::= 0)%imp. Definition prog_f : com := - Y ::= X + 1;; - WHILE ! (X = Y) DO + (Y ::= X + 1;; + WHILE ~(X = Y) DO Y ::= X + 1 - END. + END)%imp. Definition prog_g : com := - WHILE true DO + (WHILE true DO SKIP - END. + END)%imp. Definition prog_h : com := - WHILE ! (X = X) DO + (WHILE ~(X = X) DO X ::= X + 1 - END. + END)%imp. Definition prog_i : com := - WHILE ! (X = Y) DO + (WHILE ~(X = Y) DO X ::= Y + 1 - END. + END)%imp. Definition equiv_classes : list (list com) (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. @@ -469,7 +475,7 @@ Lemma sym_cequiv : forall (c1 c2 : com), cequiv c1 c2 -> cequiv c2 c1. Proof. unfold cequiv. intros c1 c2 H st st'. - assert (c1 / st \\ st' <-> c2 / st \\ st') as H'. + assert (st =[ c1 ]=> st' <-> st =[ c2 ]=> st') as H'. { (* Proof of assertion *) apply H. } apply iff_sym. assumption. Qed. @@ -487,7 +493,7 @@ Lemma trans_cequiv : forall (c1 c2 c3 : com), cequiv c1 c2 -> cequiv c2 c3 -> cequiv c1 c3. Proof. unfold cequiv. intros c1 c2 c3 H12 H23 st st'. - apply iff_trans with (c2 / st \\ st'). apply H12. apply H23. Qed. + apply iff_trans with (st =[ c2 ]=> st'). apply H12. apply H23. Qed. (* ================================================================= *) (** ** 行为等价是一种一致性 *) @@ -498,11 +504,11 @@ Proof. aequiv a1 a1' ----------------------------- - cequiv (i ::= a1) (i ::= a1') + cequiv (x ::= a1) (x ::= a1') cequiv c1 c1' cequiv c2 c2' - ------------------------ + -------------------------- cequiv (c1;;c2) (c1';;c2') ...以及这些指令的更多其它形式。 *) @@ -516,11 +522,11 @@ Proof. _'无需'_进行与不变的部分相关的证明。也就是说,程序的改变所产生的证明的工作量 与改变的大小而非整个程序的大小成比例。 *) -Theorem CAss_congruence : forall i a1 a1', +Theorem CAss_congruence : forall x a1 a1', aequiv a1 a1' -> - cequiv (CAss i a1) (CAss i a1'). + cequiv (CAss x a1) (CAss x a1'). Proof. - intros i a1 a2 Heqv st st'. + intros x a1 a2 Heqv st st'. split; intros Hceval. - (* -> *) inversion Hceval. subst. apply E_Ass. @@ -535,26 +541,26 @@ Proof. 等价于 [c1'],那么 [WHILE b1 DO c1 END] 等价于 [WHILE b1' DO c1' END]。 _'证明'_: 假设 [b1] 等价于 [b1'] 且 [c1] 等价于 [c1']。我们必须证明, - 对于每个 [st] 和 [st'],[WHILE b1 DO c1 END / st \\ st'] 当且仅当 - [WHILE b1' DO c1' END / st \\ st']。我们把两个方向分开考虑。 + 对于每个 [st] 和 [st'],[st =[ WHILE b1 DO c1 END ]=> st'] 当且仅当 + [st =[ WHILE b1' DO c1' END ]=> st']。我们把两个方向分开考虑。 - - ([->]) 我们通过对 [WHILE b1 DO c1 END / st \\ st'] 使用归纳法证明 - [WHILE b1 DO c1 END / st \\ st'] 蕴含 [WHILE b1' DO c1' END / st \\ st']。 + - ([->]) 我们通过对 [st =[ WHILE b1 DO c1 END ]=> st'] 使用归纳法证明 + [st =[ WHILE b1 DO c1 END ]=> st'] 蕴含 [st =[ WHILE b1' DO c1' END ]=> st']。 只有推导的最后所使用的规则为 [E_WhileFalse] 或 [E_WhileTrue] 时才需要进行特别讨论。 - [E_WhileFalse]:此时我们拥有假设的必备条件 [beval st b1 = false] 和 [st = st']。但是,由于 [b1] 和 [b1'] 等价,我们有 [beval st b1' = false],然后应用 [E-WhileFalse] 得出我们需要的 - [WHILE b1' DO c1' END / st \\ st']。 + [st =[ WHILE b1' DO c1' END ]=> st']。 - [E_WhileTrue]:此时我们拥有假设的必备条件 [beval st b1 = true],以及 - 对于某些状态 [st'0] 的 [c1 / st \\ st'0] 和 [WHILE b1 DO c1 END / st'0 - \\ st'],还有归纳假设 [WHILE b1' DO c1' END / st'0 \\ st']。 + 对于某些状态 [st'0] 的 [st =[ c1 ]=> st'0] 和 [st'0 =[ WHILE b1 DO c1 + END ]=> st'],还有归纳假设 [st'0 =[ WHILE b1' DO c1' END ]=> st']。 - 由于 [c1] 和 [c1'] 等价,我们有 [c1' / st \\ st'0]; + 由于 [c1] 和 [c1'] 等价,我们有 [st =[ c1' ]=> st'0]; 由于 [b1] 和 [b1'] 等价,我们有 [beval st b1' = true]。现在应用 - [E-WhileTrue],得出我们所需的 [WHILE b1' DO c1' END / st \\ st']。 + [E-WhileTrue],得出我们所需的 [st =[ WHILE b1' DO c1' END ]=> st']。 - ([<-]) 反之亦然。 [] *) @@ -567,7 +573,7 @@ Proof. intros b1 b1' c1 c1' Hb1e Hc1e st st'. split; intros Hce. - (* -> *) - remember (WHILE b1 DO c1 END) as cwhile + remember (WHILE b1 DO c1 END)%imp as cwhile eqn:Heqcwhile. induction Hce; inversion Heqcwhile; subst. + (* E_WhileFalse *) @@ -580,7 +586,7 @@ Proof. * (* 执行之后的循环 *) apply IHHce2. reflexivity. - (* <- *) - remember (WHILE b1' DO c1' END) as c'while + remember (WHILE b1' DO c1' END)%imp as c'while eqn:Heqc'while. induction Hce; inversion Heqc'while; subst. + (* E_WhileFalse *) @@ -593,7 +599,7 @@ Proof. * (* 执行之后的循环 *) apply IHHce2. reflexivity. Qed. -(** **** 练习:3 星, optional (CSeq_congruence) *) +(** **** 练习:3 星, standard, optional (CSeq_congruence) *) Theorem CSeq_congruence : forall c1 c1' c2 c2', cequiv c1 c1' -> cequiv c2 c2' -> cequiv (c1;;c2) (c1';;c2'). @@ -601,11 +607,11 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (CIf_congruence) *) +(** **** 练习:3 星, standard (CIf_congruence) *) Theorem CIf_congruence : forall b b' c1 c1' c2 c2', bequiv b b' -> cequiv c1 c1' -> cequiv c2 c2' -> - cequiv (IFB b THEN c1 ELSE c2 FI) - (IFB b' THEN c1' ELSE c2' FI). + cequiv (TEST b THEN c1 ELSE c2 FI) + (TEST b' THEN c1' ELSE c2' FI). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -616,7 +622,7 @@ Example congruence_example: cequiv (* 程序 1: *) (X ::= 0;; - IFB X = 0 + TEST X = 0 THEN Y ::= 0 ELSE @@ -624,7 +630,7 @@ Example congruence_example: FI) (* 程序 1: *) (X ::= 0;; - IFB X = 0 + TEST X = 0 THEN Y ::= X - X (* <--- 这里不同 *) ELSE @@ -632,20 +638,22 @@ Example congruence_example: FI). Proof. apply CSeq_congruence. - apply refl_cequiv. - apply CIf_congruence. - apply refl_bequiv. - apply CAss_congruence. unfold aequiv. simpl. - symmetry. apply minus_diag. - apply refl_cequiv. + - apply refl_cequiv. + - apply CIf_congruence. + + apply refl_bequiv. + + apply CAss_congruence. unfold aequiv. simpl. + * symmetry. apply minus_diag. + + apply refl_cequiv. Qed. -(** **** 练习:3 星, advanced, optional (not_congr) *) -(** 我们已经证明了 [cequiv] 关系对指令同时满足等价关系和一致性。 +(** **** 练习:3 星, advanced, optional (not_congr) + + 我们已经证明了 [cequiv] 关系对指令同时满足等价关系和一致性。 你能想出一个对于指令满足等价关系但_'不满足'_一致性的关系吗? *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * 程序变换 *) @@ -678,33 +686,33 @@ Definition ctrans_sound (ctrans : com -> com) : Prop := Fixpoint fold_constants_aexp (a : aexp) : aexp := match a with | ANum n => ANum n - | AId i => AId i + | AId x => AId x | APlus a1 a2 => - match (fold_constants_aexp a1, fold_constants_aexp a2) + match (fold_constants_aexp a1, + fold_constants_aexp a2) with | (ANum n1, ANum n2) => ANum (n1 + n2) | (a1', a2') => APlus a1' a2' end | AMinus a1 a2 => - match (fold_constants_aexp a1, fold_constants_aexp a2) + match (fold_constants_aexp a1, + fold_constants_aexp a2) with | (ANum n1, ANum n2) => ANum (n1 - n2) | (a1', a2') => AMinus a1' a2' end | AMult a1 a2 => - match (fold_constants_aexp a1, fold_constants_aexp a2) + match (fold_constants_aexp a1, + fold_constants_aexp a2) with | (ANum n1, ANum n2) => ANum (n1 * n2) | (a1', a2') => AMult a1' a2' end end. -(* 解析下面的示例时要用 *) -Local Open Scope aexp_scope. -Local Open Scope bexp_scope. - Example fold_aexp_ex1 : - fold_constants_aexp ((1 + 2) * X) = (3 * X). + fold_constants_aexp ((1 + 2) * X) + = (3 * X)%imp. Proof. reflexivity. Qed. (** 注意此版本的常量折叠不包括优化平凡的加法等 -- 为简单起见, @@ -712,7 +720,7 @@ Proof. reflexivity. Qed. 只是定义和证明会更长。 *) Example fold_aexp_ex2 : - fold_constants_aexp (X - ((0 * 6) + Y)) = (X - (0 + Y)). + fold_constants_aexp (X - ((0 * 6) + Y))%imp = (X - (0 + Y))%imp. Proof. reflexivity. Qed. (** 我们不仅可以将 [fold_constants_aexp] 优化成 [bexp](如在 [BEq] 和 [BLe] @@ -723,14 +731,16 @@ Fixpoint fold_constants_bexp (b : bexp) : bexp := | BTrue => BTrue | BFalse => BFalse | BEq a1 a2 => - match (fold_constants_aexp a1, fold_constants_aexp a2) with + match (fold_constants_aexp a1, + fold_constants_aexp a2) with | (ANum n1, ANum n2) => if n1 =? n2 then BTrue else BFalse | (a1', a2') => BEq a1' a2' end | BLe a1 a2 => - match (fold_constants_aexp a1, fold_constants_aexp a2) with + match (fold_constants_aexp a1, + fold_constants_aexp a2) with | (ANum n1, ANum n2) => if n1 <=? n2 then BTrue else BFalse | (a1', a2') => @@ -743,7 +753,8 @@ Fixpoint fold_constants_bexp (b : bexp) : bexp := | b1' => BNot b1' end | BAnd b1 b2 => - match (fold_constants_bexp b1, fold_constants_bexp b2) with + match (fold_constants_bexp b1, + fold_constants_bexp b2) with | (BTrue, BTrue) => BTrue | (BTrue, BFalse) => BFalse | (BFalse, BTrue) => BFalse @@ -753,29 +764,31 @@ Fixpoint fold_constants_bexp (b : bexp) : bexp := end. Example fold_bexp_ex1 : - fold_constants_bexp (true && ! (false && true)) = true. + fold_constants_bexp (true && ~(false && true))%imp + = true. Proof. reflexivity. Qed. Example fold_bexp_ex2 : - fold_constants_bexp ((X = Y) && (0 = (2 - (1 + 1)))) = - ((X = Y) && true). + fold_constants_bexp ((X = Y) && (0 = (2 - (1 + 1))))%imp + = ((X = Y) && true)%imp. Proof. reflexivity. Qed. (** 为了折叠指令中的常量,我们需要对所有内嵌的表达式应用适当的折叠函数。 *) +Open Scope imp. Fixpoint fold_constants_com (c : com) : com := match c with | SKIP => SKIP - | i ::= a => - CAss i (fold_constants_aexp a) + | x ::= a => + x ::= (fold_constants_aexp a) | c1 ;; c2 => (fold_constants_com c1) ;; (fold_constants_com c2) - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => match fold_constants_bexp b with - | BTrue => fold_constants_com c1 + | BTrue => fold_constants_com c1 | BFalse => fold_constants_com c2 - | b' => IFB b' THEN fold_constants_com c1 + | b' => TEST b' THEN fold_constants_com c1 ELSE fold_constants_com c2 FI end | WHILE b DO c END => @@ -785,38 +798,29 @@ Fixpoint fold_constants_com (c : com) : com := | b' => WHILE b' DO (fold_constants_com c) END end end. +Close Scope imp. Example fold_com_ex1 : fold_constants_com (* 原程序: *) (X ::= 4 + 5;; Y ::= X - 3;; - IFB (X - Y) = (2 + 4) THEN - SKIP - ELSE - Y ::= 0 - FI;; - IFB 0 <= (4 - (2 + 1)) - THEN - Y ::= 0 - ELSE - SKIP - FI;; + TEST (X - Y) = (2 + 4) THEN SKIP + ELSE Y ::= 0 FI;; + TEST 0 <= (4 - (2 + 1)) THEN Y ::= 0 + ELSE SKIP FI;; WHILE Y = 0 DO X ::= X + 1 - END) + END)%imp = (* 常量折叠后: *) (X ::= 9;; Y ::= X - 3;; - IFB (X - Y) = 6 THEN - SKIP - ELSE - Y ::= 0 - FI;; + TEST (X - Y) = 6 THEN SKIP + ELSE Y ::= 0 FI;; Y ::= 0;; WHILE Y = 0 DO X ::= X + 1 - END). + END)%imp. Proof. reflexivity. Qed. (* ================================================================= *) @@ -842,15 +846,16 @@ Proof. destruct (fold_constants_aexp a2); rewrite IHa1; rewrite IHa2; reflexivity). Qed. -(** **** 练习:3 星, optional (fold_bexp_Eq_informal) *) -(** 下面是布尔表达式常量折叠中 [BEq] 情况的可靠性的证明。 +(** **** 练习:3 星, standard, optional (fold_bexp_Eq_informal) + + 下面是布尔表达式常量折叠中 [BEq] 情况的可靠性的证明。 请认真读完它再和之后的形式化证明作比较,然后补充完 [BLe] 情况的形式化证明 (尽量不看之前 [BEq] 情况的证明)。 _'定理'_:布尔值的常量折叠函数 [fold_constants_bexp] 是可靠的。 _'证明'_:我们必须证明对于所有的布尔表达式 [b],[b] 都等价于 - [fold_constants_bexp]。我们对 [b] 使用归纳法。这里只给出了 [b] + [fold_constants_bexp b]。我们对 [b] 使用归纳法。这里只给出了 [b] 形如 [BEq a1 a2] 的情况。 在本情况中,我们必须证明 @@ -926,8 +931,7 @@ Proof. aeval st a1 = aeval st (fold_constants_aexp a1) aeval st a2 = aeval st (fold_constants_aexp a2), - 本例证毕。 [] -*) + 本例证毕。 [] *) Theorem fold_constants_bexp_sound: btrans_sound fold_constants_bexp. @@ -968,8 +972,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (fold_constants_com_sound) *) -(** 完成以下证明的 [WHILE] 情况。 *) +(** **** 练习:3 星, standard (fold_constants_com_sound) + + 完成以下证明的 [WHILE] 情况。 *) Theorem fold_constants_com_sound : ctrans_sound fold_constants_com. @@ -980,7 +985,7 @@ Proof. - (* ::= *) apply CAss_congruence. apply fold_constants_aexp_sound. - (* ;; *) apply CSeq_congruence; assumption. - - (* IFB *) + - (* TEST *) assert (bequiv b (fold_constants_bexp b)). { apply fold_constants_bexp_sound. } destruct (fold_constants_bexp b) eqn:Heqb; @@ -989,10 +994,10 @@ Proof. [fold_constants_bexp_sound] 来得出证明。) *) + (* b 总为真 *) apply trans_cequiv with c1; try assumption. - apply IFB_true; assumption. + apply TEST_true; assumption. + (* b 总为假 *) apply trans_cequiv with c2; try assumption. - apply IFB_false; assumption. + apply TEST_false; assumption. - (* WHILE *) (* 请在此处解答 *) Admitted. (** [] *) @@ -1000,8 +1005,9 @@ Proof. (* ----------------------------------------------------------------- *) (** *** 再论 (0 + n) 优化的可靠性 *) -(** **** 练习:4 星, advanced, optional (optimize_0plus) *) -(** 回顾_'逻辑基础'_ [Imp] 一章中 [optimize_0plus] 的定义: +(** **** 练习:4 星, advanced, optional (optimize_0plus) + + 回顾_'逻辑基础'_ [Imp] 一章中 [optimize_0plus] 的定义: Fixpoint optimize_0plus (e:aexp) : aexp := match e with @@ -1035,8 +1041,9 @@ Proof. - 证明此优化程序有可靠性。(这部分应该会_'很简单'_ 。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * 证明程序不等价 *) @@ -1056,57 +1063,56 @@ Proof. (** 我们马上就会发现这是不行的。不过且慢,现在, 看你自己能否找出一个反例来。 *) -(** 以下形式化的定义描述了如何在算术表达式中, - 将某个变量的所有引用都替换成另一个表达式: *) +(** 以下形式化的定义描述了如何在算术表达式 [a] 中, + 将某个变量 [x] 的所有引用都替换成另一个表达式 [u] : *) -Fixpoint subst_aexp (i : string) (u : aexp) (a : aexp) : aexp := +Fixpoint subst_aexp (x : string) (u : aexp) (a : aexp) : aexp := match a with | ANum n => ANum n - | AId i' => - if eqb_string i i' then u else AId i' + | AId x' => + if eqb_string x x' then u else AId x' | APlus a1 a2 => - APlus (subst_aexp i u a1) (subst_aexp i u a2) + APlus (subst_aexp x u a1) (subst_aexp x u a2) | AMinus a1 a2 => - AMinus (subst_aexp i u a1) (subst_aexp i u a2) + AMinus (subst_aexp x u a1) (subst_aexp x u a2) | AMult a1 a2 => - AMult (subst_aexp i u a1) (subst_aexp i u a2) + AMult (subst_aexp x u a1) (subst_aexp x u a2) end. Example subst_aexp_ex : - subst_aexp X (42 + 53) (Y + X) - = (Y + (42 + 53)). + subst_aexp X (42 + 53) (Y + X)%imp + = (Y + (42 + 53))%imp. Proof. reflexivity. Qed. (** 而这里是一个我们感兴趣的性质:它断言类似上述形式的 [c1] 和 [c2] 总是等价的。 *) -Definition subst_equiv_property := forall i1 i2 a1 a2, - cequiv (i1 ::= a1;; i2 ::= a2) - (i1 ::= a1;; i2 ::= subst_aexp i1 a1 a2). +Definition subst_equiv_property := forall x1 x2 a1 a2, + cequiv (x1 ::= a1;; x2 ::= a2) + (x1 ::= a1;; x2 ::= subst_aexp x1 a1 a2). (** 遗憾的是, 这个性质_'并不'_总是成立 -- 即,它并不是对所有的 - [i1]、[i2]、[a1] 和 [a2] 都成立。 + [x1]、[x2]、[a1] 和 [a2] 都成立。 - cequiv (i1 ::= a1;; i2 ::= a2) - (i1 ::= a1;; i2 ::= subst_aexp i1 a1 a2). + cequiv (x1 ::= a1;; x2 ::= a2) + (x1 ::= a1;; x2 ::= subst_aexp x1 a1 a2). - 我们使用反证法来证明这一点。假设对于所有的 [i1]、[i2]、[a1] + 我们使用反证法来证明这一点。假设对于所有的 [x1]、[x2]、[a1] 和 [a2],我们有 - cequiv (i1 ::= a1;; i2 ::= a2) - (i1 ::= a1;; i2 ::= subst_aexp i1 a1 a2). + cequiv (x1 ::= a1;; x2 ::= a2) + (x1 ::= a1;; x2 ::= subst_aexp x1 a1 a2). 考虑以下程序: - X ::= X + 1;; Y ::= X + X ::= X + 1;; Y ::= X 注意 - (X ::= X + 1;; Y ::= X) - / { --> 0 } \\ st1, + empty_st =[ X ::= X + 1;; Y ::= X ]=> st1, - 其中 [st1 = { X --> 1; Y --> 1 }]。 + 其中 [st1 = (Y !-> 1 ; X !-> 1)]. 根据假设,我们知道 @@ -1117,17 +1123,14 @@ Definition subst_equiv_property := forall i1 i2 a1 a2, 同时,根据 [cequiv] 的定义,我们有 - (X ::= X + 1;; Y ::= X + 1 - / { --> 0 } \\ st1. + empty_st =[ X ::= X + 1;; Y ::= X + 1 ]=> st1. 但是我们也能推导出 - (X ::= X + 1;; Y ::= X + 1) - / { --> 0 } \\ st2, - - 其中 [st2 = { X --> 1; Y --> 2 }]。但由于 [ceval] 是确定性的,而 - [st1 <> st2] ,这就造成了矛盾! [] *) + empty_st =[ X ::= X + 1;; Y ::= X + 1 ]=> st2, + 其中 [st2 = (Y !-> 2 ; X !-> 1)]。但由于 [ceval] 是确定性的,而 + [st1 <> st2] ,这就造成了矛盾! [] *) Theorem subst_inequiv : ~ subst_equiv_property. @@ -1138,65 +1141,68 @@ Proof. (* 这里有个反例:假设 [subst_equiv_property] 成立能够让我们证明以下两个程序等价... *) remember (X ::= X + 1;; - Y ::= X) + Y ::= X)%imp as c1. remember (X ::= X + 1;; - Y ::= X + 1) + Y ::= X + 1)%imp as c2. assert (cequiv c1 c2) by (subst; apply Contra). - (* ...让我们证明 [c2] 能够在两个不同的状态下停机: - st1 = {X --> 1; Y --> 1} - st2 = {X --> 1; Y --> 2}. *) - remember {X --> 1 ; Y --> 1} as st1. - remember {X --> 1 ; Y --> 2} as st2. - assert (H1: c1 / { --> 0 } \\ st1); - assert (H2: c2 / { --> 0 } \\ st2); + (* ...我们来证明 [c2] 能够在两个不同的状态下停机: + st1 = (Y !-> 1 ; X !-> 1) + st2 = (Y !-> 2 ; X !-> 1). *) + remember (Y !-> 1 ; X !-> 1) as st1. + remember (Y !-> 2 ; X !-> 1) as st2. + assert (H1 : empty_st =[ c1 ]=> st1); + assert (H2 : empty_st =[ c2 ]=> st2); try (subst; - apply E_Seq with (st' := {X --> 1}); + apply E_Seq with (st' := (X !-> 1)); apply E_Ass; reflexivity). apply H in H1. (* 最后,因为程序求值的确定性而产生矛盾。 *) - assert (Hcontra: st1 = st2) - by (apply (ceval_deterministic c2 { --> 0 }); assumption). - assert (Hcontra': st1 Y = st2 Y) + assert (Hcontra : st1 = st2) + by (apply (ceval_deterministic c2 empty_st); assumption). + assert (Hcontra' : st1 Y = st2 Y) by (rewrite Hcontra; reflexivity). subst. inversion Hcontra'. Qed. -(** **** 练习:4 星, optional (better_subst_equiv) *) -(** 之前我们思考的等价关系也不全是妄言 -- 只要再增加一个条件, +(** **** 练习:4 星, standard, optional (better_subst_equiv) + + 之前我们思考的等价关系也不全是妄言 -- 只要再增加一个条件, 即变量 [X] 不在第一个赋值语句的右边出现,它就是正确的了。 *) -Inductive var_not_used_in_aexp (X:string) : aexp -> Prop := - | VNUNum: forall n, var_not_used_in_aexp X (ANum n) - | VNUId: forall Y, X <> Y -> var_not_used_in_aexp X (AId Y) - | VNUPlus: forall a1 a2, - var_not_used_in_aexp X a1 -> - var_not_used_in_aexp X a2 -> - var_not_used_in_aexp X (APlus a1 a2) - | VNUMinus: forall a1 a2, - var_not_used_in_aexp X a1 -> - var_not_used_in_aexp X a2 -> - var_not_used_in_aexp X (AMinus a1 a2) - | VNUMult: forall a1 a2, - var_not_used_in_aexp X a1 -> - var_not_used_in_aexp X a2 -> - var_not_used_in_aexp X (AMult a1 a2). - -Lemma aeval_weakening : forall i st a ni, - var_not_used_in_aexp i a -> - aeval (st & { i --> ni }) a = aeval st a. +Inductive var_not_used_in_aexp (x : string) : aexp -> Prop := + | VNUNum : forall n, var_not_used_in_aexp x (ANum n) + | VNUId : forall y, x <> y -> var_not_used_in_aexp x (AId y) + | VNUPlus : forall a1 a2, + var_not_used_in_aexp x a1 -> + var_not_used_in_aexp x a2 -> + var_not_used_in_aexp x (APlus a1 a2) + | VNUMinus : forall a1 a2, + var_not_used_in_aexp x a1 -> + var_not_used_in_aexp x a2 -> + var_not_used_in_aexp x (AMinus a1 a2) + | VNUMult : forall a1 a2, + var_not_used_in_aexp x a1 -> + var_not_used_in_aexp x a2 -> + var_not_used_in_aexp x (AMult a1 a2). + +Lemma aeval_weakening : forall x st a ni, + var_not_used_in_aexp x a -> + aeval (x !-> ni ; st) a = aeval st a. Proof. (* 请在此处解答 *) Admitted. (** 使用 [var_not_used_in_aexp],形式化并证明正确版本的 [subst_equiv_property]。 *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) -(** **** 练习:3 星 (inequiv_exercise) *) -(** 证明无限循环不等价于 [SKIP] *) +(** **** 练习:3 星, standard (inequiv_exercise) + + 证明无限循环不等价于 [SKIP] *) Theorem inequiv_exercise: ~ cequiv (WHILE true DO SKIP END) SKIP. @@ -1247,65 +1253,69 @@ Inductive com : Type := | CSeq : com -> com -> com | CIf : bexp -> com -> com -> com | CWhile : bexp -> com -> com - | CHavoc : string -> com. (* <---- 新增的 *) + | CHavoc : string -> com. (* <--- 新增 *) Notation "'SKIP'" := - CSkip. + CSkip : imp_scope. Notation "X '::=' a" := - (CAss X a) (at level 60). + (CAss X a) (at level 60) : imp_scope. Notation "c1 ;; c2" := - (CSeq c1 c2) (at level 80, right associativity). + (CSeq c1 c2) (at level 80, right associativity) : imp_scope. Notation "'WHILE' b 'DO' c 'END'" := - (CWhile b c) (at level 80, right associativity). -Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" := - (CIf e1 e2 e3) (at level 80, right associativity). -Notation "'HAVOC' l" := (CHavoc l) (at level 60). + (CWhile b c) (at level 80, right associativity) : imp_scope. +Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" := + (CIf e1 e2 e3) (at level 80, right associativity) : imp_scope. +Notation "'HAVOC' l" := + (CHavoc l) (at level 60) : imp_scope. + +(** **** 练习:2 星, standard (himp_ceval) -(** **** 练习:2 星 (himp_ceval) *) -(** 现在,我们必须扩展操作语义。前面我们已经提过了 [ceval] 关系的模版, + 现在,我们必须扩展操作语义。前面我们已经提过了 [ceval] 关系的模版, 指定了大步语义。为了形式化 [HAVOC] 指令的行为,我们还需要在 [ceval] 的定义中添加哪些规则? *) -Reserved Notation "c1 '/' st '\\' st'" - (at level 40, st at level 39). +Reserved Notation "st '=[' c ']=>' st'" (at level 40). +Open Scope imp_scope. Inductive ceval : com -> state -> state -> Prop := - | E_Skip : forall st : state, SKIP / st \\ st - | E_Ass : forall (st : state) (a1 : aexp) (n : nat) (X : string), + | E_Skip : forall st, + st =[ SKIP ]=> st + | E_Ass : forall st a1 n x, aeval st a1 = n -> - (X ::= a1) / st \\ st & { X --> n } - | E_Seq : forall (c1 c2 : com) (st st' st'' : state), - c1 / st \\ st' -> - c2 / st' \\ st'' -> - (c1 ;; c2) / st \\ st'' - | E_IfTrue : forall (st st' : state) (b1 : bexp) (c1 c2 : com), - beval st b1 = true -> - c1 / st \\ st' -> - (IFB b1 THEN c1 ELSE c2 FI) / st \\ st' - | E_IfFalse : forall (st st' : state) (b1 : bexp) (c1 c2 : com), - beval st b1 = false -> - c2 / st \\ st' -> - (IFB b1 THEN c1 ELSE c2 FI) / st \\ st' - | E_WhileFalse : forall (b1 : bexp) (st : state) (c1 : com), - beval st b1 = false -> - (WHILE b1 DO c1 END) / st \\ st - | E_WhileTrue : forall (st st' st'' : state) (b1 : bexp) (c1 : com), - beval st b1 = true -> - c1 / st \\ st' -> - (WHILE b1 DO c1 END) / st' \\ st'' -> - (WHILE b1 DO c1 END) / st \\ st'' + st =[ x ::= a1 ]=> (x !-> n ; st) + | E_Seq : forall c1 c2 st st' st'', + st =[ c1 ]=> st' -> + st' =[ c2 ]=> st'' -> + st =[ c1 ;; c2 ]=> st'' + | E_IfTrue : forall st st' b c1 c2, + beval st b = true -> + st =[ c1 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_IfFalse : forall st st' b c1 c2, + beval st b = false -> + st =[ c2 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_WhileFalse : forall b st c, + beval st b = false -> + st =[ WHILE b DO c END ]=> st + | E_WhileTrue : forall st st' st'' b c, + beval st b = true -> + st =[ c ]=> st' -> + st' =[ WHILE b DO c END ]=> st'' -> + st =[ WHILE b DO c END ]=> st'' (* 请在此处解答 *) - where "c1 '/' st '\\' st'" := (ceval c1 st st'). + where "st =[ c ]=> st'" := (ceval c st st'). +Close Scope imp_scope. (** 作为合理性检查,以下断言对于你的定义来说应该是可证的: *) -Example havoc_example1 : (HAVOC X) / { --> 0 } \\ { X --> 0 }. +Example havoc_example1 : empty_st =[ (HAVOC X)%imp ]=> (X !-> 0). Proof. (* 请在此处解答 *) Admitted. Example havoc_example2 : - (SKIP;; HAVOC Z) / { --> 0 } \\ { Z --> 42 }. + empty_st =[ (SKIP;; HAVOC Z)%imp ]=> (Z !-> 42). Proof. (* 请在此处解答 *) Admitted. @@ -1316,35 +1326,36 @@ Definition manual_grade_for_Check_rule_for_HAVOC : option (nat*string) := None. (** 最后,我们重新定义和之前等价的指令: *) Definition cequiv (c1 c2 : com) : Prop := forall st st' : state, - c1 / st \\ st' <-> c2 / st \\ st'. + st =[ c1 ]=> st' <-> st =[ c2 ]=> st'. (** 我们应用此定义来证明一些非确定性程序是否等价。 *) -(** **** 练习:3 星 (havoc_swap) *) -(** 以下两个程序是否等价? *) +(** **** 练习:3 星, standard (havoc_swap) + + 以下两个程序是否等价? *) Definition pXY := - HAVOC X;; HAVOC Y. + (HAVOC X;; HAVOC Y)%imp. Definition pYX := - HAVOC Y;; HAVOC X. + (HAVOC Y;; HAVOC X)%imp. (** 请证明你的想法。 *) - Theorem pXY_cequiv_pYX : cequiv pXY pYX \/ ~cequiv pXY pYX. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, optional (havoc_copy) *) -(** 以下两个程序是否等价? *) +(** **** 练习:4 星, standard, optional (havoc_copy) + + 以下两个程序是否等价? *) Definition ptwice := - HAVOC X;; HAVOC Y. + (HAVOC X;; HAVOC Y)%imp. Definition pcopy := - HAVOC X;; Y ::= X. + (HAVOC X;; Y ::= X)%imp. (** 请证明你的想法。(提示:你可能会用到 [assert] 的略。) *) @@ -1360,74 +1371,76 @@ Proof. (* 请在此处解答 *) Admitted. 以下练习的最后一部分展示了这种现象。 *) -(** **** 练习:4 星, advanced (p1_p2_term) *) -(** 考虑一下指令: *) +(** **** 练习:4 星, advanced (p1_p2_term) + + 考虑一下指令: *) Definition p1 : com := - WHILE ! (X = 0) DO + (WHILE ~ (X = 0) DO HAVOC Y;; X ::= X + 1 - END. + END)%imp. Definition p2 : com := - WHILE ! (X = 0) DO + (WHILE ~ (X = 0) DO SKIP - END. + END)%imp. (** 直觉上来说,[p1] 和 [p2] 的停机行为相同:要么无限循环,要么以相同的状态开始, 就在相同的状态下停机。我们可以用以下引理分别刻画 [p1] 和 [p2] 的停机行为: *) Lemma p1_may_diverge : forall st st', st X <> 0 -> - ~ p1 / st \\ st'. + ~ st =[ p1 ]=> st'. Proof. (* 请在此处解答 *) Admitted. Lemma p2_may_diverge : forall st st', st X <> 0 -> - ~ p2 / st \\ st'. + ~ st =[ p2 ]=> st'. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced (p1_p2_equiv) *) -(** 使用这两个引理来证明 [p1] 和 [p2] 确实等价。 *) +(** **** 练习:4 星, advanced (p1_p2_equiv) + + 使用这两个引理来证明 [p1] 和 [p2] 确实等价。 *) Theorem p1_p2_equiv : cequiv p1 p2. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced (p3_p4_inequiv) *) -(** 证明以下程序_'不等价'_(提示:当 [p3] 停机时 [Z] 的值是什么?当 +(** **** 练习:4 星, advanced (p3_p4_inequiv) + + 证明以下程序_'不等价'_(提示:当 [p3] 停机时 [Z] 的值是什么?当 [p4] 停机时呢?) *) Definition p3 : com := - Z ::= 1;; - WHILE ! (X = 0) DO + (Z ::= 1;; + WHILE ~(X = 0) DO HAVOC X;; HAVOC Z - END. + END)%imp. Definition p4 : com := - X ::= 0;; - Z ::= 1. - + (X ::= 0;; + Z ::= 1)%imp. Theorem p3_p4_inequiv : ~ cequiv p3 p4. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:5 星, advanced, optional (p5_p6_equiv) *) -(** 证明以下指令等价。(提示:正如我们之前提到的,我们为 Himp 定义的 - [cequiv] 只考虑了可能的停机配置的集合:对于两个程序而言, - 当且仅当给定了相同的起始状态 [st],且可能的停机状态的集合相同时,二者才等价。 +(** **** 练习:5 星, advanced, optional (p5_p6_equiv) + + 证明以下指令等价。(提示:正如我们之前提到的,我们为 Himp 定义的 + [cequiv] 只考虑了可能的停机配置的集合:对于两个拥有相同起始状态 [st] + 的程序而言,当且仅当二者可能的停机状态的集合相同时,二者才等价。 若 [p5] 停机,那么最终状态应当是什么?反过来说,[p5] 总是会停机吗?) *) Definition p5 : com := - WHILE ! (X = 1) DO + (WHILE ~(X = 1) DO HAVOC X - END. + END)%imp. Definition p6 : com := - X ::= 1. - + (X ::= 1)%imp. Theorem p5_p6_equiv : cequiv p5 p6. Proof. (* 请在此处解答 *) Admitted. @@ -1438,8 +1451,9 @@ End Himp. (* ################################################################# *) (** * 附加练习 *) -(** **** 练习:4 星, optional (for_while_equiv) *) -(** 此练习是 [Imp] 一章中可选练习 [add_for_loop] 的扩展, +(** **** 练习:4 星, standard, optional (for_while_equiv) + + 此练习是 [Imp] 一章中可选练习 [add_for_loop] 的扩展, 就是那个让你扩展出类似 C 风格的 [for] 循环指令的练习。请证明指令: for (c1 ; b ; c2) { @@ -1454,11 +1468,13 @@ End Himp. c2 END *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) -(** **** 练习:3 星, optional (swap_noninterfering_assignments) *) -(** (提示:这里你需要 [functional_extensionality]。) *) +(** **** 练习:3 星, standard, optional (swap_noninterfering_assignments) + + (提示:这里你需要 [functional_extensionality]。) *) Theorem swap_noninterfering_assignments: forall l1 l2 a1 a2, l1 <> l2 -> @@ -1471,23 +1487,31 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced, optional (capprox) *) -(** 在这个练习中我们定义了一个非对称的程序等价变形, 叫做 +(** **** 练习:4 星, advanced, optional (capprox) + + 在这个练习中我们定义了一个非对称的程序等价变形, 叫做 _'程序近似(program approximation)'_。 当每个能让 [c1] 停机的初始状态也能让 [c2] 在相同的状态下停机时,我们就说程序 [c1] _'近似与'_ 程序 [c2] 。下面是程序近似的形式化定义: *) Definition capprox (c1 c2 : com) : Prop := forall (st st' : state), - c1 / st \\ st' -> c2 / st \\ st'. + st =[ c1 ]=> st' -> st =[ c2 ]=> st'. + +(** 例如,程序 + + c1 = WHILE ~(X = 1) DO + X ::= X - 1 + END -(** 例如,程序 [c1 = WHILE !(X = 1) DO X ::= X - 1 END] 近似于 [c2 = X ::= 1],但是 [c2] 不近似于 [c1],因为 [c1] 不会在 [X = 0] 时停机,而 [c2] 会。如果两个程序互相近似,那么它们等价。 *) (** 请找出两个程序 [c3] 和 [c4],它们互不近似。 *) -Definition c3 : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. -Definition c4 : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. +Definition c3 : com + (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. +Definition c4 : com + (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Theorem c3_c4_different : ~ capprox c3 c4 /\ ~ capprox c4 c3. Proof. (* 请在此处解答 *) Admitted. @@ -1510,4 +1534,4 @@ Theorem zprop_preserving : forall c c', Proof. (* 请在此处解答 *) Admitted. (** [] *) - +(* Sat Jan 26 15:15:43 UTC 2019 *) diff --git a/plf-current/EquivTest.v b/plf-current/EquivTest.v index 7f450897..12dd38b0 100644 --- a/plf-current/EquivTest.v +++ b/plf-current/EquivTest.v @@ -44,17 +44,17 @@ Print Assumptions skip_right. Goal True. idtac " ". -idtac "------------------- IFB_false --------------------". +idtac "------------------- TEST_false --------------------". idtac " ". -idtac "#> IFB_false". +idtac "#> TEST_false". idtac "Possible points: 2". -check_type @IFB_false ( +check_type @TEST_false ( (forall (b : Imp.bexp) (c1 c2 : Imp.com), bequiv b Imp.BFalse -> cequiv (Imp.CIf b c1 c2) c2)). idtac "Assumptions:". Abort. -Print Assumptions IFB_false. +Print Assumptions TEST_false. Goal True. idtac " ". @@ -93,8 +93,8 @@ idtac " ". idtac "#> assign_aequiv". idtac "Possible points: 2". check_type @assign_aequiv ( -(forall (X : String.string) (e : Imp.aexp), - aequiv (Imp.AId X) e -> cequiv Imp.CSkip (Imp.CAss X e))). +(forall (x : String.string) (e : Imp.aexp), + aequiv (Imp.AId x) e -> cequiv Imp.CSkip (Imp.CAss x e))). idtac "Assumptions:". Abort. Print Assumptions assign_aequiv. @@ -234,8 +234,8 @@ idtac "". idtac "********** Standard **********". idtac "---------- skip_right ---------". Print Assumptions skip_right. -idtac "---------- IFB_false ---------". -Print Assumptions IFB_false. +idtac "---------- TEST_false ---------". +Print Assumptions TEST_false. idtac "---------- swap_if_branches ---------". Print Assumptions swap_if_branches. idtac "---------- WHILE_true ---------". @@ -265,3 +265,5 @@ Print Assumptions Himp.p1_p2_equiv. idtac "---------- Himp.p3_p4_inequiv ---------". Print Assumptions Himp.p3_p4_inequiv. Abort. + +(* Sat Jan 26 15:15:53 UTC 2019 *) diff --git a/plf-current/Hoare.html b/plf-current/Hoare.html index c65d376b..8fe619e3 100644 --- a/plf-current/Hoare.html +++ b/plf-current/Hoare.html @@ -32,22 +32,16 @@
+Hoare霍尔逻辑(第一部分)
-- -- -Remove "Nat." --+ Set Warnings "-notation-overridden,-parsing".
-Require Import Coq.Bool.Bool.
-Require Import Coq.Arith.Arith.
-Require Import Coq.Arith.EqNat.
-Require Import Coq.Arith.PeanoNat. Import Nat.
-Require Import Coq.omega.Omega.
-From PLF Require Import Imp.
From PLF Require Import Maps.
+From Coq Require Import Bool.Bool.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Arith.EqNat.
+From Coq Require Import Arith.PeanoNat. Import Nat.
+From Coq Require Import omega.Omega.
+From PLF Require Import Imp.
@@ -146,7 +140,8 @@Hoare霍尔逻辑(第一部分)< ——其中“复合”的意思是,这些证明的结构直接反映了相应程序的结构。
- 在这一章里: + 本章概览... + 主题:@@ -212,7 +207,7 @@Hoare霍尔逻辑(第一部分)<
@@ -224,7 +219,7 @@Hoare霍尔逻辑(第一部分)< fun st ⇒ st X = 3 ∨ st X ≤ st Y.
Definition as4 : Assertion :=
fun st ⇒ st Z * st Z ≤ st X ∧
- ¬ (((S (st Z)) * (S (st Z))) ≤ st X).
+ ¬(((S (st Z)) * (S (st Z))) ≤ st X).
Definition as5 : Assertion := fun st ⇒ True.
Definition as6 : Assertion := fun st ⇒ False.
(* 请在此处解答 *)
@@ -248,7 +243,7 @@Hoare霍尔逻辑(第一部分)<
fun st ⇒ (st Z) * (st Z) ≤ m ∧@@ -272,13 +267,13 @@
- ¬ ((S (st Z)) * (S (st Z)) ≤ m) + ¬((S (st Z)) * (S (st Z)) ≤ m)Hoare霍尔逻辑(第一部分)<
给出两断言 P 与 Q,我们说 P 蕴含 Q, - 写作 P ->> Q,如果当 P 在 st 下成立,Q 也成立。 + 写作 P ->> Q,如果当 P 在 st 下成立,Q 也成立。Definition assert_implies (P Q : Assertion) : Prop :=@@ -293,8 +288,8 @@
- ∀ st, P st → Q st.
-Notation "P ->> Q" := (assert_implies P Q)
+ ∀st, P st → Q st.
+Notation "P ->> Q" := (assert_implies P Q)
(at level 80) : hoare_spec_scope.
Open Scope hoare_spec_scope.
Hoare霍尔逻辑(第一部分)<
-Notation "P <<->> Q" :=
- (P ->> Q ∧ Q ->> P) (at level 80) : hoare_spec_scope.
+Notation "P <<->> Q" :=
+ (P ->> Q ∧ Q ->> P) (at level 80) : hoare_spec_scope.
@@ -328,9 +323,9 @@Hoare霍尔逻辑(第一部分)<
Definition hoare_triple@@ -357,7 +352,7 @@
- (P:Assertion) (c:com) (Q:Assertion) : Prop :=
- ∀ st st',
- c / st \\ st' →
+ (P : Assertion) (c : com) (Q : Assertion) : Prop :=
+ ∀st st',
+ st =[ c ]⇒ st' →
P st →
Q st'.
Hoare霍尔逻辑(第一部分)<
--练习:1 星, optional (triples)
+练习:1 星, standard, optional (triples)
用中文重新表述下列霍尔三元组。@@ -377,17 +372,21 @@Hoare霍尔逻辑(第一部分)<
6) {{X = m}}
c
- {{(Z * Z) ≤ m ∧ ¬ (((S Z) * (S Z)) ≤ m)}} + {{(Z * Z) ≤ m ∧ ¬(((S Z) * (S Z)) ≤ m)}}+ ++(* 请在此处解答 *)- ☐ +☐ +
+- ☐ + + +-练习:1 星, optional (valid_triples)
+练习:1 星, standard, optional (valid_triples)
下列的霍尔三元组是否有效,亦即,表述的 P、c、Q 之间的 关系是否为真? @@ -398,7 +397,7 @@Hoare霍尔逻辑(第一部分)<
2) {{X = 2}} X ::= X + 1 {{X = 3}}
- 3) {{True}} X ::= 5; Y ::= 0 {{X = 5}}
+ 3) {{True}} X ::= 5;; Y ::= 0 {{X = 5}}
4) {{X = 2 ∧ X = 3}} X ::= 5 {{X = 0}}
@@ -413,12 +412,19 @@Hoare霍尔逻辑(第一部分)< {{X = 1}}
9) {{X = 1}}
- WHILE !(X = 0) DO X ::= X + 1 END
+ WHILE ~(X = 0) DO X ::= X + 1 END
{{X = 100}}+(* 请在此处解答 *)+ +☐ +
+为了热身,这里有两个关于霍尔三元组的简单定理。 @@ -426,8 +432,8 @@Hoare霍尔逻辑(第一部分)<
-Theorem hoare_post_true : ∀ (P Q : Assertion) c,
- (∀ st, Q st) →
+Theorem hoare_post_true : ∀(P Q : Assertion) c,
+ (∀st, Q st) →
{{P}} c {{Q}}.
@@ -438,8 +444,8 @@Hoare霍尔逻辑(第一部分)<
-Theorem hoare_pre_false : ∀ (P Q : Assertion) c,
- (∀ st, ~(P st)) →
+Theorem hoare_pre_false : ∀(P Q : Assertion) c,
+ (∀st, ¬(P st)) →
{{P}} c {{Q}}.
@@ -506,7 +512,7 @@Hoare霍尔逻辑(第一部分)<
- {{ a = 1 }} X ::= a {{ X = 1 }} + {{ a = 1 }} X ::= a {{ X = 1 }}@@ -520,11 +526,11 @@Hoare霍尔逻辑(第一部分)<
- {{ Q [X |-> a] }} X ::= a {{ Q }} + {{ Q [X ⊢> a] }} X ::= a {{ Q }}- 其中 "Q [X |-> a]" 读作 “在 Q 中把 X 换成 a”。 + 其中 "Q [X ⊢> a]" 读作 “在 Q 中把 X 换成 a”。例如,下列这些是赋值规则正确的应用: @@ -532,18 +538,18 @@Hoare霍尔逻辑(第一部分)<
- {{ (X ≤ 5) [X |-> X + 1]
+ {{ (X ≤ 5) [X ⊢> X + 1]
i.e., X + 1 ≤ 5 }}
X ::= X + 1
{{ X ≤ 5 }}
- {{ (X = 3) [X |-> 3]
- i.e., 3 = 3}}
+ {{ (X = 3) [X ⊢> 3]
+ i.e., 3 = 3 }}
X ::= 3
{{ X = 3 }}
- {{ (0 ≤ X ∧ X ≤ 5) [X |-> 3]
- i.e., (0 ≤ 3 ∧ 3 ≤ 5)}}
+ {{ (0 ≤ X ∧ X ≤ 5) [X ⊢> 3]
+ i.e., (0 ≤ 3 ∧ 3 ≤ 5) }}
X ::= 3
{{ 0 ≤ X ∧ X ≤ 5 }}@@ -566,25 +572,26 @@Hoare霍尔逻辑(第一部分)< Definition assn_sub X a P : Assertion :=
fun (st : state) ⇒
- P (st & { X --> aeval st a }).
-Notation "P [ X |-> a ]" := (assn_sub X a P) (at level 10).
+ P (X !-> aeval st a ; st).
+Notation "P [ X ⊢> a ]" := (assn_sub X a P)
+ (at level 10, X at next level).
-也就是说,P [X |-> a] 是一个新的断言——我们把它叫做 P' —— +也就是说,P [X ⊢> a] 是一个新的断言——我们把它叫做 P' —— 它就是 P,不过当 P 在当前状态中查找变量 X 的时候,P' 使用表 达式 a 的值。为了演示工作原理,我们来计算一下这几个例子中发生了些什么。首先,假设 - P' 是 (X ≤ 5) [X |-> 3] ——或者,更形式化地, P' 是 Coq 表达式 + P' 是 (X ≤ 5) [X ⊢> 3] ——或者,更形式化地, P' 是 Coq 表达式fun st ⇒@@ -595,7 +602,7 @@
(fun st' ⇒ st' X ≤ 5)
- (st & { X --> aeval st 3 }) + (X !-> aeval st 3 ; st),Hoare霍尔逻辑(第一部分)<
fun st ⇒@@ -605,7 +612,7 @@
(fun st' ⇒ st' X ≤ 5)
- (st & { X --> 3 }) + (X !-> 3 ; st)Hoare霍尔逻辑(第一部分)<
fun st ⇒@@ -622,7 +629,7 @@
- ((st & { X --> 3 }) X) ≤ 5 + ((X !-> 3 ; st) X) ≤ 5Hoare霍尔逻辑(第一部分)< 也就是说,P' 是一个断言指出 3 小于等于 5(像我们想的一样)。
- 一个更有趣的例子是,假设 P' 是 (X ≤ 5) [X |-> X+1]。形式化地,P' + 一个更有趣的例子是,假设 P' 是 (X ≤ 5) [X ⊢> X + 1]。形式化地,P' 是 Coq 表达式@@ -630,7 +637,7 @@Hoare霍尔逻辑(第一部分)<
fun st ⇒@@ -640,7 +647,7 @@
(fun st' ⇒ st' X ≤ 5)
- (st & { X --> aeval st (X+1) }), + (X !-> aeval st (X + 1) ; st),Hoare霍尔逻辑(第一部分)<
fun st ⇒@@ -650,11 +657,11 @@
- (st & { X --> aeval st (X+1) }) X ≤ 5 + (X !-> aeval st (X + 1) ; st) X ≤ 5Hoare霍尔逻辑(第一部分)<
fun st ⇒- 也就是说,P' 指出 X+1 最多是 5。 + 也就是说,P' 指出 X + 1 最多是 5。
- (aeval st (X+1)) ≤ 5. + (aeval st (X + 1)) ≤ 5.@@ -669,7 +676,7 @@Hoare霍尔逻辑(第一部分)<
- {{Q [X |-> a]}} X ::= a {{Q}} +{{Q [X ⊢> a]}} X ::= a {{Q}} Hoare霍尔逻辑(第一部分)<
-Theorem hoare_asgn : ∀ Q X a,
- {{Q [X |-> a]}} (X ::= a) {{Q}}.
+Theorem hoare_asgn : ∀Q X a,
+ {{Q [X ⊢> a]}} X ::= a {{Q}}.
Proof.
@@ -697,8 +704,8 @@Hoare霍尔逻辑(第一部分)<
Example assn_sub_example :
- {{(fun st ⇒ st X < 5) [X |-> X+1]}}
- (X ::= X+1)
+ {{(fun st ⇒ st X < 5) [X ⊢> X + 1]}}
+ X ::= X + 1
{{fun st ⇒ st X < 5}}.
Proof.
(* 课上已完成 *)
@@ -711,24 +718,24 @@Hoare霍尔逻辑(第一部分)<
- {{X < 4}} (X ::= X+1) {{X < 5}} + {{X < 4}} X ::= X + 1 {{X < 5}}我们会在下一节中了解怎么做。-练习:2 星 (hoare_asgn_examples)
+练习:2 星, standard (hoare_asgn_examples)
将下列非正式的霍尔三元组……- 1) {{ (X ≤ 10) [X |-> 2 * X] }}
+ 1) {{ (X ≤ 10) [X ⊢> 2 * X] }}
X ::= 2 * X
{{ X ≤ 10 }}
- 2) {{ (0 ≤ X ∧ X ≤ 5) [X |-> 3] }}
+ 2) {{ (0 ≤ X ∧ X ≤ 5) [X ⊢> 3] }}
X ::= 3
{{ 0 ≤ X ∧ X ≤ 5 }}@@ -748,7 +755,7 @@Hoare霍尔逻辑(第一部分)<
☐ --练习:2 星, recommended (hoare_asgn_wrong)
+练习:2 星, standard, recommended (hoare_asgn_wrong)
几乎所有人在看赋值规则第一眼就会觉得它是反向的。如果你还感觉很 迷惑,思考一些“正向”的规则可能有帮助。这里是一个看起来挺自然的 霍尔三元组: @@ -777,12 +784,9 @@Hoare霍尔逻辑(第一部分)<
- -Local Close Scope aexp_scope.+
-+-练习:3 星, advanced (hoare_asgn_fwd)
然而,通过引入一个参数 m(一个 Coq 整数)来记录 X 原 来的值,我们可以定义一个赋值的证明规则,它可以,直觉上讲,“正向地 @@ -809,7 +813,7 @@Hoare霍尔逻辑(第一部分)<
- (其中 st' = st & { X --> m }) +(其中 st' = (X !-> m ; st)) 可以注意到,在赋值发生之前我们用 X 原来的值重新构造了状态 @@ -819,11 +823,11 @@ Hoare霍尔逻辑(第一部分)<
Theorem hoare_asgn_fwd :@@ -853,11 +857,11 @@
- ∀ m a P,
+ ∀m a P,
{{fun st ⇒ P st ∧ st X = m}}
X ::= a
- {{fun st ⇒ P (st & { X --> m })
- ∧ st X = aeval (st & { X --> m }) a }}.
+ {{fun st ⇒ P (X !-> m ; st)
+ ∧ st X = aeval (X !-> m ; st) a }}.
Proof.
(* 请在此处解答 *) Admitted.
Hoare霍尔逻辑(第一部分)<
- {{fun st ⇒ ∃ m, P (st & { X --> m }) ∧ +{{fun st ⇒ ∃m, P (X !-> m ; st) ∧ - st X = aeval (st & { X --> m }) a }} +st X = aeval (X !-> m ; st) a }} @@ -865,11 +869,11 @@ Hoare霍尔逻辑(第一部分)<
Theorem hoare_asgn_fwd_exists :却不行。这个三元组是有效的,不过它并不是 hoare_asgn 的实例,因 - 为 True and (X = 3) [X |-> 3] 在语法上并不是相同的断言。然而, + 为 True and (X = 3) [X ⊢> 3] 在语法上并不是相同的断言。然而, 它们在逻辑上等价,所以前面那个三元组成立,后者也一定成立。 我们把这种想法用下列规则写出来:
- ∀ a P,
+ ∀a P,
{{fun st ⇒ P st}}
X ::= a
- {{fun st ⇒ ∃ m, P (st & { X --> m }) ∧
- st X = aeval (st & { X --> m }) a }}.
+ {{fun st ⇒ ∃m, P (X !-> m ; st) ∧
+ st X = aeval (X !-> m ; st) a }}.
Proof.
intros a P.
(* 请在此处解答 *) Admitted.
@@ -894,7 +898,7 @@Hoare霍尔逻辑(第一部分)<
- {{(X = 3) [X |-> 3]}} X ::= 3 {{X = 3}} + {{(X = 3) [X ⊢> 3]}} X ::= 3 {{X = 3}}@@ -908,7 +912,7 @@Hoare霍尔逻辑(第一部分)<
@@ -1504,9 +1510,9 @@ Hoare霍尔逻辑(第一部分)<
{{ True }}
- IFB X = 0
- THEN Y ::= 2
- ELSE Y ::= X + 1
+ TEST X = 0
+ THEN Y ::= 2
+ ELSE Y ::= X + 1
FI
{{ X ≤ Y }}@@ -1523,11 +1529,11 @@Hoare霍尔逻辑(第一部分)<
@@ -1558,7 +1564,7 @@
- {{P ∧ b}} c1 {{Q}} +{{P ∧ b}} c1 {{Q}} - @@ -1535,7 +1541,7 @@{{P ∧ ~b}} c2 {{Q}} +{{P ∧ ¬b}} c2 {{Q}} (hoare_if) Hoare霍尔逻辑(第一部分)<
- {{P}} IFB b THEN c1 ELSE c2 FI {{Q}} +{{P}} TEST b THEN c1 ELSE c2 FI {{Q}} Hoare霍尔逻辑(第一部分)<
-Lemma bexp_eval_true : ∀ b st,
+Lemma bexp_eval_true : ∀b st,
beval st b = true → (bassn b) st.
@@ -1568,8 +1574,8 @@Hoare霍尔逻辑(第一部分)<
-Lemma bexp_eval_false : ∀ b st,
- beval st b = false → ¬ ((bassn b) st).
+Lemma bexp_eval_false : ∀b st,
+ beval st b = false → ¬((bassn b) st).
Proof.
@@ -1584,10 +1590,10 @@Hoare霍尔逻辑(第一部分)<
-Theorem hoare_if : ∀ P Q b c1 c2,
+Theorem hoare_if : ∀P Q b c1 c2,
{{fun st ⇒ P st ∧ bassn b st}} c1 {{Q}} →
- {{fun st ⇒ P st ∧ ~(bassn b st)}} c2 {{Q}} →
- {{P}} (IFB b THEN c1 ELSE c2 FI) {{Q}}.
+ {{fun st ⇒ P st ∧ ¬(bassn b st)}} c2 {{Q}} →
+ {{P}} TEST b THEN c1 ELSE c2 FI {{Q}}.
Proof.
@@ -1617,7 +1623,7 @@Hoare霍尔逻辑(第一部分)< Example if_example :
{{fun st ⇒ True}}
- IFB X = 0
+ TEST X = 0
THEN Y ::= 2
ELSE Y ::= X + 1
FI
@@ -1642,14 +1648,14 @@Hoare霍尔逻辑(第一部分)<
-练习:2 星 (if_minus_plus)
+练习:2 星, standard (if_minus_plus)
用 hoare_if 证明下面的三元组。不要使用 unfold hoare_triple。Theorem if_minus_plus :
{{fun st ⇒ True}}
- IFB X ≤ Y
+ TEST X ≤ Y
THEN Z ::= Y - X
ELSE Y ::= X + Z
FI
@@ -1665,7 +1671,7 @@Hoare霍尔逻辑(第一部分)<
-练习:4 星 (if1_hoare)
+练习:4 星, standard (if1_hoare)
在这个练习中我们考虑对 Imp 加入形如 IF1 b THEN c FI 的“单边条件”。 这里 b 是个布尔表达式而 c 是一个命令。如果 b 化简为 true, c 就被执行,而如果 b 化简为 false, IF1 b THEN c FI 就啥也不做。 @@ -1690,17 +1696,17 @@Hoare霍尔逻辑(第一部分)< | CWhile : bexp → com → com
| CIf1 : bexp → com → com.
Notation "'SKIP'" :=
- CSkip.
+ CSkip : imp_scope.
Notation "c1 ;; c2" :=
- (CSeq c1 c2) (at level 80, right associativity).
+ (CSeq c1 c2) (at level 80, right associativity) : imp_scope.
Notation "X '::=' a" :=
- (CAss X a) (at level 60).
+ (CAss X a) (at level 60) : imp_scope.
Notation "'WHILE' b 'DO' c 'END'" :=
- (CWhile b c) (at level 80, right associativity).
-Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" :=
- (CIf e1 e2 e3) (at level 80, right associativity).
+ (CWhile b c) (at level 80, right associativity) : imp_scope.
+Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" :=
+ (CIf e1 e2 e3) (at level 80, right associativity) : imp_scope.
Notation "'IF1' b 'THEN' c 'FI'" :=
- (CIf1 b c) (at level 80, right associativity).
+ (CIf1 b c) (at level 80, right associativity) : imp_scope.
@@ -1709,29 +1715,38 @@Hoare霍尔逻辑(第一部分)<
-Reserved Notation "c1 '/' st '\\' st'" (at level 40, st at level 39).
+Reserved Notation "st '=[' c ']⇒' st'" (at level 40).
+Open Scope imp_scope.
Inductive ceval : com → state → state → Prop :=
- | E_Skip : ∀ st : state, SKIP / st \\ st
- | E_Ass : ∀ (st : state) (a1 : aexp) (n : nat) (X : string),
- aeval st a1 = n → (X ::= a1) / st \\ st & { X --> n }
- | E_Seq : ∀ (c1 c2 : com) (st st' st'' : state),
- c1 / st \\ st' → c2 / st' \\ st'' → (c1 ;; c2) / st \\ st''
- | E_IfTrue : ∀ (st st' : state) (b1 : bexp) (c1 c2 : com),
- beval st b1 = true →
- c1 / st \\ st' → (IFB b1 THEN c1 ELSE c2 FI) / st \\ st'
- | E_IfFalse : ∀ (st st' : state) (b1 : bexp) (c1 c2 : com),
- beval st b1 = false →
- c2 / st \\ st' → (IFB b1 THEN c1 ELSE c2 FI) / st \\ st'
- | E_WhileFalse : ∀ (b1 : bexp) (st : state) (c1 : com),
- beval st b1 = false → (WHILE b1 DO c1 END) / st \\ st
- | E_WhileTrue : ∀ (st st' st'' : state) (b1 : bexp) (c1 : com),
- beval st b1 = true →
- c1 / st \\ st' →
- (WHILE b1 DO c1 END) / st' \\ st'' →
- (WHILE b1 DO c1 END) / st \\ st''
+ | E_Skip : ∀st,
+ st =[ SKIP ]⇒ st
+ | E_Ass : ∀st a1 n x,
+ aeval st a1 = n →
+ st =[ x ::= a1 ]⇒ (x !-> n ; st)
+ | E_Seq : ∀c1 c2 st st' st'',
+ st =[ c1 ]⇒ st' →
+ st' =[ c2 ]⇒ st'' →
+ st =[ c1 ;; c2 ]⇒ st''
+ | E_IfTrue : ∀st st' b c1 c2,
+ beval st b = true →
+ st =[ c1 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_IfFalse : ∀st st' b c1 c2,
+ beval st b = false →
+ st =[ c2 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_WhileFalse : ∀b st c,
+ beval st b = false →
+ st =[ WHILE b DO c END ]⇒ st
+ | E_WhileTrue : ∀st st' st'' b c,
+ beval st b = true →
+ st =[ c ]⇒ st' →
+ st' =[ WHILE b DO c END ]⇒ st'' →
+ st =[ WHILE b DO c END ]⇒ st''
(* 请在此处解答 *)
- where "c1 '/' st '\\' st'" := (ceval c1 st st').
+ where "st '=[' c ']⇒' st'" := (ceval c st st').
+Close Scope imp_scope.
@@ -1739,9 +1754,10 @@Hoare霍尔逻辑(第一部分)<
-Definition hoare_triple (P:Assertion) (c:com) (Q:Assertion) : Prop :=
- ∀ st st',
- c / st \\ st' →
+Definition hoare_triple
+ (P : Assertion) (c : com) (Q : Assertion) : Prop :=
+ ∀st st',
+ st =[ c ]⇒ st' →
P st →
Q st'.
Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q)
@@ -1766,7 +1782,7 @@Hoare霍尔逻辑(第一部分)<
{{ X + Y = Z }}
- IF1 !(Y = 0) THEN
+ IF1 ~(Y = 0) THEN
X ::= X + Y
FI
{{ X = Z }} @@ -1783,9 +1799,9 @@Hoare霍尔逻辑(第一部分)< Lemma hoare_if1_good :
{{ fun st ⇒ st X + st Y = st Z }}
- IF1 !(Y = 0) THEN
+ (IF1 ~(Y = 0) THEN
X ::= X + Y
- FI
+ FI)%imp
{{ fun st ⇒ st X = st Z }}.
Proof. (* 请在此处解答 *) Admitted.
End If1.
@@ -1877,7 +1893,7 @@Hoare霍尔逻辑(第一部分)<
- {{P}} WHILE b DO c END {{P ∧ ~b}} +{{P}} WHILE b DO c END {{P ∧ ¬b}} 这几乎就是我们想要的规则,不过它还有一点可以改进的地方:在循环体 @@ -1886,9 +1902,7 @@ Hoare霍尔逻辑(第一部分)<
这给我们带来了一点额外的信息用来推论 c (用来说明它结束时 - 满足不变式)。 这让我们可以给出这个规则的最终版本: -- + 满足不变式)。 而这会将我们导向此规则的最终版本:断言 P 叫做循环不变式(invariant of the loop)。 @@ -1907,16 +1921,16 @@
{{P ∧ b}} c {{P}} @@ -1899,7 +1913,7 @@Hoare霍尔逻辑(第一部分)<
- {{P}} WHILE b DO c END {{P ∧ ~b}} +{{P}} WHILE b DO c END {{P ∧ ¬b}} Hoare霍尔逻辑(第一部分)<
-Theorem hoare_while : ∀ P b c,
+Theorem hoare_while : ∀P b c,
{{fun st ⇒ P st ∧ bassn b st}} c {{P}} →
- {{P}} WHILE b DO c END {{fun st ⇒ P st ∧ ¬ (bassn b st)}}.
+ {{P}} WHILE b DO c END {{fun st ⇒ P st ∧ ¬(bassn b st)}}.
Proof.
intros P b c Hhoare st st' He HP.
(* 像之前见到过的,我们需要对 He 做归纳来推理。
因为,在“继续循环”的情形中,假设会是关于整个循环而不只是关于 c 的。*)
- remember (WHILE b DO c END) as wcom eqn:Heqwcom.
+ remember (WHILE b DO c END)%imp as wcom eqn:Heqwcom.
induction He;
try (inversion Heqwcom); subst; clear Heqwcom.
- (* E_WhileFalse *)
@@ -1943,7 +1957,7 @@Hoare霍尔逻辑(第一部分)<
- WHILE X = 2 DO X := 1 END + WHILE X = 2 DO X := 1 END@@ -1978,7 +1992,7 @@Hoare霍尔逻辑(第一部分)<
-Theorem always_loop_hoare : ∀ P Q,@@ -2174,7 +2188,7 @@
+Theorem always_loop_hoare : ∀P Q,
{{P}} WHILE true DO SKIP END {{Q}}.
@@ -2015,8 +2029,8 @@Hoare霍尔逻辑(第一部分)<
练习:4 星, advanced (hoare_repeat)
- 在这个练习中,我们会往 Imp 里面加一种新的命令:REPEAT c UNTIL a END。 - 请你写出 repeat 的求值规则,并且写一个关于它的霍尔逻辑证明规则。 + 在这个练习中,我们会往 Imp 里面加一种新的命令:REPEAT c UNTIL b END。 + 请你写出 REPEAT 的求值规则,并且写一个关于它的霍尔逻辑证明规则。 (回想在 Auto 中给出的规则,试着自己把这个写出来,别偷看。)@@ -2046,7 +2060,7 @@Hoare霍尔逻辑(第一部分)< (CAsgn X a) (at level 60).
Notation "'WHILE' b 'DO' c 'END'" :=
(CWhile b c) (at level 80, right associativity).
-Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" :=
+Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" :=
(CIf e1 e2 e3) (at level 80, right associativity).
Notation "'REPEAT' e1 'UNTIL' b2 'END'" :=
(CRepeat e1 b2) (at level 80, right associativity).
@@ -2059,34 +2073,36 @@Hoare霍尔逻辑(第一部分)<
+Reserved Notation "st '=[' c ']⇒' st'" (at level 40).
Inductive ceval : state → com → state → Prop :=
- | E_Skip : ∀ st,
- ceval st SKIP st
- | E_Ass : ∀ st a1 n X,
+ | E_Skip : ∀st,
+ st =[ SKIP ]⇒ st
+ | E_Ass : ∀st a1 n x,
aeval st a1 = n →
- ceval st (X ::= a1) (st & { X --> n })
- | E_Seq : ∀ c1 c2 st st' st'',
- ceval st c1 st' →
- ceval st' c2 st'' →
- ceval st (c1 ;; c2) st''
- | E_IfTrue : ∀ st st' b1 c1 c2,
- beval st b1 = true →
- ceval st c1 st' →
- ceval st (IFB b1 THEN c1 ELSE c2 FI) st'
- | E_IfFalse : ∀ st st' b1 c1 c2,
- beval st b1 = false →
- ceval st c2 st' →
- ceval st (IFB b1 THEN c1 ELSE c2 FI) st'
- | E_WhileFalse : ∀ b1 st c1,
- beval st b1 = false →
- ceval st (WHILE b1 DO c1 END) st
- | E_WhileTrue : ∀ st st' st'' b1 c1,
- beval st b1 = true →
- ceval st c1 st' →
- ceval st' (WHILE b1 DO c1 END) st'' →
- ceval st (WHILE b1 DO c1 END) st''
+ st =[ x ::= a1 ]⇒ (x !-> n ; st)
+ | E_Seq : ∀c1 c2 st st' st'',
+ st =[ c1 ]⇒ st' →
+ st' =[ c2 ]⇒ st'' →
+ st =[ c1 ;; c2 ]⇒ st''
+ | E_IfTrue : ∀st st' b c1 c2,
+ beval st b = true →
+ st =[ c1 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_IfFalse : ∀st st' b c1 c2,
+ beval st b = false →
+ st =[ c2 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_WhileFalse : ∀b st c,
+ beval st b = false →
+ st =[ WHILE b DO c END ]⇒ st
+ | E_WhileTrue : ∀st st' st'' b c,
+ beval st b = true →
+ st =[ c ]⇒ st' →
+ st' =[ WHILE b DO c END ]⇒ st'' →
+ st =[ WHILE b DO c END ]⇒ st''
(* 请在此处解答 *)
-.
+
+where "st '=[' c ']⇒' st'" := (ceval st c st').
@@ -2094,11 +2110,9 @@Hoare霍尔逻辑(第一部分)<
-Notation "c1 '/' st '\\' st'" := (ceval st c1 st')@@ -2115,7 +2129,7 @@
- (at level 40, st at level 39).
-Definition hoare_triple (P:Assertion) (c:com) (Q:Assertion)
+Definition hoare_triple (P : Assertion) (c : com) (Q : Assertion)
: Prop :=
- ∀ st st', (c / st \\ st') → P st → Q st'.
+ ∀st st', st =[ c ]⇒ st' → P st → Q st'.
Notation "{{ P }} c {{ Q }}" :=
(hoare_triple P c Q) (at level 90, c at next level).
Hoare霍尔逻辑(第一部分)< Y ::= Y + 1
UNTIL X = 1 END.
Theorem ex1_repeat_works :
- ex1_repeat / { --> 0 } \\ { X --> 1 ; Y --> 1 }.
+ empty_st =[ ex1_repeat ]⇒ (Y !-> 1 ; X !-> 1).
Proof.
(* 请在此处解答 *) Admitted.
Hoare霍尔逻辑(第一部分)<
- {{Q [X |-> a]}} X::=a {{Q}} +{{Q [X ⊢> a]}} X::=a {{Q}} @@ -2209,11 +2223,11 @@
Hoare霍尔逻辑(第一部分)<
- {{P ∧ b}} c1 {{Q}} +{{P ∧ b}} c1 {{Q}} - @@ -2221,7 +2235,7 @@{{P ∧ ~b}} c2 {{Q}} +{{P ∧ ¬b}} c2 {{Q}} (hoare_if) Hoare霍尔逻辑(第一部分)<
- {{P}} IFB b THEN c1 ELSE c2 FI {{Q}} +{{P}} TEST b THEN c1 ELSE c2 FI {{Q}} @@ -2234,7 +2248,7 @@
Hoare霍尔逻辑(第一部分)<
- {{P}} WHILE b DO c END {{P ∧ ~b}} +{{P}} WHILE b DO c END {{P ∧ ¬b}} @@ -2243,11 +2257,11 @@
Hoare霍尔逻辑(第一部分)<
- P ->> P' +P ->> P' - @@ -2266,7 +2280,7 @@Q' ->> Q +Q' ->> Q (hoare_consequence) Hoare霍尔逻辑(第一部分)<
-练习:3 星 (hoare_havoc)
+练习:3 星, standard (hoare_havoc)
在这个练习中我们将会为一种 HAVOC 命令实现证明规则,这个命令类似于 Imp 中的 any 表达式。 @@ -2293,33 +2307,40 @@Hoare霍尔逻辑(第一部分)< (CSeq c1 c2) (at level 80, right associativity).
Notation "'WHILE' b 'DO' c 'END'" :=
(CWhile b c) (at level 80, right associativity).
-Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" :=
+Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" :=
(CIf e1 e2 e3) (at level 80, right associativity).
Notation "'HAVOC' X" := (CHavoc X) (at level 60).
-Reserved Notation "c1 '/' st '\\' st'" (at level 40, st at level 39).
+Reserved Notation "st '=[' c ']⇒' st'" (at level 40).
Inductive ceval : com → state → state → Prop :=
- | E_Skip : ∀ st : state, SKIP / st \\ st
- | E_Ass : ∀ (st : state) (a1 : aexp) (n : nat) (X : string),
- aeval st a1 = n → (X ::= a1) / st \\ st & { X --> n }
- | E_Seq : ∀ (c1 c2 : com) (st st' st'' : state),
- c1 / st \\ st' → c2 / st' \\ st'' → (c1 ;; c2) / st \\ st''
- | E_IfTrue : ∀ (st st' : state) (b1 : bexp) (c1 c2 : com),
- beval st b1 = true →
- c1 / st \\ st' → (IFB b1 THEN c1 ELSE c2 FI) / st \\ st'
- | E_IfFalse : ∀ (st st' : state) (b1 : bexp) (c1 c2 : com),
- beval st b1 = false →
- c2 / st \\ st' → (IFB b1 THEN c1 ELSE c2 FI) / st \\ st'
- | E_WhileFalse : ∀ (b1 : bexp) (st : state) (c1 : com),
- beval st b1 = false → (WHILE b1 DO c1 END) / st \\ st
- | E_WhileTrue : ∀ (st st' st'' : state) (b1 : bexp) (c1 : com),
- beval st b1 = true →
- c1 / st \\ st' →
- (WHILE b1 DO c1 END) / st' \\ st'' →
- (WHILE b1 DO c1 END) / st \\ st''
- | E_Havoc : ∀ (st : state) (X : string) (n : nat),
- (HAVOC X) / st \\ st & { X --> n }
+ | E_Skip : ∀st,
+ st =[ SKIP ]⇒ st
+ | E_Ass : ∀st a1 n x,
+ aeval st a1 = n →
+ st =[ x ::= a1 ]⇒ (x !-> n ; st)
+ | E_Seq : ∀c1 c2 st st' st'',
+ st =[ c1 ]⇒ st' →
+ st' =[ c2 ]⇒ st'' →
+ st =[ c1 ;; c2 ]⇒ st''
+ | E_IfTrue : ∀st st' b c1 c2,
+ beval st b = true →
+ st =[ c1 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_IfFalse : ∀st st' b c1 c2,
+ beval st b = false →
+ st =[ c2 ]⇒ st' →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ st'
+ | E_WhileFalse : ∀b st c,
+ beval st b = false →
+ st =[ WHILE b DO c END ]⇒ st
+ | E_WhileTrue : ∀st st' st'' b c,
+ beval st b = true →
+ st =[ c ]⇒ st' →
+ st' =[ WHILE b DO c END ]⇒ st'' →
+ st =[ WHILE b DO c END ]⇒ st''
+ | E_Havoc : ∀st X n,
+ st =[ HAVOC X ]⇒ (X !-> n ; st)
- where "c1 '/' st '\\' st'" := (ceval c1 st st').
+where "st '=[' c ']⇒' st'" := (ceval c st st').
@@ -2328,7 +2349,7 @@diff --git a/plf-current/Hoare.v b/plf-current/Hoare.v index e142b314..4beda4f3 100644 --- a/plf-current/Hoare.v +++ b/plf-current/Hoare.v @@ -1,15 +1,13 @@ (** * Hoare: 霍尔逻辑(第一部分) *) -(** Remove "Nat." - *) Set Warnings "-notation-overridden,-parsing". -Require Import Coq.Bool.Bool. -Require Import Coq.Arith.Arith. -Require Import Coq.Arith.EqNat. -Require Import Coq.Arith.PeanoNat. Import Nat. -Require Import Coq.omega.Omega. -From PLF Require Import Imp. From PLF Require Import Maps. +From Coq Require Import Bool.Bool. +From Coq Require Import Arith.Arith. +From Coq Require Import Arith.EqNat. +From Coq Require Import Arith.PeanoNat. Import Nat. +From Coq Require Import omega.Omega. +From PLF Require Import Imp. (** 在_'逻辑基础'_(_'软件基础'_ 的第一章) 中, 我们用课程前面的部分中学习的数学工具研究了一个小型编程语言 Imp 。 @@ -62,7 +60,8 @@ From PLF Require Import Maps. ;和一种用来证明程序正确地实现了规范的_'复合证明技巧(compositional proof technique)'_ ——其中“复合”的意思是,这些证明的结构直接反映了相应程序的结构。*) -(** 在这一章里: +(** 本章概览... + 主题: - 推理 Imp 程序_'功能正确性(functional correctness)'_ 的系统方法 目标: @@ -86,8 +85,9 @@ From PLF Require Import Maps. Definition Assertion := state -> Prop. -(** **** 练习:1 星, optional (assertions) *) -(** 用中文重新表述下列断言(或者用你最喜欢的语言)。 *) +(** **** 练习:1 星, standard, optional (assertions) + + 用中文重新表述下列断言(或者用你最喜欢的语言)。 *) Module ExAssertions. Definition as1 : Assertion := fun st => st X = 3. @@ -108,8 +108,7 @@ End ExAssertions. (2) 状态 [st] 是唯一我们希望用来再断言中查找变量的状态(我们将不会 讨论在同一时间的两种不同状态。 当我们非正式地讨论某些例子的时候,我们会简化一下:我们把开头的 - [fun st =>] 去掉,并且用 [X] 来代替 [st X] 所以,我们将把*) -(** + [fun st =>] 去掉,并且用 [X] 来代替 [st X] 所以,我们将把 fun st => (st Z) * (st Z) <= m /\ ~ ((S (st Z)) * (S (st Z)) <= m) @@ -161,9 +160,9 @@ Notation "P <<->> Q" := (** 形式化地: *) Definition hoare_triple - (P:Assertion) (c:com) (Q:Assertion) : Prop := + (P : Assertion) (c : com) (Q : Assertion) : Prop := forall st st', - c / st \\ st' -> + st =[ c ]=> st' -> P st -> Q st'. @@ -171,16 +170,17 @@ Definition hoare_triple 利的: {{P}} c {{Q}}. -*) -(** (传统的记号是 [{P} c {Q}],不过单花括号已经被用在 Coq 中其 + + (传统的记号是 [{P} c {Q}],不过单花括号已经被用在 Coq 中其 它东西上了。*) Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q) (at level 90, c at next level) : hoare_spec_scope. -(** **** 练习:1 星, optional (triples) *) -(** 用中文重新表述下列霍尔三元组。 +(** **** 练习:1 星, standard, optional (triples) + + 用中文重新表述下列霍尔三元组。 1) {{True}} c {{X = 5}} @@ -198,18 +198,20 @@ Notation "{{ P }} c {{ Q }}" := c {{(Z * Z) <= m /\ ~ (((S Z) * (S Z)) <= m)}} *) +(* 请在此处解答 -(** [] *) + [] *) -(** **** 练习:1 星, optional (valid_triples) *) -(** 下列的霍尔三元组是否_'有效'_,亦即,表述的 [P]、[c]、[Q] 之间的 +(** **** 练习:1 星, standard, optional (valid_triples) + + 下列的霍尔三元组是否_'有效'_,亦即,表述的 [P]、[c]、[Q] 之间的 关系是否为真? 1) {{True}} X ::= 5 {{X = 5}} 2) {{X = 2}} X ::= X + 1 {{X = 3}} - 3) {{True}} X ::= 5; Y ::= 0 {{X = 5}} + 3) {{True}} X ::= 5;; Y ::= 0 {{X = 5}} 4) {{X = 2 /\ X = 3}} X ::= 5 {{X = 0}} @@ -224,10 +226,12 @@ Notation "{{ P }} c {{ Q }}" := {{X = 1}} 9) {{X = 1}} - WHILE !(X = 0) DO X ::= X + 1 END + WHILE ~(X = 0) DO X ::= X + 1 END {{X = 100}} *) -(** [] *) +(* 请在此处解答 + + [] *) (** 为了热身,这里有两个关于霍尔三元组的简单定理。 (确保你弄懂它们的意思。)*) @@ -241,7 +245,7 @@ Proof. apply H. Qed. Theorem hoare_pre_false : forall (P Q : Assertion) c, - (forall st, ~(P st)) -> + (forall st, ~ (P st)) -> {{P}} c {{Q}}. Proof. intros P Q c H. unfold hoare_triple. @@ -282,7 +286,7 @@ Proof. (** 更一般地, 如果 [a] 是_'任意'_算术表达式,那么 - {{ a = 1 }} X ::= a {{ X = 1 }} + {{ a = 1 }} X ::= a {{ X = 1 }} 是一个有效的霍尔三元组。 *) @@ -302,12 +306,12 @@ Proof. {{ X <= 5 }} {{ (X = 3) [X |-> 3] - i.e., 3 = 3}} + i.e., 3 = 3 }} X ::= 3 {{ X = 3 }} {{ (0 <= X /\ X <= 5) [X |-> 3] - i.e., (0 <= 3 /\ 3 <= 5)}} + i.e., (0 <= 3 /\ 3 <= 5) }} X ::= 3 {{ 0 <= X /\ X <= 5 }} *) @@ -323,9 +327,10 @@ Proof. Definition assn_sub X a P : Assertion := fun (st : state) => - P (st & { X --> aeval st a }). + P (X !-> aeval st a ; st). -Notation "P [ X |-> a ]" := (assn_sub X a P) (at level 10). +Notation "P [ X |-> a ]" := (assn_sub X a P) + (at level 10, X at next level). (** 也就是说,[P [X |-> a]] 是一个新的断言——我们把它叫做 [P'] —— 它就是 [P],不过当 [P] 在当前状态中查找变量 [X] 的时候,[P'] 使用表 @@ -336,18 +341,18 @@ Notation "P [ X |-> a ]" := (assn_sub X a P) (at level 10). fun st => (fun st' => st' X <= 5) - (st & { X --> aeval st 3 }) + (X !-> aeval st 3 ; st), 它简化为 fun st => (fun st' => st' X <= 5) - (st & { X --> 3 }) + (X !-> 3 ; st) 并且可以进一步简化为 fun st => - ((st & { X --> 3 }) X) <= 5 + ((X !-> 3 ; st) X) <= 5 最终是 @@ -356,24 +361,24 @@ Notation "P [ X |-> a ]" := (assn_sub X a P) (at level 10). 也就是说,[P'] 是一个断言指出 [3] 小于等于 [5](像我们想的一样)。*) -(** 一个更有趣的例子是,假设 [P'] 是 [(X <= 5) [X |-> X+1]]。形式化地,[P'] +(** 一个更有趣的例子是,假设 [P'] 是 [(X <= 5) [X |-> X + 1]]。形式化地,[P'] 是 Coq 表达式 fun st => (fun st' => st' X <= 5) - (st & { X --> aeval st (X+1) }), + (X !-> aeval st (X + 1) ; st), 它简化为 fun st => - (st & { X --> aeval st (X+1) }) X <= 5 + (X !-> aeval st (X + 1) ; st) X <= 5 并且进一步简化为 fun st => - (aeval st (X+1)) <= 5. + (aeval st (X + 1)) <= 5. - 也就是说,[P'] 指出 [X+1] 最多是 [5]。 + 也就是说,[P'] 指出 [X + 1] 最多是 [5]。 *) (** 现在,利用替换的概念,我们可以给出下述赋值证明规则的严谨证明: @@ -385,7 +390,7 @@ Notation "P [ X |-> a ]" := (assn_sub X a P) (at level 10). (** 我们可以形式化地证明这个规则是正确的。*) Theorem hoare_asgn : forall Q X a, - {{Q [X |-> a]}} (X ::= a) {{Q}}. + {{Q [X |-> a]}} X ::= a {{Q}}. Proof. unfold hoare_triple. intros Q X a st st' HE HQ. @@ -395,8 +400,8 @@ Proof. (** 下述是一个利用这个规则的形式化证明。*) Example assn_sub_example : - {{(fun st => st X < 5) [X |-> X+1]}} - (X ::= X+1) + {{(fun st => st X < 5) [X |-> X + 1]}} + X ::= X + 1 {{fun st => st X < 5}}. Proof. (* 课上已完成 *) @@ -404,12 +409,13 @@ Proof. (** 当然,更加有帮助的是证明这个更简单的三元组: - {{X < 4}} (X ::= X+1) {{X < 5}} + {{X < 4}} X ::= X + 1 {{X < 5}} 我们会在下一节中了解怎么做。*) -(** **** 练习:2 星 (hoare_asgn_examples) *) -(** 将下列非正式的霍尔三元组…… +(** **** 练习:2 星, standard (hoare_asgn_examples) + + 将下列非正式的霍尔三元组…… 1) {{ (X <= 10) [X |-> 2 * X] }} X ::= 2 * X @@ -428,8 +434,9 @@ Proof. Definition manual_grade_for_hoare_asgn_examples : option (nat*string) := None. (** [] *) -(** **** 练习:2 星, recommended (hoare_asgn_wrong) *) -(** 几乎所有人在看赋值规则第一眼就会觉得它是反向的。如果你还感觉很 +(** **** 练习:2 星, standard, recommended (hoare_asgn_wrong) + + 几乎所有人在看赋值规则第一眼就会觉得它是反向的。如果你还感觉很 迷惑,思考一些“正向”的规则可能有帮助。这里是一个看起来挺自然的 霍尔三元组: @@ -446,10 +453,9 @@ Definition manual_grade_for_hoare_asgn_examples : option (nat*string) := None. Definition manual_grade_for_hoare_asgn_wrong : option (nat*string) := None. (** [] *) -Local Close Scope aexp_scope. +(** **** 练习:3 星, advanced (hoare_asgn_fwd) -(** **** 练习:3 星, advanced (hoare_asgn_fwd) *) -(** 然而,通过引入一个_'参数'_ [m](一个 Coq 整数)来记录 [X] 原 + 然而,通过引入一个_'参数'_ [m](一个 Coq 整数)来记录 [X] 原 来的值,我们可以定义一个赋值的证明规则,它可以,直觉上讲,“正向地 工作”。 @@ -457,7 +463,7 @@ Local Close Scope aexp_scope. {{fun st => P st /\ st X = m}} X ::= a {{fun st => P st' /\ st X = aeval st' a }} - (其中 st' = st & { X --> m }) + (其中 st' = (X !-> m ; st)) 可以注意到,在赋值发生之前我们用 [X] 原来的值重新构造了状态 [st']。证明这个规则是正确的。(注意,这个规则比 [hoare_asgn] 复杂些。) @@ -467,29 +473,30 @@ Theorem hoare_asgn_fwd : forall m a P, {{fun st => P st /\ st X = m}} X ::= a - {{fun st => P (st & { X --> m }) - /\ st X = aeval (st & { X --> m }) a }}. + {{fun st => P (X !-> m ; st) + /\ st X = aeval (X !-> m ; st) a }}. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, advanced, optional (hoare_asgn_fwd_exists) *) -(** 另外一种定义正向赋值规则的方式是,对变量在赋值之前的值做存在量化。 +(** **** 练习:2 星, advanced, optional (hoare_asgn_fwd_exists) + + 另外一种定义正向赋值规则的方式是,对变量在赋值之前的值做存在量化。 证明这是正确的。 ------------------------------------ (hoare_asgn_fwd_exists) {{fun st => P st}} X ::= a - {{fun st => exists m, P (st & { X --> m }) /\ - st X = aeval (st & { X --> m }) a }} + {{fun st => exists m, P (X !-> m ; st) /\ + st X = aeval (X !-> m ; st) a }} *) Theorem hoare_asgn_fwd_exists : forall a P, {{fun st => P st}} X ::= a - {{fun st => exists m, P (st & { X --> m }) /\ - st X = aeval (st & { X --> m }) a }}. + {{fun st => exists m, P (X !-> m ; st) /\ + st X = aeval (X !-> m ; st) a }}. Proof. intros a P. (* 请在此处解答 *) Admitted. @@ -561,15 +568,15 @@ Proof. (** 例如,我们可以这样应用第一条规则: - {{ True }} ->> - {{ 1 = 1 }} + {{ True }} ->> + {{ 1 = 1 }} X ::= 1 - {{ X = 1 }} + {{ X = 1 }} 或者,形式化地:*) Example hoare_asgn_example1 : - {{fun st => True}} (X ::= 1) {{fun st => st X = 1}}. + {{fun st => True}} X ::= 1 {{fun st => st X = 1}}. Proof. (* 课上已完成 *) apply hoare_consequence_pre @@ -580,21 +587,21 @@ Qed. (** 我们也可以用它来证明之前提到的例子。 - {{ X < 4 }} ->> - {{ (X < 5)[X |-> X+1] }} + {{ X < 4 }} ->> + {{ (X < 5)[X |-> X + 1] }} X ::= X + 1 - {{ X < 5 }} + {{ X < 5 }} 或者,形式化地:*) Example assn_sub_example2 : {{(fun st => st X < 4)}} - (X ::= X+1) + X ::= X + 1 {{fun st => st X < 5}}. Proof. (* 课上已完成 *) apply hoare_consequence_pre - with (P' := (fun st => st X < 5) [X |-> X+1]). + with (P' := (fun st => st X < 5) [X |-> X + 1]). apply hoare_asgn. intros st H. unfold assn_sub, t_update. simpl. omega. Qed. @@ -639,7 +646,7 @@ Proof. Example hoare_asgn_example1' : {{fun st => True}} - (X ::= 1) + X ::= 1 {{fun st => st X = 1}}. Proof. eapply hoare_consequence_pre. @@ -683,10 +690,9 @@ Proof. (** 在这里使用 [apply HP'] 将会失败并产生如下错误: - Error: Impossible to unify "?175" with "y". + Error: Impossible to unify "?175" with "y". 有一个简单的解决办法:把 [destruct HP] 提到 [eapply HQ] _'之前'_。 *) - Abort. Lemma silly2_fixed : @@ -714,8 +720,9 @@ Proof. intros P Q HP HQ. destruct HP as [y HP']. eapply HQ. eassumption. Qed. -(** **** 练习:2 星 (hoare_asgn_examples_2) *) -(** 将下述的非形式化霍尔三元组 +(** **** 练习:2 星, standard (hoare_asgn_examples_2) + + 将下述的非形式化霍尔三元组 {{ X + 1 <= 5 }} X ::= X + 1 {{ X <= 5 }} {{ 0 <= 3 /\ 3 <= 5 }} X ::= 3 {{ 0 <= X /\ X <= 5 }} @@ -729,7 +736,6 @@ Qed. Definition manual_grade_for_hoare_asgn_examples_2 : option (nat*string) := None. (** [] *) - (* ================================================================= *) (** ** 跳过 *) @@ -755,7 +761,7 @@ Proof. {{ P }} c1 {{ Q }} {{ Q }} c2 {{ R }} - --------------------- (hoare_seq) + ---------------------- (hoare_seq) {{ P }} c1;;c2 {{ R }} *) @@ -779,7 +785,7 @@ Proof. {{ a = n }} X ::= a;; - {{ X = n }} <---- + {{ X = n }} <--- decoration for Q SKIP {{ X = n }} *) @@ -788,7 +794,7 @@ Proof. Example hoare_asgn_example3 : forall a n, {{fun st => aeval st a = n}} - (X ::= a;; SKIP) + X ::= a;; SKIP {{fun st => st X = n}}. Proof. intros a n. eapply hoare_seq. @@ -802,8 +808,9 @@ Qed. (** 我们一般会将 [hoare_seq] 和 [hoare_consequence_pre] 以及 [eapply] 策略一起使用,如上所示。*) -(** **** 练习:2 星, recommended (hoare_asgn_example4) *) -(** 将这个“标注程序”翻译成正式证明: +(** **** 练习:2 星, standard, recommended (hoare_asgn_example4) + + 将这个“标注程序”翻译成正式证明: {{ True }} ->> {{ 1 = 1 }} @@ -816,19 +823,23 @@ Qed. (带 “[->>]” 的标记代表了使用 [hoare_consequence_pre]。) *) Example hoare_asgn_example4 : - {{fun st => True}} (X ::= 1;; Y ::= 2) + {{fun st => True}} + X ::= 1;; Y ::= 2 {{fun st => st X = 1 /\ st Y = 2}}. Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (swap_exercise) *) -(** 写一个 Imp 程序 [c],用来交换变量 [X] 和 [Y] 并且说明 +(** **** 练习:3 星, standard (swap_exercise) + + 写一个 Imp 程序 [c],用来交换变量 [X] 和 [Y] 并且说明 它符合如下规范: {{X <= Y}} c {{Y <= X}} - 你的证明不应该使用 [unfold hoare_triple]。 *) + 你的证明不应该使用 [unfold hoare_triple]。 + (提示:记住赋值规则在“从后往前”,即从后置条件到前置条件应用时工作得最好。 + 因此你的证明可以从程序的后面开始逐步往前进行。) *) Definition swap_program : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. @@ -841,12 +852,13 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (hoarestate1) *) -(** 解释为何下列命题无法被证明: +(** **** 练习:3 星, standard (hoarestate1) + + 解释为何下列命题无法被证明: forall (a : aexp) (n : nat), {{fun st => aeval st a = n}} - (X ::= 3;; Y ::= a) + X ::= 3;; Y ::= a {{fun st => st Y = n}}. *) @@ -866,16 +878,16 @@ Definition manual_grade_for_hoarestate1 : option (nat*string) := None. {{P}} c1 {{Q}} {{P}} c2 {{Q}} - -------------------------------- - {{P}} IFB b THEN c1 ELSE c2 {{Q}} + --------------------------------- + {{P}} TEST b THEN c1 ELSE c2 {{Q}} *) (** 然而,这个规则太弱了。例如,用这个规则我们并不能推理出 {{ True }} - IFB X = 0 - THEN Y ::= 2 - ELSE Y ::= X + 1 + TEST X = 0 + THEN Y ::= 2 + ELSE Y ::= X + 1 FI {{ X <= Y }} @@ -884,13 +896,12 @@ Definition manual_grade_for_hoarestate1 : option (nat*string) := None. (** 不过我们还是可以表述得更精确。在“THEN”分支中,[b] 化简为 [true],而在“ELSE”分支中我们知道它化简为 [false]。 我们可以让这个信息作为 [c1] 和 [c2] 的假设出现可以让我们分别研究 - [c1] 和 [c2] 的行为(亦即它们为什么能导出后置条件 [Q])。*) -(** + [c1] 和 [c2] 的行为(亦即它们为什么能导出后置条件 [Q])。 - {{P /\ b}} c1 {{Q}} - {{P /\ ~b}} c2 {{Q}} + {{P /\ b}} c1 {{Q}} + {{P /\ ~ b}} c2 {{Q}} ------------------------------------ (hoare_if) - {{P}} IFB b THEN c1 ELSE c2 FI {{Q}} + {{P}} TEST b THEN c1 ELSE c2 FI {{Q}} *) (** 要形式化地解释这个规则,我们还需要做一点微小的工作。 @@ -921,8 +932,8 @@ Proof. Theorem hoare_if : forall P Q b c1 c2, {{fun st => P st /\ bassn b st}} c1 {{Q}} -> - {{fun st => P st /\ ~(bassn b st)}} c2 {{Q}} -> - {{P}} (IFB b THEN c1 ELSE c2 FI) {{Q}}. + {{fun st => P st /\ ~ (bassn b st)}} c2 {{Q}} -> + {{P}} TEST b THEN c1 ELSE c2 FI {{Q}}. Proof. intros P Q b c1 c2 HTrue HFalse st st' HE HP. inversion HE; subst. @@ -944,7 +955,7 @@ Proof. Example if_example : {{fun st => True}} - IFB X = 0 + TEST X = 0 THEN Y ::= 2 ELSE Y ::= X + 1 FI @@ -964,12 +975,13 @@ Proof. simpl; intros st _. omega. Qed. -(** **** 练习:2 星 (if_minus_plus) *) -(** 用 [hoare_if] 证明下面的三元组。不要使用 [unfold hoare_triple]。*) +(** **** 练习:2 星, standard (if_minus_plus) + + 用 [hoare_if] 证明下面的三元组。不要使用 [unfold hoare_triple]。*) Theorem if_minus_plus : {{fun st => True}} - IFB X <= Y + TEST X <= Y THEN Z ::= Y - X ELSE Y ::= X + Z FI @@ -981,8 +993,9 @@ Proof. (* ----------------------------------------------------------------- *) (** *** 练习:单侧条件 *) -(** **** 练习:4 星 (if1_hoare) *) -(** 在这个练习中我们考虑对 Imp 加入形如 [IF1 b THEN c FI] 的“单边条件”。 +(** **** 练习:4 星, standard (if1_hoare) + + 在这个练习中我们考虑对 Imp 加入形如 [IF1 b THEN c FI] 的“单边条件”。 这里 [b] 是个布尔表达式而 [c] 是一个命令。如果 [b] 化简为 [true], [c] 就被执行,而如果 [b] 化简为 [false], [IF1 b THEN c FI] 就啥也不做。 @@ -1003,51 +1016,61 @@ Inductive com : Type := | CIf1 : bexp -> com -> com. Notation "'SKIP'" := - CSkip. + CSkip : imp_scope. Notation "c1 ;; c2" := - (CSeq c1 c2) (at level 80, right associativity). + (CSeq c1 c2) (at level 80, right associativity) : imp_scope. Notation "X '::=' a" := - (CAss X a) (at level 60). + (CAss X a) (at level 60) : imp_scope. Notation "'WHILE' b 'DO' c 'END'" := - (CWhile b c) (at level 80, right associativity). -Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" := - (CIf e1 e2 e3) (at level 80, right associativity). + (CWhile b c) (at level 80, right associativity) : imp_scope. +Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" := + (CIf e1 e2 e3) (at level 80, right associativity) : imp_scope. Notation "'IF1' b 'THEN' c 'FI'" := - (CIf1 b c) (at level 80, right associativity). + (CIf1 b c) (at level 80, right associativity) : imp_scope. (** 接下来我们需要拓展求值规则以包含 [IF1] 的情形。我们把任务交给你…… 应该网 [ceval] 中加入哪条(那些)命令来化简单边分支命令?*) -Reserved Notation "c1 '/' st '\\' st'" (at level 40, st at level 39). +Reserved Notation "st '=[' c ']=>' st'" (at level 40). +Open Scope imp_scope. Inductive ceval : com -> state -> state -> Prop := - | E_Skip : forall st : state, SKIP / st \\ st - | E_Ass : forall (st : state) (a1 : aexp) (n : nat) (X : string), - aeval st a1 = n -> (X ::= a1) / st \\ st & { X --> n } - | E_Seq : forall (c1 c2 : com) (st st' st'' : state), - c1 / st \\ st' -> c2 / st' \\ st'' -> (c1 ;; c2) / st \\ st'' - | E_IfTrue : forall (st st' : state) (b1 : bexp) (c1 c2 : com), - beval st b1 = true -> - c1 / st \\ st' -> (IFB b1 THEN c1 ELSE c2 FI) / st \\ st' - | E_IfFalse : forall (st st' : state) (b1 : bexp) (c1 c2 : com), - beval st b1 = false -> - c2 / st \\ st' -> (IFB b1 THEN c1 ELSE c2 FI) / st \\ st' - | E_WhileFalse : forall (b1 : bexp) (st : state) (c1 : com), - beval st b1 = false -> (WHILE b1 DO c1 END) / st \\ st - | E_WhileTrue : forall (st st' st'' : state) (b1 : bexp) (c1 : com), - beval st b1 = true -> - c1 / st \\ st' -> - (WHILE b1 DO c1 END) / st' \\ st'' -> - (WHILE b1 DO c1 END) / st \\ st'' + | E_Skip : forall st, + st =[ SKIP ]=> st + | E_Ass : forall st a1 n x, + aeval st a1 = n -> + st =[ x ::= a1 ]=> (x !-> n ; st) + | E_Seq : forall c1 c2 st st' st'', + st =[ c1 ]=> st' -> + st' =[ c2 ]=> st'' -> + st =[ c1 ;; c2 ]=> st'' + | E_IfTrue : forall st st' b c1 c2, + beval st b = true -> + st =[ c1 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_IfFalse : forall st st' b c1 c2, + beval st b = false -> + st =[ c2 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_WhileFalse : forall b st c, + beval st b = false -> + st =[ WHILE b DO c END ]=> st + | E_WhileTrue : forall st st' st'' b c, + beval st b = true -> + st =[ c ]=> st' -> + st' =[ WHILE b DO c END ]=> st'' -> + st =[ WHILE b DO c END ]=> st'' (* 请在此处解答 *) - where "c1 '/' st '\\' st'" := (ceval c1 st st'). + where "st '=[' c ']=>' st'" := (ceval c st st'). +Close Scope imp_scope. (** 现在我们把霍尔三元组的定义和记号重新写在这里。*) -Definition hoare_triple (P:Assertion) (c:com) (Q:Assertion) : Prop := +Definition hoare_triple + (P : Assertion) (c : com) (Q : Assertion) : Prop := forall st st', - c / st \\ st' -> + st =[ c ]=> st' -> P st -> Q st'. @@ -1064,7 +1087,7 @@ Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q) 能够证明下列的霍尔三元组是有效的: {{ X + Y = Z }} - IF1 !(Y = 0) THEN + IF1 ~(Y = 0) THEN X ::= X + Y FI {{ X = Z }} @@ -1075,9 +1098,9 @@ Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q) Lemma hoare_if1_good : {{ fun st => st X + st Y = st Z }} - IF1 !(Y = 0) THEN + (IF1 ~(Y = 0) THEN X ::= X + Y - FI + FI)%imp {{ fun st => st X = st Z }}. Proof. (* 请在此处解答 *) Admitted. @@ -1114,35 +1137,33 @@ Definition manual_grade_for_if1_hoare : option (nat*string) := None. (** 不过就像我们在上面对条件语句分析时那样,我们还会有一点附加 的信息:除了 [P] 成立以外,[b] 会在执行完毕以后化简为 [false]。 - 所以,我们可以再添补一下后置条件: *) -(** + 所以,我们可以再添补一下后置条件: - {{P}} WHILE b DO c END {{P /\ ~b}} + {{P}} WHILE b DO c END {{P /\ ~ b}} *) (** 那么循环体被执行的情形呢?为了确保 [P] 在循环最终退出 的时候成立,我们当然需要保证命令 [c] 执行后 [P] 成立。 进一步说,因为 [P] 在 [c] 第一次执行前成立,每次 [c] 执行完成 都会重新满足作为后置条件的 [P],我们可以假设 [P] 在 [c] 执行前 - 就成立。总结为以下规则:*) -(** + 就成立。总结为以下规则: {{P}} c {{P}} ----------------------------------- - {{P}} WHILE b DO c END {{P /\ ~b}} -*) -(** 这几乎就是我们想要的规则,不过它还有一点可以改进的地方:在循环体 + {{P}} WHILE b DO c END {{P /\ ~ b}} + + 这几乎就是我们想要的规则,不过它还有一点可以改进的地方:在循环体 开始是的时候,我们不止知道 [P] 成立,还有条件 [b] 会在当前状态 中化简为 [true]。*) (** 这给我们带来了一点额外的信息用来推论 [c] (用来说明它结束时 - 满足不变式)。*) -(** 这让我们可以给出这个规则的最终版本:*) -(** + 满足不变式)。 + + 而这会将我们导向此规则的最终版本: {{P /\ b}} c {{P}} - ----------------------------------- (hoare_while) - {{P}} WHILE b DO c END {{P /\ ~b}} + ---------------------------------- (hoare_while) + {{P}} WHILE b DO c END {{P /\ ~ b}} 断言 [P] 叫做_'循环不变式(invariant of the loop)'_。 *) @@ -1154,7 +1175,7 @@ Proof. intros P b c Hhoare st st' He HP. (* 像之前见到过的,我们需要对 [He] 做归纳来推理。 因为,在“继续循环”的情形中,假设会是关于整个循环而不只是关于 [c] 的。*) - remember (WHILE b DO c END) as wcom eqn:Heqwcom. + remember (WHILE b DO c END)%imp as wcom eqn:Heqwcom. induction He; try (inversion Heqwcom); subst; clear Heqwcom. - (* E_WhileFalse *) @@ -1165,7 +1186,6 @@ Proof. split. assumption. apply bexp_eval_true. assumption. Qed. - (** 令人费解的事情是,我们把断言 [P] 叫做“循环不变式” 并不代表它只是由 (上述问题中的)循环体所保证(也就是 [{{P}} c {{P}}],其中 [c] 是循环体), 而实际上 [P] _'加上循环条件为真'_才是 [c] 能够推出后置条件所 @@ -1174,7 +1194,7 @@ Qed. 这是略微弱化的(但十分重要)前提。例如,如果 [P] 是断言 [X = 0],那么 [P] _'是'_下述循环的不变式: - WHILE X = 2 DO X := 1 END + WHILE X = 2 DO X := 1 END 即使它很明显_'不是'_只由循环体所导出。*) @@ -1224,9 +1244,10 @@ Proof. (* ----------------------------------------------------------------- *) (** *** 练习:[REPEAT] *) -(** **** 练习:4 星, advanced (hoare_repeat) *) -(** 在这个练习中,我们会往 Imp 里面加一种新的命令:[REPEAT] c [UNTIL] a [END]。 - 请你写出 [repeat] 的求值规则,并且写一个关于它的霍尔逻辑证明规则。 +(** **** 练习:4 星, advanced (hoare_repeat) + + 在这个练习中,我们会往 Imp 里面加一种新的命令:[REPEAT] c [UNTIL] b [END]。 + 请你写出 [REPEAT] 的求值规则,并且写一个关于它的霍尔逻辑证明规则。 (回想在 [Auto] 中给出的规则,试着自己把这个写出来,别偷看。)*) Module RepeatExercise. @@ -1251,7 +1272,7 @@ Notation "X '::=' a" := (CAsgn X a) (at level 60). Notation "'WHILE' b 'DO' c 'END'" := (CWhile b c) (at level 80, right associativity). -Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" := +Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" := (CIf e1 e2 e3) (at level 80, right associativity). Notation "'REPEAT' e1 'UNTIL' b2 'END'" := (CRepeat e1 b2) (at level 80, right associativity). @@ -1260,43 +1281,43 @@ Notation "'REPEAT' e1 'UNTIL' b2 'END'" := 模板,不过注意 [REPEAT] 的循环体至少要执行一次,并且循环会在条件 为真的时候结束。*) +Reserved Notation "st '=[' c ']=>' st'" (at level 40). + Inductive ceval : state -> com -> state -> Prop := | E_Skip : forall st, - ceval st SKIP st - | E_Ass : forall st a1 n X, + st =[ SKIP ]=> st + | E_Ass : forall st a1 n x, aeval st a1 = n -> - ceval st (X ::= a1) (st & { X --> n }) + st =[ x ::= a1 ]=> (x !-> n ; st) | E_Seq : forall c1 c2 st st' st'', - ceval st c1 st' -> - ceval st' c2 st'' -> - ceval st (c1 ;; c2) st'' - | E_IfTrue : forall st st' b1 c1 c2, - beval st b1 = true -> - ceval st c1 st' -> - ceval st (IFB b1 THEN c1 ELSE c2 FI) st' - | E_IfFalse : forall st st' b1 c1 c2, - beval st b1 = false -> - ceval st c2 st' -> - ceval st (IFB b1 THEN c1 ELSE c2 FI) st' - | E_WhileFalse : forall b1 st c1, - beval st b1 = false -> - ceval st (WHILE b1 DO c1 END) st - | E_WhileTrue : forall st st' st'' b1 c1, - beval st b1 = true -> - ceval st c1 st' -> - ceval st' (WHILE b1 DO c1 END) st'' -> - ceval st (WHILE b1 DO c1 END) st'' + st =[ c1 ]=> st' -> + st' =[ c2 ]=> st'' -> + st =[ c1 ;; c2 ]=> st'' + | E_IfTrue : forall st st' b c1 c2, + beval st b = true -> + st =[ c1 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_IfFalse : forall st st' b c1 c2, + beval st b = false -> + st =[ c2 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_WhileFalse : forall b st c, + beval st b = false -> + st =[ WHILE b DO c END ]=> st + | E_WhileTrue : forall st st' st'' b c, + beval st b = true -> + st =[ c ]=> st' -> + st' =[ WHILE b DO c END ]=> st'' -> + st =[ WHILE b DO c END ]=> st'' (* 请在此处解答 *) -. -(** 下面是一些之前出现的定义,我们把它重新写一遍它就会用新的 [ceval]。 *) +where "st '=[' c ']=>' st'" := (ceval st c st'). -Notation "c1 '/' st '\\' st'" := (ceval st c1 st') - (at level 40, st at level 39). +(** 下面是一些之前出现的定义,我们把它重新写一遍它就会用新的 [ceval]。 *) -Definition hoare_triple (P:Assertion) (c:com) (Q:Assertion) +Definition hoare_triple (P : Assertion) (c : com) (Q : Assertion) : Prop := - forall st st', (c / st \\ st') -> P st -> Q st'. + forall st st', st =[ c ]=> st' -> P st -> Q st'. Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q) (at level 90, c at next level). @@ -1311,7 +1332,7 @@ Definition ex1_repeat := UNTIL X = 1 END. Theorem ex1_repeat_works : - ex1_repeat / { --> 0 } \\ { X --> 1 ; Y --> 1 }. + empty_st =[ ex1_repeat ]=> (Y !-> 1 ; X !-> 1). Proof. (* 请在此处解答 *) Admitted. @@ -1344,7 +1365,7 @@ Definition manual_grade_for_hoare_repeat : option (nat*string) := None. (** 到此为止,我们引入了用来推理 Imp 程序的工具,霍尔逻辑。霍尔逻辑 的证明规则有: - ------------------------------ (hoare_asgn) + --------------------------- (hoare_asgn) {{Q [X |-> a]}} X::=a {{Q}} -------------------- (hoare_skip) @@ -1352,17 +1373,17 @@ Definition manual_grade_for_hoare_repeat : option (nat*string) := None. {{ P }} c1 {{ Q }} {{ Q }} c2 {{ R }} - --------------------- (hoare_seq) + ---------------------- (hoare_seq) {{ P }} c1;;c2 {{ R }} - {{P /\ b}} c1 {{Q}} - {{P /\ ~b}} c2 {{Q}} + {{P /\ b}} c1 {{Q}} + {{P /\ ~ b}} c2 {{Q}} ------------------------------------ (hoare_if) - {{P}} IFB b THEN c1 ELSE c2 FI {{Q}} + {{P}} TEST b THEN c1 ELSE c2 FI {{Q}} {{P /\ b}} c {{P}} ----------------------------------- (hoare_while) - {{P}} WHILE b DO c END {{P /\ ~b}} + {{P}} WHILE b DO c END {{P /\ ~ b}} {{P'}} c {{Q'}} P ->> P' @@ -1375,9 +1396,9 @@ Definition manual_grade_for_hoare_repeat : option (nat*string) := None. (* ################################################################# *) (** * 附加练习 *) +(** **** 练习:3 星, standard (hoare_havoc) -(** **** 练习:3 星 (hoare_havoc) *) -(** 在这个练习中我们将会为一种 [HAVOC] 命令实现证明规则,这个命令类似于 + 在这个练习中我们将会为一种 [HAVOC] 命令实现证明规则,这个命令类似于 [Imp] 中的 [any] 表达式。 首先我们把这些命令放在一个分离的模块里,并且把命令的语法和粗略语义 @@ -1401,40 +1422,47 @@ Notation "c1 ;; c2" := (CSeq c1 c2) (at level 80, right associativity). Notation "'WHILE' b 'DO' c 'END'" := (CWhile b c) (at level 80, right associativity). -Notation "'IFB' e1 'THEN' e2 'ELSE' e3 'FI'" := +Notation "'TEST' e1 'THEN' e2 'ELSE' e3 'FI'" := (CIf e1 e2 e3) (at level 80, right associativity). Notation "'HAVOC' X" := (CHavoc X) (at level 60). -Reserved Notation "c1 '/' st '\\' st'" (at level 40, st at level 39). +Reserved Notation "st '=[' c ']=>' st'" (at level 40). Inductive ceval : com -> state -> state -> Prop := - | E_Skip : forall st : state, SKIP / st \\ st - | E_Ass : forall (st : state) (a1 : aexp) (n : nat) (X : string), - aeval st a1 = n -> (X ::= a1) / st \\ st & { X --> n } - | E_Seq : forall (c1 c2 : com) (st st' st'' : state), - c1 / st \\ st' -> c2 / st' \\ st'' -> (c1 ;; c2) / st \\ st'' - | E_IfTrue : forall (st st' : state) (b1 : bexp) (c1 c2 : com), - beval st b1 = true -> - c1 / st \\ st' -> (IFB b1 THEN c1 ELSE c2 FI) / st \\ st' - | E_IfFalse : forall (st st' : state) (b1 : bexp) (c1 c2 : com), - beval st b1 = false -> - c2 / st \\ st' -> (IFB b1 THEN c1 ELSE c2 FI) / st \\ st' - | E_WhileFalse : forall (b1 : bexp) (st : state) (c1 : com), - beval st b1 = false -> (WHILE b1 DO c1 END) / st \\ st - | E_WhileTrue : forall (st st' st'' : state) (b1 : bexp) (c1 : com), - beval st b1 = true -> - c1 / st \\ st' -> - (WHILE b1 DO c1 END) / st' \\ st'' -> - (WHILE b1 DO c1 END) / st \\ st'' - | E_Havoc : forall (st : state) (X : string) (n : nat), - (HAVOC X) / st \\ st & { X --> n } - - where "c1 '/' st '\\' st'" := (ceval c1 st st'). + | E_Skip : forall st, + st =[ SKIP ]=> st + | E_Ass : forall st a1 n x, + aeval st a1 = n -> + st =[ x ::= a1 ]=> (x !-> n ; st) + | E_Seq : forall c1 c2 st st' st'', + st =[ c1 ]=> st' -> + st' =[ c2 ]=> st'' -> + st =[ c1 ;; c2 ]=> st'' + | E_IfTrue : forall st st' b c1 c2, + beval st b = true -> + st =[ c1 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_IfFalse : forall st st' b c1 c2, + beval st b = false -> + st =[ c2 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' + | E_WhileFalse : forall b st c, + beval st b = false -> + st =[ WHILE b DO c END ]=> st + | E_WhileTrue : forall st st' st'' b c, + beval st b = true -> + st =[ c ]=> st' -> + st' =[ WHILE b DO c END ]=> st'' -> + st =[ WHILE b DO c END ]=> st'' + | E_Havoc : forall st X n, + st =[ HAVOC X ]=> (X !-> n ; st) + +where "st '=[' c ']=>' st'" := (ceval c st st'). (** 对霍尔三元组的定义和之前完全一致。 *) Definition hoare_triple (P:Assertion) (c:com) (Q:Assertion) : Prop := - forall st st', c / st \\ st' -> P st -> Q st'. + forall st st', st =[ c ]=> st' -> P st -> Q st'. Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q) (at level 90, c at next level) @@ -1454,5 +1482,258 @@ Proof. End Himp. (** [] *) +(** **** 练习:4 星, standard, optional (assert_vs_assume) *) + +Module HoareAssertAssume. + +(** 在这个练习中我们会对 Imp 加入语句 [ASSERT] 和 [ASSUME]。这两个命令 + 都是用来指出某个布尔表达式应该在任何一次程序运行到这里的时候都为真。 + 但是它们有下列区别: + + - 如果 [ASSERT] 失败了,程序就会进入错误状态并且退出。 + + - 如果 [ASSUME] 失败了,程序就不能运行。换句话说这段程序会卡住,没有 + 最终状态。 + + 新的一系列命令是:*) + +Inductive com : Type := + | CSkip : com + | CAss : string -> aexp -> com + | CSeq : com -> com -> com + | CIf : bexp -> com -> com -> com + | CWhile : bexp -> com -> com + | CAssert : bexp -> com + | CAssume : bexp -> com. + +Notation "'SKIP'" := + CSkip. +Notation "x '::=' a" := + (CAss x a) (at level 60). +Notation "c1 ;; c2" := + (CSeq c1 c2) (at level 80, right associativity). +Notation "'WHILE' b 'DO' c 'END'" := + (CWhile b c) (at level 80, right associativity). +Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" := + (CIf c1 c2 c3) (at level 80, right associativity). +Notation "'ASSERT' b" := + (CAssert b) (at level 60). +Notation "'ASSUME' b" := + (CAssume b) (at level 60). + +(** 要定义 [ASSERT] 和 [ASSUME] 的行为,我们必须要加入一个表示错误 + 状态的记号,它指出某个 [ASSERT] 失败了。我们修改一下 [ceval] + 规则,让它是开始状态和“结束状态或者是 [error]”的关系。[result] + 类型是程序结束时的值,要么是 [state] 要么是 [error]。*) + +Inductive result : Type := + | RNormal : state -> result + | RError : result. + +(** 现在我们可以给出新语言的 [ceval] 了。*) + +Inductive ceval : com -> state -> result -> Prop := + (* 稍加修改的旧有规则 *) + | E_Skip : forall st, + st =[ SKIP ]=> RNormal st + | E_Ass : forall st a1 n x, + aeval st a1 = n -> + st =[ x ::= a1 ]=> RNormal (x !-> n ; st) + | E_SeqNormal : forall c1 c2 st st' r, + st =[ c1 ]=> RNormal st' -> + st' =[ c2 ]=> r -> + st =[ c1 ;; c2 ]=> r + | E_SeqError : forall c1 c2 st, + st =[ c1 ]=> RError -> + st =[ c1 ;; c2 ]=> RError + | E_IfTrue : forall st r b c1 c2, + beval st b = true -> + st =[ c1 ]=> r -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> r + | E_IfFalse : forall st r b c1 c2, + beval st b = false -> + st =[ c2 ]=> r -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> r + | E_WhileFalse : forall b st c, + beval st b = false -> + st =[ WHILE b DO c END ]=> RNormal st + | E_WhileTrueNormal : forall st st' r b c, + beval st b = true -> + st =[ c ]=> RNormal st' -> + st' =[ WHILE b DO c END ]=> r -> + st =[ WHILE b DO c END ]=> r + | E_WhileTrueError : forall st b c, + beval st b = true -> + st =[ c ]=> RError -> + st =[ WHILE b DO c END ]=> RError + (* Assert 和 Assume 的规则 *) + | E_AssertTrue : forall st b, + beval st b = true -> + st =[ ASSERT b ]=> RNormal st + | E_AssertFalse : forall st b, + beval st b = false -> + st =[ ASSERT b ]=> RError + | E_Assume : forall st b, + beval st b = true -> + st =[ ASSUME b ]=> RNormal st + +where "st '=[' c ']=>' r" := (ceval c st r). + +(** 我们重新定义霍尔三元组:现在,[{{P}} c {{Q}}] 的意思是, + 当 [c] 在一个满足 [P] 的状态中启动并且停机在一个状态 [r],那么 [r] + 不是错误并且满足 [Q]。*) + +Definition hoare_triple + (P : Assertion) (c : com) (Q : Assertion) : Prop := + forall st r, + st =[ c ]=> r -> P st -> + (exists st', r = RNormal st' /\ Q st'). + +Notation "{{ P }} c {{ Q }}" := + (hoare_triple P c Q) (at level 90, c at next level) + : hoare_spec_scope. +(** 为了测试你对这个修改的理解是否正确,请给出一组前置条件和后置条件, + 它们可以被 [ASSUME] 语句导出却不能被 [ASSERT] 导出。然后证明任何关于 + [ASSERT] 的三元组换成 [ASSUME] 也是正确的。*) + +Theorem assert_assume_differ : exists P b Q, + ({{P}} ASSUME b {{Q}}) + /\ ~ ({{P}} ASSERT b {{Q}}). +Proof. +(* 请在此处解答 *) Admitted. + +Theorem assert_implies_assume : forall P b Q, + ({{P}} ASSERT b {{Q}}) + -> ({{P}} ASSUME b {{Q}}). +Proof. +(* 请在此处解答 *) Admitted. + +(** 你的任务是为 [ASSERT] 和 [ASSUME] 创建霍尔规则,并且用它们证明 + 一个小程序是正确的。把你的规则起名为 [hoare_assert] 和 [hoare_assume]。 + + 为了你方便点,我们把新语义上的那些旧有的霍尔规则帮你证明好了。*) + +Theorem hoare_asgn : forall Q X a, + {{Q [X |-> a]}} X ::= a {{Q}}. +Proof. + unfold hoare_triple. + intros Q X a st st' HE HQ. + inversion HE. subst. + exists (X !-> aeval st a ; st). split; try reflexivity. + assumption. Qed. + +Theorem hoare_consequence_pre : forall (P P' Q : Assertion) c, + {{P'}} c {{Q}} -> + P ->> P' -> + {{P}} c {{Q}}. +Proof. + intros P P' Q c Hhoare Himp. + intros st st' Hc HP. apply (Hhoare st st'). + assumption. apply Himp. assumption. Qed. + +Theorem hoare_consequence_post : forall (P Q Q' : Assertion) c, + {{P}} c {{Q'}} -> + Q' ->> Q -> + {{P}} c {{Q}}. +Proof. + intros P Q Q' c Hhoare Himp. + intros st r Hc HP. + unfold hoare_triple in Hhoare. + assert (exists st', r = RNormal st' /\ Q' st'). + { apply (Hhoare st); assumption. } + destruct H as [st' [Hr HQ']]. + exists st'. split; try assumption. + apply Himp. assumption. +Qed. + +Theorem hoare_seq : forall P Q R c1 c2, + {{Q}} c2 {{R}} -> + {{P}} c1 {{Q}} -> + {{P}} c1;;c2 {{R}}. +Proof. + intros P Q R c1 c2 H1 H2 st r H12 Pre. + inversion H12; subst. + - eapply H1. + + apply H6. + + apply H2 in H3. apply H3 in Pre. + destruct Pre as [st'0 [Heq HQ]]. + inversion Heq; subst. assumption. + - (* 找到矛盾的假设 *) + apply H2 in H5. apply H5 in Pre. + destruct Pre as [st' [C _]]. + inversion C. +Qed. + +(** 把你的霍尔规则,[hoare_assert] 和 [hoare_assume] 写在下面。*) + +(* 请在此处解答 *) + +(** 下列是其它证明规则(用来检查是否合理)*) +Theorem hoare_skip : forall P, + {{P}} SKIP {{P}}. +Proof. + intros P st st' H HP. inversion H. subst. + eexists. split. reflexivity. assumption. +Qed. + +Theorem hoare_if : forall P Q b c1 c2, + {{fun st => P st /\ bassn b st}} c1 {{Q}} -> + {{fun st => P st /\ ~ (bassn b st)}} c2 {{Q}} -> + {{P}} TEST b THEN c1 ELSE c2 FI {{Q}}. +Proof. + intros P Q b c1 c2 HTrue HFalse st st' HE HP. + inversion HE; subst. + - (* b 是 true *) + apply (HTrue st st'). + assumption. + split. assumption. + apply bexp_eval_true. assumption. + - (* b 是 false *) + apply (HFalse st st'). + assumption. + split. assumption. + apply bexp_eval_false. assumption. Qed. + +Theorem hoare_while : forall P b c, + {{fun st => P st /\ bassn b st}} c {{P}} -> + {{P}} WHILE b DO c END {{fun st => P st /\ ~ (bassn b st)}}. +Proof. + intros P b c Hhoare st st' He HP. + remember (WHILE b DO c END) as wcom eqn:Heqwcom. + induction He; + try (inversion Heqwcom); subst; clear Heqwcom. + - (* E_WhileFalse *) + eexists. split. reflexivity. split. + assumption. apply bexp_eval_false. assumption. + - (* E_WhileTrueNormal *) + clear IHHe1. + apply IHHe2. reflexivity. + clear IHHe2 He2 r. + unfold hoare_triple in Hhoare. + apply Hhoare in He1. + + destruct He1 as [st1 [Heq Hst1]]. + inversion Heq; subst. + assumption. + + split; assumption. + - (* E_WhileTrueError *) + exfalso. clear IHHe. + unfold hoare_triple in Hhoare. + apply Hhoare in He. + + destruct He as [st' [C _]]. inversion C. + + split; assumption. +Qed. + +Example assert_assume_example: + {{fun st => True}} + ASSUME (X = 1);; + X ::= X + 1;; + ASSERT (X = 2) + {{fun st => True}}. +Proof. +(* 请在此处解答 *) Admitted. + +End HoareAssertAssume. +(** [] *) +(* Sat Jan 26 15:15:43 UTC 2019 *) diff --git a/plf-current/Hoare2.html b/plf-current/Hoare2.html index 15910827..f4aec669 100644 --- a/plf-current/Hoare2.html +++ b/plf-current/Hoare2.html @@ -35,18 +35,19 @@Hoare霍尔逻辑(第一部分)<
Definition hoare_triple (P:Assertion) (c:com) (Q:Assertion) : Prop :=☐ + +
- ∀ st st', c / st \\ st' → P st → Q st'.
+ ∀st st', st =[ c ]⇒ st' → P st → Q st'.
Notation "{{ P }} c {{ Q }}" := (hoare_triple P c Q)
(at level 90, c at next level)
: hoare_spec_scope.
@@ -2342,7 +2363,7 @@Hoare霍尔逻辑(第一部分)< Definition havoc_pre (X : string) (Q : Assertion) : Assertion
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem hoare_havoc : ∀ (Q : Assertion) (X : string),
+Theorem hoare_havoc : ∀(Q : Assertion) (X : string),
{{ havoc_pre X Q }} HAVOC X {{ Q }}.
Proof.
(* 请在此处解答 *) Admitted.
@@ -2350,6 +2371,305 @@Hoare霍尔逻辑(第一部分)<
+ ++ +
+Module HoareAssertAssume.
++ 在这个练习中我们会对 Imp 加入语句 ASSERT 和 ASSUME。这两个命令 + 都是用来指出某个布尔表达式应该在任何一次程序运行到这里的时候都为真。 + 但是它们有下列区别: + +++ ++
+ 新的一系列命令是: +- 如果 ASSERT 失败了,程序就会进入错误状态并且退出。 + +
++ + +- 如果 ASSUME 失败了,程序就不能运行。换句话说这段程序会卡住,没有 + 最终状态。 + +
++ +Inductive com : Type :=+ +
+ | CSkip : com
+ | CAss : string → aexp → com
+ | CSeq : com → com → com
+ | CIf : bexp → com → com → com
+ | CWhile : bexp → com → com
+ | CAssert : bexp → com
+ | CAssume : bexp → com.
+Notation "'SKIP'" :=
+ CSkip.
+Notation "x '::=' a" :=
+ (CAss x a) (at level 60).
+Notation "c1 ;; c2" :=
+ (CSeq c1 c2) (at level 80, right associativity).
+Notation "'WHILE' b 'DO' c 'END'" :=
+ (CWhile b c) (at level 80, right associativity).
+Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" :=
+ (CIf c1 c2 c3) (at level 80, right associativity).
+Notation "'ASSERT' b" :=
+ (CAssert b) (at level 60).
+Notation "'ASSUME' b" :=
+ (CAssume b) (at level 60).
++要定义 ASSERT 和 ASSUME 的行为,我们必须要加入一个表示错误 + 状态的记号,它指出某个 ASSERT 失败了。我们修改一下 ceval + 规则,让它是开始状态和“结束状态或者是 error”的关系。result + 类型是程序结束时的值,要么是 state 要么是 error。 +++ +Inductive result : Type :=+ +
+ | RNormal : state → result
+ | RError : result.
++现在我们可以给出新语言的 ceval 了。 +++ +Inductive ceval : com → state → result → Prop :=+ +
+ (* 稍加修改的旧有规则 *)
+ | E_Skip : ∀st,
+ st =[ SKIP ]⇒ RNormal st
+ | E_Ass : ∀st a1 n x,
+ aeval st a1 = n →
+ st =[ x ::= a1 ]⇒ RNormal (x !-> n ; st)
+ | E_SeqNormal : ∀c1 c2 st st' r,
+ st =[ c1 ]⇒ RNormal st' →
+ st' =[ c2 ]⇒ r →
+ st =[ c1 ;; c2 ]⇒ r
+ | E_SeqError : ∀c1 c2 st,
+ st =[ c1 ]⇒ RError →
+ st =[ c1 ;; c2 ]⇒ RError
+ | E_IfTrue : ∀st r b c1 c2,
+ beval st b = true →
+ st =[ c1 ]⇒ r →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ r
+ | E_IfFalse : ∀st r b c1 c2,
+ beval st b = false →
+ st =[ c2 ]⇒ r →
+ st =[ TEST b THEN c1 ELSE c2 FI ]⇒ r
+ | E_WhileFalse : ∀b st c,
+ beval st b = false →
+ st =[ WHILE b DO c END ]⇒ RNormal st
+ | E_WhileTrueNormal : ∀st st' r b c,
+ beval st b = true →
+ st =[ c ]⇒ RNormal st' →
+ st' =[ WHILE b DO c END ]⇒ r →
+ st =[ WHILE b DO c END ]⇒ r
+ | E_WhileTrueError : ∀st b c,
+ beval st b = true →
+ st =[ c ]⇒ RError →
+ st =[ WHILE b DO c END ]⇒ RError
+ (* Assert 和 Assume 的规则 *)
+ | E_AssertTrue : ∀st b,
+ beval st b = true →
+ st =[ ASSERT b ]⇒ RNormal st
+ | E_AssertFalse : ∀st b,
+ beval st b = false →
+ st =[ ASSERT b ]⇒ RError
+ | E_Assume : ∀st b,
+ beval st b = true →
+ st =[ ASSUME b ]⇒ RNormal st
+
+where "st '=[' c ']⇒' r" := (ceval c st r).
++我们重新定义霍尔三元组:现在,{{P}} c {{Q}} 的意思是, + 当 c 在一个满足 P 的状态中启动并且停机在一个状态 r,那么 r + 不是错误并且满足 Q。 +++ +Definition hoare_triple+ +
+ (P : Assertion) (c : com) (Q : Assertion) : Prop :=
+ ∀st r,
+ st =[ c ]⇒ r → P st →
+ (∃st', r = RNormal st' ∧ Q st').
+Notation "{{ P }} c {{ Q }}" :=
+ (hoare_triple P c Q) (at level 90, c at next level)
+ : hoare_spec_scope.
++为了测试你对这个修改的理解是否正确,请给出一组前置条件和后置条件, + 它们可以被 ASSUME 语句导出却不能被 ASSERT 导出。然后证明任何关于 + ASSERT 的三元组换成 ASSUME 也是正确的。 +++ +Theorem assert_assume_differ : ∃P b Q,+ +
+ ({{P}} ASSUME b {{Q}})
+ ∧ ¬({{P}} ASSERT b {{Q}}).
+Proof.
+(* 请在此处解答 *) Admitted.
+Theorem assert_implies_assume : ∀P b Q,
+ ({{P}} ASSERT b {{Q}})
+ → ({{P}} ASSUME b {{Q}}).
+Proof.
+(* 请在此处解答 *) Admitted.
++你的任务是为 ASSERT 和 ASSUME 创建霍尔规则,并且用它们证明 + 一个小程序是正确的。把你的规则起名为 hoare_assert 和 hoare_assume。 + +++ + 为了你方便点,我们把新语义上的那些旧有的霍尔规则帮你证明好了。 ++ +Theorem hoare_asgn : ∀Q X a,+ +
+ {{Q [X ⊢> a]}} X ::= a {{Q}}.
+Proof.
+ unfold hoare_triple.
+ intros Q X a st st' HE HQ.
+ inversion HE. subst.
+ ∃(X !-> aeval st a ; st). split; try reflexivity.
+ assumption. Qed.
+Theorem hoare_consequence_pre : ∀(P P' Q : Assertion) c,
+ {{P'}} c {{Q}} →
+ P ->> P' →
+ {{P}} c {{Q}}.
+Proof.
+ intros P P' Q c Hhoare Himp.
+ intros st st' Hc HP. apply (Hhoare st st').
+ assumption. apply Himp. assumption. Qed.
+Theorem hoare_consequence_post : ∀(P Q Q' : Assertion) c,
+ {{P}} c {{Q'}} →
+ Q' ->> Q →
+ {{P}} c {{Q}}.
+Proof.
+ intros P Q Q' c Hhoare Himp.
+ intros st r Hc HP.
+ unfold hoare_triple in Hhoare.
+ assert (∃st', r = RNormal st' ∧ Q' st').
+ { apply (Hhoare st); assumption. }
+ destruct H as [st' [Hr HQ']].
+ ∃st'. split; try assumption.
+ apply Himp. assumption.
+Qed.
+Theorem hoare_seq : ∀P Q R c1 c2,
+ {{Q}} c2 {{R}} →
+ {{P}} c1 {{Q}} →
+ {{P}} c1;;c2 {{R}}.
+Proof.
+ intros P Q R c1 c2 H1 H2 st r H12 Pre.
+ inversion H12; subst.
+ - eapply H1.
+ + apply H6.
+ + apply H2 in H3. apply H3 in Pre.
+ destruct Pre as [st'0 [Heq HQ]].
+ inversion Heq; subst. assumption.
+ - (* 找到矛盾的假设 *)
+ apply H2 in H5. apply H5 in Pre.
+ destruct Pre as [st' [C _]].
+ inversion C.
+Qed.
++ 把你的霍尔规则,hoare_assert 和 hoare_assume 写在下面。 +++ +(* 请在此处解答 *)+ +
++下列是其它证明规则(用来检查是否合理) +++Theorem hoare_skip : ∀P,+ +☐ +
+ {{P}} SKIP {{P}}.
+Proof.
+ intros P st st' H HP. inversion H. subst.
+ eexists. split. reflexivity. assumption.
+Qed.
+Theorem hoare_if : ∀P Q b c1 c2,
+ {{fun st ⇒ P st ∧ bassn b st}} c1 {{Q}} →
+ {{fun st ⇒ P st ∧ ¬(bassn b st)}} c2 {{Q}} →
+ {{P}} TEST b THEN c1 ELSE c2 FI {{Q}}.
+Proof.
+ intros P Q b c1 c2 HTrue HFalse st st' HE HP.
+ inversion HE; subst.
+ - (* b 是 true *)
+ apply (HTrue st st').
+ assumption.
+ split. assumption.
+ apply bexp_eval_true. assumption.
+ - (* b 是 false *)
+ apply (HFalse st st').
+ assumption.
+ split. assumption.
+ apply bexp_eval_false. assumption. Qed.
+Theorem hoare_while : ∀P b c,
+ {{fun st ⇒ P st ∧ bassn b st}} c {{P}} →
+ {{P}} WHILE b DO c END {{fun st ⇒ P st ∧ ¬(bassn b st)}}.
+Proof.
+ intros P b c Hhoare st st' He HP.
+ remember (WHILE b DO c END) as wcom eqn:Heqwcom.
+ induction He;
+ try (inversion Heqwcom); subst; clear Heqwcom.
+ - (* E_WhileFalse *)
+ eexists. split. reflexivity. split.
+ assumption. apply bexp_eval_false. assumption.
+ - (* E_WhileTrueNormal *)
+ clear IHHe1.
+ apply IHHe2. reflexivity.
+ clear IHHe2 He2 r.
+ unfold hoare_triple in Hhoare.
+ apply Hhoare in He1.
+ + destruct He1 as [st1 [Heq Hst1]].
+ inversion Heq; subst.
+ assumption.
+ + split; assumption.
+ - (* E_WhileTrueError *)
+ exfalso. clear IHHe.
+ unfold hoare_triple in Hhoare.
+ apply Hhoare in He.
+ + destruct He as [st' [C _]]. inversion C.
+ + split; assumption.
+Qed.
+Example assert_assume_example:
+ {{fun st ⇒ True}}
+ ASSUME (X = 1);;
+ X ::= X + 1;;
+ ASSERT (X = 2)
+ {{fun st ⇒ True}}.
+Proof.
+(* 请在此处解答 *) Admitted.
+End HoareAssertAssume.
++ +(* Sat Jan 26 15:15:43 UTC 2019 *)
+Hoare2Hoare Logic, Part II Set Warnings "-notation-overridden,-parsing".
-Require Import Coq.Bool.Bool.
-Require Import Coq.Arith.Arith.
-Require Import Coq.Arith.EqNat.
-Require Import Coq.Arith.PeanoNat. Import Nat.
-Require Import Coq.omega.Omega.
+From Coq Require Import Strings.String.
From PLF Require Import Maps.
-From PLF Require Import Imp.
+From Coq Require Import Bool.Bool.
+From Coq Require Import Arith.Arith.
+From Coq Require Import Arith.EqNat.
+From Coq Require Import Arith.PeanoNat. Import Nat.
+From Coq Require Import omega.Omega.
From PLF Require Import Hoare.
+From PLF Require Import Imp.
For example, consider the program: --X ::= m;;
Z ::= p;
- WHILE !(X = 0) DO
+ WHILE ~(X = 0) DO
Z ::= Z - 1;;
X ::= X - 1
END @@ -85,9 +84,7 @@Hoare2Hoare Logic, Part IIm and p, which stand for fixed-but-arbitrary numbers. Formally, they are simply Coq variables of type nat.) - Here is one possible specification for this program: -
- + Here is one possible specification for this program:@@ -95,7 +92,7 @@Hoare2Hoare Logic, Part II{{ True }}
X ::= m;;
Z ::= p;
- WHILE !(X = 0) DO
+ WHILE ~(X = 0) DO
Z ::= Z - 1;;
X ::= X - 1
END
@@ -105,29 +102,28 @@Hoare2Hoare Logic, Part II Here is a decorated version of the program, embodying a proof of this specification: -
-- {{ True }} ->>@@ -196,7 +192,7 @@
+ {{ True }} ->>
{{ m = m }}
X ::= m;;
- {{ X = m }} ->>
+ {{ X = m }} ->>
{{ X = m ∧ p = p }}
Z ::= p;
- {{ X = m ∧ Z = p }} ->>
+ {{ X = m ∧ Z = p }} ->>
{{ Z - X = p - m }}
- WHILE !(X = 0) DO
- {{ Z - X = p - m ∧ X ≠ 0 }} ->>
+ WHILE ~(X = 0) DO
+ {{ Z - X = p - m ∧ X ≠ 0 }} ->>
{{ (Z - 1) - (X - 1) = p - m }}
Z ::= Z - 1;;
{{ Z - (X - 1) = p - m }}
X ::= X - 1
{{ Z - X = p - m }}
END
- {{ Z - X = p - m ∧ ¬ (X ≠ 0) }} ->> {{ Z = p - m }} + {{ Z - X = p - m ∧ ¬(X ≠ 0) }} ->>
+ {{ Z = p - m }}Hoare2Hoare Logic, Part II
- {{ P [X |-> a] }}
+ {{ P [X ⊢> a] }}
X ::= a
{{ P }}@@ -223,7 +219,7 @@Hoare2Hoare Logic, Part II {{ P }}
- IFB b THEN
+ TEST b THEN
{{ P ∧ b }}
c1
{{ Q }}
@@ -274,13 +270,13 @@Hoare2Hoare Logic, Part II
-
- A pair of assertions separated by ->> is locally consistent if +
- A pair of assertions separated by ->> is locally consistent if the first implies the second:
- {{ P }} ->>- We can prove using decorations that this program is correct — - i.e., it always swaps the values of variables X and Y. - + We can prove (informally) using decorations that this program is + correct — i.e., it always swaps the values of variables X and Y.
+ {{ P }} ->>
{{ P' }}@@ -311,7 +307,7 @@Hoare2Hoare Logic, Part II
- (1) {{ X = m ∧ Y = n }} ->>
+ (1) {{ X = m ∧ Y = n }} ->>
(2) {{ (X + Y) - ((X + Y) - Y) = n ∧ (X + Y) - Y = m }}
X ::= X + Y;;
(3) {{ X - (X - Y) = n ∧ X - Y = m }}
@@ -395,7 +390,7 @@Hoare2Hoare Logic, Part II
--Example: Simple Conditionals
+Example: Simple Conditionals
@@ -405,13 +400,13 @@Hoare2Hoare Logic, Part II (1) {{True}}
- IFB X ≤ Y THEN
- (2) {{True ∧ X ≤ Y}} ->>
+ TEST X ≤ Y THEN
+ (2) {{True ∧ X ≤ Y}} ->>
(3) {{(Y - X) + X = Y ∨ (Y - X) + Y = X}}
Z ::= Y - X
(4) {{Z + X = Y ∨ Z + Y = X}}
ELSE
- (5) {{True ∧ ~(X ≤ Y) }} ->>
+ (5) {{True ∧ ~(X ≤ Y) }} ->>
(6) {{(X - Y) + X = Y ∨ (X - Y) + Y = X}}
Z ::= X - Y
(7) {{Z + X = Y ∨ Z + Y = X}}
@@ -454,20 +449,20 @@Hoare2Hoare Logic, Part II
练习:2 星 (if_minus_plus_reloaded)
+练习:2 星, standard (if_minus_plus_reloaded)
Fill in valid decorations for the following program:{{ True }}
- IFB X ≤ Y THEN
- {{ }} ->>
+ TEST X ≤ Y THEN
+ {{ }} ->>
{{ }}
Z ::= Y - X
{{ }}
ELSE
- {{ }} ->>
+ {{ }} ->>
{{ }}
Y ::= X + Z
{{ }}
@@ -487,7 +482,7 @@Hoare2Hoare Logic, Part II☐
-Example: Reduce to Zero
+Example: Reduce to Zero
@@ -498,13 +493,13 @@Hoare2Hoare Logic, Part II (1) {{ True }}
- WHILE !(X = 0) DO
- (2) {{ True ∧ X ≠ 0 }} ->>
+ WHILE ~(X = 0) DO
+ (2) {{ True ∧ X ≠ 0 }} ->>
(3) {{ True }}
X ::= X - 1
(4) {{ True }}
END
- (5) {{ True ∧ X = 0 }} ->>
+ (5) {{ True ∧ X = 0 }} ->>
(6) {{ X = 0 }}@@ -544,9 +539,9 @@Hoare2Hoare Logic, Part II Definition reduce_to_zero' : com :=
- WHILE !(X = 0) DO
+ (WHILE ~(X = 0) DO
X ::= X - 1
- END.
+ END)%imp.
Theorem reduce_to_zero_correct' :
{{fun st ⇒ True}}
reduce_to_zero'
@@ -562,8 +557,8 @@Hoare2Hoare Logic, Part II(* Loop body preserves invariant *)
(* Need to massage precondition before hoare_asgn applies *)
eapply hoare_consequence_pre. apply hoare_asgn.
- (* Proving trivial implication (2) ->> (3) *)
- intros st [HT Hbp]. unfold assn_sub. apply I.
+ (* Proving trivial implication (2) ->> (3) *)
+ intros st [HT Hbp]. unfold assn_sub. constructor.
- (* Invariant and negated guard imply postcondition *)
intros st [Inv GuardFalse].
unfold bassn in GuardFalse. simpl in GuardFalse.
@@ -575,7 +570,7 @@Hoare2Hoare Logic, Part II In order to give a specification to this program we need to - remember that dividing m by n produces a reminder X and a + remember that dividing m by n produces a remainder X and a quotient Y such that n * Y + X = m ∧ X < n.
@@ -615,14 +610,14 @@Hoare2Hoare Logic, Part II
- (1) {{ True }} ->>- To verify this program, we need to find an invariant I for the - loop. As a first step we can leave I as an unknown and build a + To verify this program, we need to find an invariant Inv for the + loop. As a first step we can leave Inv as an unknown and build a _skeleton_ for the proof by applying the rules for local consistency (working from the end of the program to the beginning, as usual, and without any thinking at all yet). @@ -705,22 +700,22 @@
+ (1) {{ True }} ->>
(2) {{ n * 0 + m = m }}
X ::= m;;
(3) {{ n * 0 + X = m }}
Y ::= 0;;
(4) {{ n * Y + X = m }}
WHILE n ≤ X DO
- (5) {{ n * Y + X = m ∧ n ≤ X }} ->>
+ (5) {{ n * Y + X = m ∧ n ≤ X }} ->>
(6) {{ n * (Y + 1) + (X - n) = m }}
X ::= X - n;;
(7) {{ n * (Y + 1) + X = m }}
@@ -648,7 +643,7 @@Hoare2Hoare Logic, Part II -
Example: Slow Subtraction
+Example: Slow Subtraction
@@ -681,7 +676,7 @@Hoare2Hoare Logic, Part II {{ X = m ∧ Y = n }}
- WHILE !(X = 0) DO
+ WHILE ~(X = 0) DO
Y ::= Y - 1;;
X ::= X - 1
END
@@ -692,8 +687,8 @@Hoare2Hoare Logic, Part II
Hoare2Hoare Logic, Part II
- (1) {{ X = m ∧ Y = n }} ->> (a)- By examining this skeleton, we can see that any valid I will + By examining this skeleton, we can see that any valid Inv will have to respect three conditions:
- (2) {{ I }}
- WHILE !(X = 0) DO
- (3) {{ I ∧ X ≠ 0 }} ->> (c)
- (4) {{ I [X |-> X-1] [Y |-> Y-1] }}
+ (1) {{ X = m ∧ Y = n }} ->> (a)
+ (2) {{ Inv }}
+ WHILE ~(X = 0) DO
+ (3) {{ Inv ∧ X ≠ 0 }} ->> (c)
+ (4) {{ Inv [X ⊢> X-1] [Y ⊢> Y-1] }}
Y ::= Y - 1;;
- (5) {{ I [X |-> X-1] }}
+ (5) {{ Inv [X ⊢> X-1] }}
X ::= X - 1
- (6) {{ I }}
+ (6) {{ Inv }}
END
- (7) {{ I ∧ ¬ (X ≠ 0) }} ->> (b)
+ (7) {{ Inv ∧ ¬(X ≠ 0) }} ->> (b)
(8) {{ Y = n - m }}@@ -734,8 +729,8 @@Hoare2Hoare Logic, Part II -
- (c) it must be _preserved_ by one iteration of the loop, i.e., (3) - must imply (4). +
- (c) it must be _preserved_ by each iteration of the loop (given + that the loop guard evaluates to true), i.e., (3) must imply (4).
@@ -755,23 +750,23 @@Hoare2Hoare Logic, Part IITrue as an invariant did the - job. So let's try instantiating I with True in the skeleton + job. So let's try instantiating Inv with True in the skeleton above and see what we get...
- (1) {{ X = m ∧ Y = n }} ->> (a - OK)
+ (1) {{ X = m ∧ Y = n }} ->> (a - OK)
(2) {{ True }}
- WHILE !(X = 0) DO
- (3) {{ True ∧ X ≠ 0 }} ->> (c - OK)
+ WHILE ~(X = 0) DO
+ (3) {{ True ∧ X ≠ 0 }} ->> (c - OK)
(4) {{ True }}
Y ::= Y - 1;;
(5) {{ True }}
X ::= X - 1
(6) {{ True }}
END
- (7) {{ True ∧ X = 0 }} ->> (b - WRONG!)
+ (7) {{ True ∧ X = 0 }} ->> (b - WRONG!)
(8) {{ Y = n - m }}@@ -787,23 +782,23 @@Hoare2Hoare Logic, Part III with Y = n - m, and + return to our skeleton, instantiate Inv with Y = n - m, and check conditions (a) to (c) again.
- (1) {{ X = m ∧ Y = n }} ->> (a - WRONG!)
+ (1) {{ X = m ∧ Y = n }} ->> (a - WRONG!)
(2) {{ Y = n - m }}
- WHILE !(X = 0) DO
- (3) {{ Y = n - m ∧ X ≠ 0 }} ->> (c - WRONG!)
+ WHILE ~(X = 0) DO
+ (3) {{ Y = n - m ∧ X ≠ 0 }} ->> (c - WRONG!)
(4) {{ Y - 1 = n - m }}
Y ::= Y - 1;;
(5) {{ Y = n - m }}
X ::= X - 1
(6) {{ Y = n - m }}
END
- (7) {{ Y = n - m ∧ X = 0 }} ->> (b - OK)
+ (7) {{ Y = n - m ∧ X = 0 }} ->> (b - OK)
(8) {{ Y = n - m }}@@ -836,23 +831,23 @@Hoare2Hoare Logic, Part IIX = 0 and Y = 3; and then the loop stops. Notice that the difference between Y and X stays constant between iterations: initially, Y = n and X = m, and the - difference is always n - m. So let's try instantiating I in + difference is always n - m. So let's try instantiating Inv in the skeleton above with Y - X = n - m.
- (1) {{ X = m ∧ Y = n }} ->> (a - OK)
+ (1) {{ X = m ∧ Y = n }} ->> (a - OK)
(2) {{ Y - X = n - m }}
- WHILE !(X = 0) DO
- (3) {{ Y - X = n - m ∧ X ≠ 0 }} ->> (c - OK)
+ WHILE ~(X = 0) DO
+ (3) {{ Y - X = n - m ∧ X ≠ 0 }} ->> (c - OK)
(4) {{ (Y - 1) - (X - 1) = n - m }}
Y ::= Y - 1;;
(5) {{ Y - (X - 1) = n - m }}
X ::= X - 1
(6) {{ Y - X = n - m }}
END
- (7) {{ Y - X = n - m ∧ X = 0 }} ->> (b - OK)
+ (7) {{ Y - X = n - m ∧ X = 0 }} ->> (b - OK)
(8) {{ Y = n - m }}@@ -864,11 +859,11 @@Hoare2Hoare Logic, Part II
-Exercise: Slow Assignment
+Exercise: Slow Assignment
-练习:2 星 (slow_assignment)
+练习:2 星, standard (slow_assignment)
A roundabout way of assigning a number currently stored in X to the variable Y is to start Y at 0, then decrement X until it hits 0, incrementing Y at each step. Here is a program that @@ -879,7 +874,7 @@Hoare2Hoare Logic, Part II {{ X = m }}
Y ::= 0;;
- WHILE !(X = 0) DO
+ WHILE ~(X = 0) DO
X ::= X - 1;;
Y ::= Y + 1
END
@@ -900,18 +895,18 @@Hoare2Hoare Logic, Part II☐
-Exercise: Slow Addition
+Exercise: Slow Addition
-练习:3 星, optional (add_slowly_decoration)
+练习:3 星, standard, optional (add_slowly_decoration)
The following program adds the variable X into the variable Z by repeatedly decrementing X and incrementing Z.- WHILE !(X = 0) DO
+ WHILE ~(X = 0) DO
Z ::= Z + 1;;
X ::= X - 1
END @@ -931,7 +926,7 @@Hoare2Hoare Logic, Part II☐
- {{ X = m }} ->> (a - OK)
+ {{ X = m }} ->> (a - OK)
{{ parity X = parity m }}
WHILE 2 ≤ X DO
- {{ parity X = parity m ∧ 2 ≤ X }} ->> (c - OK)
+ {{ parity X = parity m ∧ 2 ≤ X }} ->> (c - OK)
{{ parity (X-2) = parity m }}
X ::= X - 2
{{ parity X = parity m }}
END
- {{ parity X = parity m ∧ X < 2 }} ->> (b - OK)
+ {{ parity X = parity m ∧ X < 2 }} ->> (b - OK)
{{ X = parity m }}@@ -996,13 +991,13 @@Hoare2Hoare Logic, Part IIparity X = parity (X-2).
-练习:3 星, optional (parity_formal)
+练习:3 星, standard, optional (parity_formal)
Translate this proof to Coq. Refer to the reduce_to_zero example for ideas. You may find the following two lemmas useful:-Lemma parity_ge_2 : ∀ x,- Fill in the blanks in following decorated program: + Fill in the blanks in following decorated program. For full credit, + make sure all the arithmetic operations used in the assertions are + well-defined on natural numbers.
+Lemma parity_ge_2 : ∀x,
2 ≤ x →
parity (x - 2) = parity x.
@@ -1015,8 +1010,8 @@Hoare2Hoare Logic, Part II
-Lemma parity_lt_2 : ∀ x,
- ¬ 2 ≤ x →
+Lemma parity_lt_2 : ∀x,
+ ¬2 ≤ x →
parity (x) = x.
@@ -1027,7 +1022,7 @@Hoare2Hoare Logic, Part II
-Theorem parity_correct : ∀ m,
+Theorem parity_correct : ∀m,
{{ fun st ⇒ st X = m }}
WHILE 2 ≤ X DO
X ::= X - 2
@@ -1040,7 +1035,7 @@Hoare2Hoare Logic, Part II☐
-Example: Finding Square Roots
+Example: Finding Square Roots
@@ -1068,17 +1063,17 @@Hoare2Hoare Logic, Part II
- (1) {{ X=m }} ->> (a - second conjunct of (2) WRONG!)
+ (1) {{ X=m }} ->> (a - second conjunct of (2) WRONG!)
(2) {{ 0*0 ≤ m ∧ m<1*1 }}
Z ::= 0;;
(3) {{ Z*Z ≤ m ∧ m<(Z+1)*(Z+1) }}
WHILE (Z+1)*(Z+1) ≤ X DO
- (4) {{ Z*Z≤m ∧ (Z+1)*(Z+1)≤X }} ->> (c - WRONG!)
+ (4) {{ Z*Z≤m ∧ (Z+1)*(Z+1)≤X }} ->> (c - WRONG!)
(5) {{ (Z+1)*(Z+1)≤m ∧ m<(Z+2)*(Z+2) }}
Z ::= Z+1
(6) {{ Z*Z≤m ∧ m<(Z+1)*(Z+1) }}
END
- (7) {{ Z*Z≤m ∧ m<(Z+1)*(Z+1) ∧ ~((Z+1)*(Z+1)≤X) }} ->> (b - OK)
+ (7) {{ Z*Z≤m ∧ m<(Z+1)*(Z+1) ∧ ~((Z+1)*(Z+1)≤X) }} ->> (b - OK)
(8) {{ Z*Z≤m ∧ m<(Z+1)*(Z+1) }}@@ -1087,15 +1082,16 @@Hoare2Hoare Logic, Part IIX while (5) mentions m. But note that X is never - assigned in this program, so we should always have X=m, but we - didn't propagate this information from (1) into the loop invariant. + assigned in this program, so we should always have X=m; we + didn't propagate this information from (1) into the loop + invariant, but we could!
- Also, looking at the second conjunct of (8), it seems quite - hopeless as an invariant (why?); fortunately, we don't need it, - since we can obtain it from the negation of the guard — the third - conjunct in (7) — again under the assumption that X=m. + Also, we don't need the second conjunct of (8), since we can + obtain it from the negation of the guard — the third conjunct + in (7) — again under the assumption that X=m. This allows + us to simplify a bit.@@ -1104,17 +1100,17 @@Hoare2Hoare Logic, Part II
- {{ X=m }} ->> (a - OK)- Very often, even if a variable is used in a loop in a read-only + Very often, if a variable is used in a loop in a read-only fashion (i.e., it is referred to by the program or by the specification and it is not changed by the loop), it is necessary to add the fact that it doesn't change to the loop invariant.
+ {{ X=m }} ->> (a - OK)
{{ X=m ∧ 0*0 ≤ m }}
Z ::= 0;
{{ X=m ∧ Z*Z ≤ m }}
WHILE (Z+1)*(Z+1) ≤ X DO
- {{ X=m ∧ Z*Z≤m ∧ (Z+1)*(Z+1)≤X }} ->> (c - OK)
+ {{ X=m ∧ Z*Z≤m ∧ (Z+1)*(Z+1)≤X }} ->> (c - OK)
{{ X=m ∧ (Z+1)*(Z+1)≤m }}
- Z ::= Z+1
+ Z ::= Z + 1
{{ X=m ∧ Z*Z≤m }}
END
- {{ X=m ∧ Z*Z≤m ∧ X<(Z+1)*(Z+1) }} ->> (b - OK)
+ {{ X=m ∧ Z*Z≤m ∧ X<(Z+1)*(Z+1) }} ->> (b - OK)
{{ Z*Z≤m ∧ m<(Z+1)*(Z+1) }}@@ -1124,14 +1120,14 @@Hoare2Hoare Logic, Part II
-Example: Squaring
+Example: Squaring
@@ -1143,7 +1139,7 @@Hoare2Hoare Logic, Part II{{ X = m }}
Y ::= 0;;
Z ::= 0;;
- WHILE !(Y = X) DO
+ WHILE ~(Y = X) DO
Z ::= Z + X;;
Y ::= Y + 1
END
@@ -1164,21 +1160,21 @@Hoare2Hoare Logic, Part II
- {{ X = m }} ->> (a - WRONG)
+ {{ X = m }} ->> (a - WRONG)
{{ 0 = m*m ∧ X = m }}
Y ::= 0;;
{{ 0 = m*m ∧ X = m }}
Z ::= 0;;
{{ Z = m*m ∧ X = m }}
- WHILE !(Y = X) DO
- {{ Z = Y*m ∧ X = m ∧ Y ≠ X }} ->> (c - WRONG)
+ WHILE ~(Y = X) DO
+ {{ Z = Y*m ∧ X = m ∧ Y ≠ X }} ->> (c - WRONG)
{{ Z+X = m*m ∧ X = m }}
Z ::= Z + X;;
{{ Z = m*m ∧ X = m }}
Y ::= Y + 1
{{ Z = m*m ∧ X = m }}
END
- {{ Z = m*m ∧ X = m ∧ ~(Y ≠ X) }} ->> (b - OK)
+ {{ Z = m*m ∧ X = m ∧ ~(Y ≠ X) }} ->> (b - OK)
{{ Z = m*m }}@@ -1197,21 +1193,21 @@Hoare2Hoare Logic, Part II
- {{ X = m }} ->> (a - OK)
+ {{ X = m }} ->> (a - OK)
{{ 0 = 0*m ∧ X = m }}
Y ::= 0;;
{{ 0 = Y*m ∧ X = m }}
Z ::= 0;;
{{ Z = Y*m ∧ X = m }}
- WHILE !(Y = X) DO
- {{ Z = Y*m ∧ X = m ∧ Y ≠ X }} ->> (c - OK)
+ WHILE ~(Y = X) DO
+ {{ Z = Y*m ∧ X = m ∧ Y ≠ X }} ->> (c - OK)
{{ Z+X = (Y+1)*m ∧ X = m }}
Z ::= Z + X;
{{ Z = (Y+1)*m ∧ X = m }}
Y ::= Y + 1
{{ Z = Y*m ∧ X = m }}
END
- {{ Z = Y*m ∧ X = m ∧ ~(Y ≠ X) }} ->> (b - OK)
+ {{ Z = Y*m ∧ X = m ∧ ~(Y ≠ X) }} ->> (b - OK)
{{ Z = m*m }}@@ -1226,17 +1222,17 @@Hoare2Hoare Logic, Part IIZ = m*m and the Z = Y*m conjunct of the invariant. It is often the case that one has - to replace parameters with variables — or - with expressions involving both variables and parameters, like - m - Y — when going from postconditions to invariants. + to replace parameters with variables — or with expressions + involving both variables and parameters, like m - Y — when + going from postconditions to invariants.
-Exercise: Factorial
+Exercise: Factorial
-练习:3 星 (factorial)
+练习:3 星, standard (factorial)
Recall that n! denotes the factorial of n (i.e., n! = 1*2*...*n). Here is an Imp program that calculates the factorial of the number initially stored in the variable X and puts it in @@ -1247,7 +1243,7 @@Hoare2Hoare Logic, Part II {{ X = m }}
Y ::= 1 ;;
- WHILE !(X = 0)
+ WHILE ~(X = 0)
DO
Y ::= Y * X ;;
X ::= X - 1
@@ -1256,24 +1252,26 @@Hoare2Hoare Logic, Part II
- {{ X = m }} ->>
+ {{ X = m }} ->>
{{ }}
Y ::= 1;;
{{ }}
- WHILE !(X = 0)
- DO {{ }} ->>
+ WHILE ~(X = 0)
+ DO {{ }} ->>
{{ }}
Y ::= Y * X;;
{{ }}
X ::= X - 1
{{ }}
END
- {{ }} ->>
+ {{ }} ->>
{{ Y = m! }}@@ -1287,13 +1285,23 @@Hoare2Hoare Logic, Part II ☐ +
+ +(* LY: I saw one submission for factorial_dec use a program like that instead
+ of the one already given by the informal exercise. I accepted it because the
+ exercise does not require to reuse the given program, and we did not
+ strictly define what it means to "implement" factorial in Imp.
+ This other one "implements" factorial in the same way two_loops_dec
+ "implements" the sum (a + b + c).
+*)
+-Exercise: Min
+Exercise: Min
-练习:3 星 (Min_Hoare)
+练习:3 星, standard (Min_Hoare)
Fill in valid decorations for the following program. For the ⇒ steps in your annotations, you may rely (silently) on the following facts about min @@ -1301,9 +1309,9 @@Hoare2Hoare Logic, Part II
- Lemma lemma1 : ∀ x y,
+ Lemma lemma1 : ∀x y,
(x=0 ∨ y=0) → min x y = 0.
- Lemma lemma2 : ∀ x y,
+ Lemma lemma2 : ∀x y,
min (x-1) (y-1) = (min x y) - 1.@@ -1313,7 +1321,7 @@Hoare2Hoare Logic, Part II
- {{ True }} ->>
+ {{ True }} ->>
{{ }}
X ::= a;;
{{ }}
@@ -1321,8 +1329,8 @@Hoare2Hoare Logic, Part II{{ }}
Z ::= 0;;
{{ }}
- WHILE !(X = 0) && !(Y = 0) DO
- {{ }} ->>
+ WHILE ~(X = 0) && ~(Y = 0) DO
+ {{ }} ->>
{{ }}
X := X - 1;;
{{ }}
@@ -1331,7 +1339,7 @@Hoare2Hoare Logic, Part IIZ := Z + 1
{{ }}
END
- {{ }} ->>
+ {{ }} ->>
{{ Z = min a b }}@@ -1348,23 +1356,23 @@Hoare2Hoare Logic, Part II
-练习:3 星 (two_loops)
+练习:3 星, standard (two_loops)
Here is a very inefficient way of adding 3 numbers:- X ::= 0;;@@ -1374,34 +1382,34 @@
- Y ::= 0;;
- Z ::= c;;
- WHILE !(X = a) DO
- X ::= X + 1;;
- Z ::= Z + 1
- END;;
- WHILE !(Y = b) DO
- Y ::= Y + 1;;
- Z ::= Z + 1
- END + X ::= 0;;
+ Y ::= 0;;
+ Z ::= c;;
+ WHILE ~(X = a) DO
+ X ::= X + 1;;
+ Z ::= Z + 1
+ END;;
+ WHILE ~(Y = b) DO
+ Y ::= Y + 1;;
+ Z ::= Z + 1
+ ENDHoare2Hoare Logic, Part II
- {{ True }} ->>@@ -1416,11 +1424,11 @@
- {{ }}
- X ::= 0;;
- {{ }}
- Y ::= 0;;
- {{ }}
- Z ::= c;;
- {{ }}
- WHILE !(X = a) DO
- {{ }} ->>
+ {{ True }} ->>
{{ }}
- X ::= X + 1;;
- {{ }}
- Z ::= Z + 1
+ X ::= 0;;
{{ }}
- END;;
- {{ }} ->>
- {{ }}
- WHILE !(Y = b) DO
- {{ }} ->>
+ Y ::= 0;;
{{ }}
- Y ::= Y + 1;;
+ Z ::= c;;
{{ }}
- Z ::= Z + 1
+ WHILE ~(X = a) DO
+ {{ }} ->>
+ {{ }}
+ X ::= X + 1;;
+ {{ }}
+ Z ::= Z + 1
+ {{ }}
+ END;;
+ {{ }} ->>
{{ }}
- END
- {{ }} ->>
- {{ Z = a + b + c }} + WHILE ~(Y = b) DO
+ {{ }} ->>
+ {{ }}
+ Y ::= Y + 1;;
+ {{ }}
+ Z ::= Z + 1
+ {{ }}
+ END
+ {{ }} ->>
+ {{ Z = a + b + c }}Hoare2Hoare Logic, Part II☐
-Exercise: Power Series
+Exercise: Power Series
-练习:4 星, optional (dpow2_down)
+练习:4 星, standard, optional (dpow2_down)
Here is a program that computes the series: 1 + 2 + 2^2 + ... + 2^m = 2^(m+1) - 1 @@ -1430,7 +1438,7 @@Hoare2Hoare Logic, Part IIX ::= 0;;
Y ::= 1;;
Z ::= 1;;
- WHILE !(X = m) DO
+ WHILE ~(X = m) DO
Z ::= 2 * Z;;
Y ::= Y + Z;;
X ::= X + 1
@@ -1448,7 +1456,7 @@Hoare2Hoare Logic, Part II☐
-Weakest Preconditions (Optional)
+Weakest Preconditions (Optional)
@@ -1506,7 +1514,7 @@Hoare2Hoare Logic, Part IIDefinition is_wp P c Q :=
{{P}} c {{Q}} ∧
- ∀ P', {{P'}} c {{Q}} → (P' ->> P).
+ ∀P', {{P'}} c {{Q}} → (P' ->> P).
@@ -1516,7 +1524,7 @@Hoare2Hoare Logic, Part IIQ will hold after executing c.
-练习:1 星, optional (wp)
+练习:1 星, standard, optional (wp)
What are the weakest preconditions of the following commands for the following postconditions? @@ -1530,7 +1538,7 @@Hoare2Hoare Logic, Part II{{ ? }} X ::= Y {{ X = Y }}
4) {{ ? }}
- IFB X == 0 THEN Y ::= Z + 1 ELSE Y ::= W + 2 FI
+ TEST X = 0 THEN Y ::= Z + 1 ELSE Y ::= W + 2 FI
{{ Y = 5 }}
5) {{ ? }}
@@ -1553,7 +1561,7 @@Hoare2Hoare Logic, Part II
-练习:3 星, advanced, optional (is_wp_formal)
+练习:3 星, advanced, optional (is_wp_formal)
Prove formally, using the definition of hoare_triple, that Y ≤ 4 is indeed the weakest precondition of X ::= Y + 1 with respect to postcondition X ≤ 5. @@ -1571,14 +1579,14 @@Hoare2Hoare Logic, Part II
-练习:2 星, advanced, optional (hoare_asgn_weakest)
+练习:2 星, advanced, optional (hoare_asgn_weakest)
Show that the precondition in the rule hoare_asgn is in fact the weakest precondition.-Theorem hoare_asgn_weakest : ∀ Q X a,@@ -1587,16 +1595,16 @@
- is_wp (Q [X |-> a]) (X ::= a) Q.
+Theorem hoare_asgn_weakest : ∀Q X a,
+ is_wp (Q [X ⊢> a]) (X ::= a) Q.
Proof.
(* 请在此处解答 *) Admitted.
Hoare2Hoare Logic, Part II
-练习:2 星, advanced, optional (hoare_havoc_weakest)
+练习:2 星, advanced, optional (hoare_havoc_weakest)
Show that your havoc_pre rule from the himp_hoare exercise in the Hoare chapter returns the weakest precondition.Module Himp2.@@ -1604,7 +1612,7 @@
Import Himp.
-Lemma hoare_havoc_weakest : ∀ (P Q : Assertion) (X : string),
+Lemma hoare_havoc_weakest : ∀(P Q : Assertion) (X : string),
{{ P }} HAVOC X {{ Q }} →
- P ->> havoc_pre X Q.
+ P ->> havoc_pre X Q.
Proof.
(* 请在此处解答 *) Admitted.
Hoare2Hoare Logic, Part II☐
--Formal Decorated Programs (Optional)
+Formal Decorated Programs (Advanced)
@@ -1618,7 +1626,7 @@Hoare2Hoare Logic, Part II
Syntax
+Syntax
@@ -1629,11 +1637,11 @@Hoare2Hoare Logic, Part IIdecorated, is used to add the precondition - for the entire program. + redundant decorations—the postcondition of the first likely being + the same as the precondition of the second. Instead, decorations + are added corresponding to postconditions only. A separate type, + decorated, is used to add just one precondition for the entire + program.
@@ -1648,6 +1656,7 @@Hoare2Hoare Logic, Part IIDCPost : dcom → Assertion → dcom.
Inductive decorated : Type :=
| Decorated : Assertion → dcom → decorated.
+Delimit Scope default with default.
Notation "'SKIP' {{ P }}"
:= (DCSkip P)
(at level 10) : dcom_scope.
@@ -1657,13 +1666,13 @@Hoare2Hoare Logic, Part IINotation "'WHILE' b 'DO' {{ Pbody }} d 'END' {{ Ppost }}"
:= (DCWhile b Pbody d Ppost)
(at level 80, right associativity) : dcom_scope.
-Notation "'IFB' b 'THEN' {{ P }} d 'ELSE' {{ P' }} d' 'FI' {{ Q }}"
+Notation "'TEST' b 'THEN' {{ P }} d 'ELSE' {{ P' }} d' 'FI' {{ Q }}"
:= (DCIf b P d P' d' Q)
(at level 80, right associativity) : dcom_scope.
-Notation "'->>' {{ P }} d"
+Notation "'->>' {{ P }} d"
:= (DCPre P d)
(at level 90, right associativity) : dcom_scope.
-Notation "d '->>' {{ P }}"
+Notation "d '->>' {{ P }}"
:= (DCPost d P)
(at level 80, right associativity) : dcom_scope.
Notation " d ;; d' "
@@ -1673,7 +1682,13 @@Hoare2Hoare Logic, Part IIDecorated P d)
(at level 90) : dcom_scope.
Delimit Scope dcom_scope with dcom.
-Open Scope dcom_scope.
+Open Scope dcom_scope.
+Example dec0 :=
+ SKIP {{ fun st ⇒ True }}.
+Example dec1 :=
+ WHILE true DO {{ fun st ⇒ True }} SKIP {{ fun st ⇒ True }} END
+ {{ fun st ⇒ True }}.
+Set Printing All.
@@ -1686,21 +1701,21 @@Hoare2Hoare Logic, Part II->>. The "without" version is intended to be + without a ->>. The "without" version is intended to be used to supply the initial precondition at the very top of the program.
Example dec_while : decorated :=@@ -1710,12 +1725,12 @@
- {{ fun st ⇒ True }}
- WHILE !(X = 0)
+ {{ fun st ⇒ True }}
+ WHILE ~(X = 0)
DO
{{ fun st ⇒ True ∧ st X ≠ 0}}
X ::= X - 1
{{ fun _ ⇒ True }}
END
- {{ fun st ⇒ True ∧ st X = 0}} ->>
+ {{ fun st ⇒ True ∧ st X = 0}} ->>
{{ fun st ⇒ st X = 0 }}.
Hoare2Hoare Logic, Part II
-Fixpoint extract (d:dcom) : com :=
+Fixpoint extract (d : dcom) : com :=
match d with
| DCSkip _ ⇒ SKIP
| DCSeq d1 d2 ⇒ (extract d1 ;; extract d2)
| DCAsgn X a _ ⇒ X ::= a
- | DCIf b _ d1 _ d2 _ ⇒ IFB b THEN extract d1 ELSE extract d2 FI
+ | DCIf b _ d1 _ d2 _ ⇒ TEST b THEN extract d1 ELSE extract d2 FI
| DCWhile b _ d _ ⇒ WHILE b DO extract d END
| DCPre _ d ⇒ extract d
| DCPost d _ ⇒ extract d
@@ -1771,7 +1786,7 @@Hoare2Hoare Logic, Part II
-Fixpoint post (d:dcom) : Assertion :=-
+Fixpoint post (d : dcom) : Assertion :=
match d with
| DCSkip P ⇒ P
| DCSeq d1 d2 ⇒ post d2
@@ -1818,7 +1833,7 @@Hoare2Hoare Logic, Part II
Extracting Verification Conditions
+Extracting Verification Conditions
@@ -1837,33 +1852,32 @@Hoare2Hoare Logic, Part II
-Fixpoint verification_conditions (P : Assertion) (d:dcom)@@ -1874,7 +1888,7 @@
- : Prop :=
+Fixpoint verification_conditions (P : Assertion) (d : dcom) : Prop :=
match d with
| DCSkip Q ⇒
- (P ->> Q)
+ (P ->> Q)
| DCSeq d1 d2 ⇒
verification_conditions P d1
∧ verification_conditions (post d1) d2
| DCAsgn X a Q ⇒
- (P ->> Q [X |-> a])
+ (P ->> Q [X ⊢> a])
| DCIf b P1 d1 P2 d2 Q ⇒
- ((fun st ⇒ P st ∧ bassn b st) ->> P1)
- ∧ ((fun st ⇒ P st ∧ ¬ (bassn b st)) ->> P2)
- ∧ (post d1 ->> Q) ∧ (post d2 ->> Q)
+ ((fun st ⇒ P st ∧ bassn b st) ->> P1)
+ ∧ ((fun st ⇒ P st ∧ ¬(bassn b st)) ->> P2)
+ ∧ (post d1 ->> Q) ∧ (post d2 ->> Q)
∧ verification_conditions P1 d1
∧ verification_conditions P2 d2
| DCWhile b Pbody d Ppost ⇒
(* post d is the loop invariant and the initial
precondition *)
- (P ->> post d)
- ∧ ((fun st ⇒ post d st ∧ bassn b st) ->> Pbody)
- ∧ ((fun st ⇒ post d st ∧ ~(bassn b st)) ->> Ppost)
+ (P ->> post d)
+ ∧ ((fun st ⇒ post d st ∧ bassn b st) ->> Pbody)
+ ∧ ((fun st ⇒ post d st ∧ ~(bassn b st)) ->> Ppost)
∧ verification_conditions Pbody d
| DCPre P' d ⇒
- (P ->> P') ∧ verification_conditions P' d
+ (P ->> P') ∧ verification_conditions P' d
| DCPost d Q ⇒
- verification_conditions P d ∧ (post d ->> Q)
+ verification_conditions P d ∧ (post d ->> Q)
end.
Hoare2Hoare Logic, Part II
-Theorem verification_correct : ∀ d P,
+Theorem verification_correct : ∀d P,
verification_conditions P d → {{P}} (extract d) {{post d}}.
@@ -1885,7 +1899,7 @@Hoare2Hoare Logic, Part IIapply hoare_skip.
assumption.
- (* Seq *)
- inversion H as [H1 H2]. clear H.
+ destruct H as [H1 H2].
eapply hoare_seq.
apply IHd2. apply H2.
apply IHd1. apply H1.
@@ -1894,8 +1908,7 @@Hoare2Hoare Logic, Part IIapply hoare_asgn.
assumption.
- (* If *)
- inversion H as [HPre1 [HPre2 [Hd1 [Hd2 [HThen HElse]]]]].
- clear H.
+ destruct H as [HPre1 [HPre2 [Hd1 [Hd2 [HThen HElse]]]]].
apply IHd1 in HThen. clear IHd1.
apply IHd2 in HElse. clear IHd2.
apply hoare_if.
@@ -1904,23 +1917,23 @@Hoare2Hoare Logic, Part IIeapply hoare_consequence_post with (Q':=post d2); eauto.
eapply hoare_consequence_pre; eauto.
- (* While *)
- inversion H as [Hpre [Hbody1 [Hpost1 Hd]]]. clear H.
+ destruct H as [Hpre [Hbody1 [Hpost1 Hd]]].
eapply hoare_consequence_pre; eauto.
eapply hoare_consequence_post; eauto.
apply hoare_while.
eapply hoare_consequence_pre; eauto.
- (* Pre *)
- inversion H as [HP Hd]; clear H.
+ destruct H as [HP Hd].
eapply hoare_consequence_pre. apply IHd. apply Hd. assumption.
- (* Post *)
- inversion H as [Hd HQ]; clear H.
+ destruct H as [Hd HQ].
eapply hoare_consequence_post. apply IHd. apply Hd. assumption.
Qed.
-Automation
+Automation
@@ -1932,7 +1945,7 @@Hoare2Hoare Logic, Part IImatch dec with
| Decorated P d ⇒ verification_conditions P d
end.
-Lemma verification_correct_dec : ∀ dec,
+Lemma verification_correct_dec : ∀dec,
verification_conditions_dec dec → dec_correct dec.
Proof.
intros [P d]. apply verification_correct.
@@ -1953,15 +1966,16 @@Hoare2Hoare Logic, Part II
- ==>@@ -1987,7 +2001,7 @@
- (((fun _ : state ⇒ True) ->> (fun _ : state ⇒ True)) ∧
- ((fun st : state ⇒ True ∧ bassn (! (X = 0)) st) ->>
+ ===>
+ (((fun _ : state ⇒ True) ->> (fun _ : state ⇒ True)) ∧
+ ((fun st : state ⇒ True ∧ bassn (~(X = 0)) st) ->>
(fun st : state ⇒ True ∧ st X ≠ 0)) ∧
- ((fun st : state ⇒ True ∧ ¬ bassn (! (X = 0)) st) ->>
+ ((fun st : state ⇒ True ∧ ¬bassn (~(X = 0)) st) ->>
(fun st : state ⇒ True ∧ st X = 0)) ∧
- (fun st : state ⇒ True ∧ st X ≠ 0) ->>
- (fun _ : state ⇒ True) [X |-> X - 1]) ∧
- (fun st : state ⇒ True ∧ st X = 0) ->> (fun st : state ⇒ st X = 0) + (fun st : state ⇒ True ∧ st X ≠ 0) ->>
+ (fun _ : state ⇒ True) [X ⊢> X - 1]) ∧
+ (fun st : state ⇒ True ∧ st X = 0) ->>
+ (fun st : state ⇒ st X = 0)Hoare2Hoare Logic, Part IIrepeat rewrite t_update_eq;
repeat (rewrite t_update_neq; [| (intro X; inversion X)]);
simpl in *;
- repeat match goal with [H : _ ∧ _ |- _] ⇒ destruct H end;
+ repeat match goal with [H : _ ∧ _ ⊢ _] ⇒ destruct H end;
repeat rewrite not_true_iff_false in *;
repeat rewrite not_false_iff_true in *;
repeat rewrite negb_true_iff in *;
@@ -1999,10 +2013,10 @@Hoare2Hoare Logic, Part IItry subst;
repeat
match goal with
- [st : state |- _] ⇒
+ [st : state ⊢ _] ⇒
match goal with
- [H : st _ = _ |- _] ⇒ rewrite → H in *; clear H
- | [H : _ = st _ |- _] ⇒ rewrite <- H in *; clear H
+ [H : st _ = _ ⊢ _] ⇒ rewrite → H in *; clear H
+ | [H : _ = st _ ⊢ _] ⇒ rewrite <- H in *; clear H
end
end;
try eauto; try omega.
@@ -2011,8 +2025,8 @@Hoare2Hoare Logic, Part II What's left after verify does its thing is "just the interesting parts" of checking that the decorations are correct. For very - simple examples verify immediately solves the goal (provided - that the annotations are correct!). + simple examples, verify sometimes even immediately solves the + goal (provided that the annotations are correct!).
@@ -2027,26 +2041,26 @@Hoare2Hoare Logic, Part II
-Example subtract_slowly_dec (m:nat) (p:nat) : decorated :=-
- {{ fun st ⇒ st X = m ∧ st Z = p }} ->>
+Example subtract_slowly_dec (m : nat) (p : nat) : decorated :=
+ {{ fun st ⇒ st X = m ∧ st Z = p }} ->>
{{ fun st ⇒ st Z - st X = p - m }}
- WHILE ! (X = 0)
- DO {{ fun st ⇒ st Z - st X = p - m ∧ st X ≠ 0 }} ->>
+ WHILE ~(X = 0)
+ DO {{ fun st ⇒ st Z - st X = p - m ∧ st X ≠ 0 }} ->>
{{ fun st ⇒ (st Z - 1) - (st X - 1) = p - m }}
Z ::= Z - 1
{{ fun st ⇒ st Z - (st X - 1) = p - m }} ;;
X ::= X - 1
{{ fun st ⇒ st Z - st X = p - m }}
END
- {{ fun st ⇒ st Z - st X = p - m ∧ st X = 0 }} ->>
+ {{ fun st ⇒ st Z - st X = p - m ∧ st X = 0 }} ->>
{{ fun st ⇒ st Z = p - m }}.
-Theorem subtract_slowly_dec_correct : ∀ m p,
+Theorem subtract_slowly_dec_correct : ∀m p,
dec_correct (subtract_slowly_dec m p).
Proof. intros m p. verify. (* this grinds for a bit! *) Qed.
Swapping Using Addition and Subtraction
+Swapping Using Addition and Subtraction
@@ -2066,7 +2080,7 @@Hoare2Hoare Logic, Part IIY ::= X - Y;;
X ::= X - Y.
Definition swap_dec m n : decorated :=
- {{ fun st ⇒ st X = m ∧ st Y = n}} ->>
+ {{ fun st ⇒ st X = m ∧ st Y = n}} ->>
{{ fun st ⇒ (st X + st Y) - ((st X + st Y) - st Y) = n
∧ (st X + st Y) - st Y = m }}
X ::= X + Y
@@ -2075,32 +2089,32 @@Hoare2Hoare Logic, Part II{{ fun st ⇒ st X - st Y = n ∧ st Y = m }};;
X ::= X - Y
{{ fun st ⇒ st X = n ∧ st Y = m}}.
-Theorem swap_correct : ∀ m n,
+Theorem swap_correct : ∀m n,
dec_correct (swap_dec m n).
Proof. intros; verify. Qed.
Definition if_minus_plus_com :=
- IFB X ≤ Y
+ (TEST X ≤ Y
THEN Z ::= Y - X
ELSE Y ::= X + Z
- FI.
+ FI)%imp.
Definition if_minus_plus_dec :=
{{fun st ⇒ True}}
- IFB X ≤ Y THEN
- {{ fun st ⇒ True ∧ st X ≤ st Y }} ->>
+ TEST X ≤ Y THEN
+ {{ fun st ⇒ True ∧ st X ≤ st Y }} ->>
{{ fun st ⇒ st Y = st X + (st Y - st X) }}
Z ::= Y - X
{{ fun st ⇒ st Y = st X + st Z }}
ELSE
- {{ fun st ⇒ True ∧ ~(st X ≤ st Y) }} ->>
+ {{ fun st ⇒ True ∧ ~(st X ≤ st Y) }} ->>
{{ fun st ⇒ st X + st Z = st X + st Z }}
Y ::= X + Z
{{ fun st ⇒ st Y = st X + st Z }}
@@ -2111,14 +2125,14 @@Hoare2Hoare Logic, Part IIProof. verify. Qed.
Definition if_minus_dec :=
{{fun st ⇒ True}}
- IFB X ≤ Y THEN
- {{fun st ⇒ True ∧ st X ≤ st Y }} ->>
+ TEST X ≤ Y THEN
+ {{fun st ⇒ True ∧ st X ≤ st Y }} ->>
{{fun st ⇒ (st Y - st X) + st X = st Y
∨ (st Y - st X) + st Y = st X}}
Z ::= Y - X
{{fun st ⇒ st Z + st X = st Y ∨ st Z + st Y = st X}}
ELSE
- {{fun st ⇒ True ∧ ~(st X ≤ st Y) }} ->>
+ {{fun st ⇒ True ∧ ~(st X ≤ st Y) }} ->>
{{fun st ⇒ (st X - st Y) + st X = st Y
∨ (st X - st Y) + st Y = st X}}
Z ::= X - Y
@@ -2131,30 +2145,30 @@Hoare2Hoare Logic, Part II
Definition div_mod_dec (a b : nat) : decorated :=
- {{ fun st ⇒ True }} ->>
+ {{ fun st ⇒ True }} ->>
{{ fun st ⇒ b * 0 + a = a }}
X ::= a
{{ fun st ⇒ b * 0 + st X = a }};;
Y ::= 0
{{ fun st ⇒ b * st Y + st X = a }};;
WHILE b ≤ X DO
- {{ fun st ⇒ b * st Y + st X = a ∧ b ≤ st X }} ->>
+ {{ fun st ⇒ b * st Y + st X = a ∧ b ≤ st X }} ->>
{{ fun st ⇒ b * (st Y + 1) + (st X - b) = a }}
X ::= X - b
{{ fun st ⇒ b * (st Y + 1) + st X = a }};;
Y ::= Y + 1
{{ fun st ⇒ b * st Y + st X = a }}
END
- {{ fun st ⇒ b * st Y + st X = a ∧ ~(b ≤ st X) }} ->>
+ {{ fun st ⇒ b * st Y + st X = a ∧ ~(b ≤ st X) }} ->>
{{ fun st ⇒ b * st Y + st X = a ∧ (st X < b) }}.
-Theorem div_mod_dec_correct : ∀ a b,
+Theorem div_mod_dec_correct : ∀a b,
dec_correct (div_mod_dec a b).
Proof. intros a b. verify.
rewrite mult_plus_distr_l. omega.
@@ -2162,7 +2176,7 @@Hoare2Hoare Logic, Part II
@@ -2183,33 +2197,33 @@Hoare2Hoare Logic, Part IIInductive ev : nat → Prop :=
| ev_0 : ev O
- | ev_SS : ∀ n:nat, ev n → ev (S (S n)).
+ | ev_SS : ∀n : nat, ev n → ev (S (S n)).
Definition find_parity_dec m : decorated :=
- {{ fun st ⇒ st X = m}} ->>
+ {{ fun st ⇒ st X = m}} ->>
{{ fun st ⇒ st X ≤ m ∧ ev (m - st X) }}
WHILE 2 ≤ X DO
- {{ fun st ⇒ (st X ≤ m ∧ ev (m - st X)) ∧ 2 ≤ st X }} ->>
+ {{ fun st ⇒ (st X ≤ m ∧ ev (m - st X)) ∧ 2 ≤ st X }} ->>
{{ fun st ⇒ st X - 2 ≤ m ∧ (ev (m - (st X - 2))) }}
X ::= X - 2
{{ fun st ⇒ st X ≤ m ∧ ev (m - st X) }}
END
- {{ fun st ⇒ (st X ≤ m ∧ ev (m - st X)) ∧ st X < 2 }} ->>
+ {{ fun st ⇒ (st X ≤ m ∧ ev (m - st X)) ∧ st X < 2 }} ->>
{{ fun st ⇒ st X=0 ↔ ev m }}.
-Lemma l1 : ∀ m n p,
+Lemma l1 : ∀m n p,
p ≤ n →
n ≤ m →
m - (n - p) = m - n + p.
Proof. intros. omega. Qed.
-Lemma l2 : ∀ m,
+Lemma l2 : ∀m,
ev m →
ev (m + 2).
Proof. intros. rewrite plus_comm. simpl. constructor. assumption. Qed.
-Lemma l3' : ∀ m,
+Lemma l3' : ∀m,
ev m →
¬ev (S m).
Proof. induction m; intros H1 H2. inversion H2. apply IHm.
inversion H2; subst; assumption. assumption. Qed.
-Lemma l3 : ∀ m,
+Lemma l3 : ∀m,
1 ≤ m →
ev m →
ev (m - 1) →
@@ -2217,7 +2231,7 @@Hoare2Hoare Logic, Part IIProof. intros. apply l2 in H1.
assert (G : m - 1 + 2 = S m). clear H0 H1. omega.
rewrite G in H1. apply l3' in H0. apply H0. assumption. Qed.
-Theorem find_parity_correct : ∀ m,
+Theorem find_parity_correct : ∀m,
dec_correct (find_parity_dec m).
Proof.
intro m. verify;
@@ -2231,7 +2245,7 @@Hoare2Hoare Logic, Part IIrewrite l1; try assumption.
apply l2; assumption.
- (* invariant strong enough to imply conclusion
- (-> direction) *)
+ (-> direction) *)
rewrite <- minus_n_O in H2. assumption.
- (* invariant strong enough to imply conclusion
(<- direction) *)
@@ -2253,17 +2267,17 @@Hoare2Hoare Logic, Part II Definition find_parity_dec' m : decorated :=
- {{ fun st ⇒ st X = m}} ->>
+ {{ fun st ⇒ st X = m}} ->>
{{ fun st ⇒ ev (st X) ↔ ev m }}
WHILE 2 ≤ X DO
- {{ fun st ⇒ (ev (st X) ↔ ev m) ∧ 2 ≤ st X }} ->>
+ {{ fun st ⇒ (ev (st X) ↔ ev m) ∧ 2 ≤ st X }} ->>
{{ fun st ⇒ (ev (st X - 2) ↔ ev m) }}
X ::= X - 2
{{ fun st ⇒ (ev (st X) ↔ ev m) }}
END
- {{ fun st ⇒ (ev (st X) ↔ ev m) ∧ ~(2 ≤ st X) }} ->>
+ {{ fun st ⇒ (ev (st X) ↔ ev m) ∧ ~(2 ≤ st X) }} ->>
{{ fun st ⇒ st X=0 ↔ ev m }}.
-Lemma l4 : ∀ m,
+Lemma l4 : ∀m,
2 ≤ m →
(ev (m - 2) ↔ ev m).
Proof.
@@ -2273,7 +2287,7 @@Hoare2Hoare Logic, Part IIconstructor. assumption.
inversion H0. assumption.
Qed.
-Theorem find_parity_correct' : ∀ m,
+Theorem find_parity_correct' : ∀m,
dec_correct (find_parity_dec' m).
Proof.
intros m. verify;
@@ -2286,7 +2300,7 @@Hoare2Hoare Logic, Part II(* invariant preserved (part 2) *)
rewrite l4; eauto.
- (* invariant strong enough to imply conclusion
- (-> direction) *)
+ (-> direction) *)
apply H0. constructor.
- (* invariant strong enough to imply conclusion
(<- direction) *)
@@ -2307,17 +2321,17 @@Hoare2Hoare Logic, Part II Definition parity_dec m : decorated :=
- {{ fun st ⇒ st X = m}} ->>
+ {{ fun st ⇒ st X = m}} ->>
{{ fun st ⇒ parity (st X) = parity m }}
WHILE 2 ≤ X DO
- {{ fun st ⇒ parity (st X) = parity m ∧ 2 ≤ st X }} ->>
+ {{ fun st ⇒ parity (st X) = parity m ∧ 2 ≤ st X }} ->>
{{ fun st ⇒ parity (st X - 2) = parity m }}
X ::= X - 2
{{ fun st ⇒ parity (st X) = parity m }}
END
- {{ fun st ⇒ parity (st X) = parity m ∧ ~(2 ≤ st X) }} ->>
+ {{ fun st ⇒ parity (st X) = parity m ∧ ~(2 ≤ st X) }} ->>
{{ fun st ⇒ st X = parity m }}.
-Theorem parity_dec_correct : ∀ m,
+Theorem parity_dec_correct : ∀m,
dec_correct (parity_dec m).
Proof.
intros. verify;
@@ -2333,34 +2347,34 @@Hoare2Hoare Logic, Part II
Definition sqrt_dec m : decorated :=
- {{ fun st ⇒ st X = m }} ->>
+ {{ fun st ⇒ st X = m }} ->>
{{ fun st ⇒ st X = m ∧ 0*0 ≤ m }}
Z ::= 0
{{ fun st ⇒ st X = m ∧ st Z*st Z ≤ m }};;
WHILE (Z+1)*(Z+1) ≤ X DO
{{ fun st ⇒ (st X = m ∧ st Z*st Z≤m)
- ∧ (st Z + 1)*(st Z + 1) ≤ st X }} ->>
+ ∧ (st Z + 1)*(st Z + 1) ≤ st X }} ->>
{{ fun st ⇒ st X = m ∧ (st Z+1)*(st Z+1)≤m }}
Z ::= Z + 1
{{ fun st ⇒ st X = m ∧ st Z*st Z≤m }}
END
{{ fun st ⇒ (st X = m ∧ st Z*st Z≤m)
- ∧ ~((st Z + 1)*(st Z + 1) ≤ st X) }} ->>
+ ∧ ~((st Z + 1)*(st Z + 1) ≤ st X) }} ->>
{{ fun st ⇒ st Z*st Z≤m ∧ m<(st Z+1)*(st Z+1) }}.
-Theorem sqrt_correct : ∀ m,
+Theorem sqrt_correct : ∀m,
dec_correct (sqrt_dec m).
Proof. intro m. verify. Qed.
-Squaring
+Squaring
@@ -2375,19 +2389,19 @@Hoare2Hoare Logic, Part IIY ::= X
{{ fun st ⇒ st X = m ∧ st Y = m }};;
Z ::= 0
- {{ fun st ⇒ st X = m ∧ st Y = m ∧ st Z = 0}} ->>
+ {{ fun st ⇒ st X = m ∧ st Y = m ∧ st Z = 0}} ->>
{{ fun st ⇒ st Z + st X * st Y = m * m }};;
- WHILE !(Y = 0) DO
- {{ fun st ⇒ st Z + st X * st Y = m * m ∧ st Y ≠ 0 }} ->>
+ WHILE ~(Y = 0) DO
+ {{ fun st ⇒ st Z + st X * st Y = m * m ∧ st Y ≠ 0 }} ->>
{{ fun st ⇒ (st Z + st X) + st X * (st Y - 1) = m * m }}
Z ::= Z + X
{{ fun st ⇒ st Z + st X * (st Y - 1) = m * m }};;
Y ::= Y - 1
{{ fun st ⇒ st Z + st X * st Y = m * m }}
END
- {{ fun st ⇒ st Z + st X * st Y = m * m ∧ st Y = 0 }} ->>
+ {{ fun st ⇒ st Z + st X * st Y = m * m ∧ st Y = 0 }} ->>
{{ fun st ⇒ st Z = m * m }}.
-Theorem square_dec_correct : ∀ m,
+Theorem square_dec_correct : ∀m,
dec_correct (square_dec m).
Proof.
intro n. verify.
@@ -2395,7 +2409,7 @@Hoare2Hoare Logic, Part IIdestruct (st Y) as [| y']. apply False_ind. apply H0.
reflexivity.
simpl. rewrite <- minus_n_O.
- assert (G : ∀ n m, n * S m = n + n * m). {
+ assert (G : ∀n m, n * S m = n + n * m). {
clear. intros. induction n. reflexivity. simpl.
rewrite IHn. omega. }
rewrite <- H. rewrite G. rewrite plus_assoc. reflexivity.
@@ -2407,10 +2421,10 @@Hoare2Hoare Logic, Part IIY ::= X
{{ fun st ⇒ st X = n ∧ st Y = n }};;
Z ::= 0
- {{ fun st ⇒ st X = n ∧ st Y = n ∧ st Z = 0 }} ->>
+ {{ fun st ⇒ st X = n ∧ st Y = n ∧ st Z = 0 }} ->>
{{ fun st ⇒ st Z = st X * (st X - st Y)
∧ st X = n ∧ st Y ≤ st X }};;
- WHILE !(Y = 0) DO
+ WHILE ~(Y = 0) DO
{{ fun st ⇒ (st Z = st X * (st X - st Y)
∧ st X = n ∧ st Y ≤ st X)
∧ st Y ≠ 0 }}
@@ -2423,9 +2437,9 @@Hoare2Hoare Logic, Part IIEND
{{ fun st ⇒ (st Z = st X * (st X - st Y)
∧ st X = n ∧ st Y ≤ st X)
- ∧ st Y = 0 }} ->>
+ ∧ st Y = 0 }} ->>
{{ fun st ⇒ st Z = n * n }}.
-Theorem square_dec'_correct : ∀ n,
+Theorem square_dec'_correct : ∀n,
dec_correct (square_dec' n).
Proof.
intro n. verify.
@@ -2434,7 +2448,7 @@Hoare2Hoare Logic, Part II(* invariant preserved *) subst.
rewrite mult_minus_distr_l.
repeat rewrite mult_minus_distr_l. rewrite mult_1_r.
- assert (G : ∀ n m p,
+ assert (G : ∀n m p,
m ≤ n → p ≤ m → n - (m - p) = n - m + p).
intros. omega.
rewrite G. reflexivity. apply mult_le_compat_l. assumption.
@@ -2446,25 +2460,25 @@Hoare2Hoare Logic, Part IIrewrite <- minus_n_O. reflexivity.
Qed.
Definition square_simpler_dec (m : nat) : decorated :=
- {{ fun st ⇒ st X = m }} ->>
+ {{ fun st ⇒ st X = m }} ->>
{{ fun st ⇒ 0 = 0*m ∧ st X = m }}
Y ::= 0
{{ fun st ⇒ 0 = (st Y)*m ∧ st X = m }};;
Z ::= 0
- {{ fun st ⇒ st Z = (st Y)*m ∧ st X = m }}->>
+ {{ fun st ⇒ st Z = (st Y)*m ∧ st X = m }}->>
{{ fun st ⇒ st Z = (st Y)*m ∧ st X = m }};;
- WHILE !(Y = X) DO
+ WHILE ~(Y = X) DO
{{ fun st ⇒ (st Z = (st Y)*m ∧ st X = m)
- ∧ st Y ≠ st X }} ->>
+ ∧ st Y ≠ st X }} ->>
{{ fun st ⇒ st Z + st X = ((st Y) + 1)*m ∧ st X = m }}
Z ::= Z + X
{{ fun st ⇒ st Z = ((st Y) + 1)*m ∧ st X = m }};;
Y ::= Y + 1
{{ fun st ⇒ st Z = (st Y)*m ∧ st X = m }}
END
- {{ fun st ⇒ (st Z = (st Y)*m ∧ st X = m) ∧ st Y = st X }} ->>
+ {{ fun st ⇒ (st Z = (st Y)*m ∧ st X = m) ∧ st Y = st X }} ->>
{{ fun st ⇒ st Z = m*m }}.
-Theorem square_simpler_dec_correct : ∀ m,
+Theorem square_simpler_dec_correct : ∀m,
dec_correct (square_simpler_dec m).
Proof.
intro m. verify.
@@ -2474,14 +2488,14 @@Hoare2Hoare Logic, Part II
Definition two_loops_dec (a b c : nat) : decorated :=
- {{ fun st ⇒ True }} ->>
+ {{ fun st ⇒ True }} ->>
{{ fun st ⇒ c = 0 + c ∧ 0 = 0 }}
X ::= 0
{{ fun st ⇒ c = st X + c ∧ 0 = 0 }};;
@@ -2489,33 +2503,33 @@Hoare2Hoare Logic, Part II{{ fun st ⇒ c = st X + c ∧ st Y = 0 }};;
Z ::= c
{{ fun st ⇒ st Z = st X + c ∧ st Y = 0 }};;
- WHILE !(X = a) DO
- {{ fun st ⇒ (st Z = st X + c ∧ st Y = 0) ∧ st X ≠ a }} ->>
+ WHILE ~(X = a) DO
+ {{ fun st ⇒ (st Z = st X + c ∧ st Y = 0) ∧ st X ≠ a }} ->>
{{ fun st ⇒ st Z + 1 = st X + 1 + c ∧ st Y = 0 }}
X ::= X + 1
{{ fun st ⇒ st Z + 1 = st X + c ∧ st Y = 0 }};;
Z ::= Z + 1
{{ fun st ⇒ st Z = st X + c ∧ st Y = 0 }}
END
- {{ fun st ⇒ (st Z = st X + c ∧ st Y = 0) ∧ st X = a }} ->>
+ {{ fun st ⇒ (st Z = st X + c ∧ st Y = 0) ∧ st X = a }} ->>
{{ fun st ⇒ st Z = a + st Y + c }};;
- WHILE !(Y = b) DO
- {{ fun st ⇒ st Z = a + st Y + c ∧ st Y ≠ b }} ->>
+ WHILE ~(Y = b) DO
+ {{ fun st ⇒ st Z = a + st Y + c ∧ st Y ≠ b }} ->>
{{ fun st ⇒ st Z + 1 = a + st Y + 1 + c }}
Y ::= Y + 1
{{ fun st ⇒ st Z + 1 = a + st Y + c }};;
Z ::= Z + 1
{{ fun st ⇒ st Z = a + st Y + c }}
END
- {{ fun st ⇒ (st Z = a + st Y + c) ∧ st Y = b }} ->>
+ {{ fun st ⇒ (st Z = a + st Y + c) ∧ st Y = b }} ->>
{{ fun st ⇒ st Z = a + b + c }}.
-Theorem two_loops_correct : ∀ a b c,
+Theorem two_loops_correct : ∀a b c,
dec_correct (two_loops_dec a b c).
Proof. intros a b c. verify. Qed.
@@ -2526,8 +2540,8 @@Hoare2Hoare Logic, Part II | S n' ⇒ 2 * (pow2 n')
end.
-Definition dpow2_down (n: nat) :=
- {{ fun st ⇒ True }} ->>
+Definition dpow2_down (n : nat) :=
+ {{ fun st ⇒ True }} ->>
{{ fun st ⇒ 1 = (pow2 (0 + 1))-1 ∧ 1 = pow2 0 }}
X ::= 0
{{ fun st ⇒ 1 = (pow2 (0 + 1))-1 ∧ 1 = pow2 (st X) }};;
@@ -2535,9 +2549,9 @@Hoare2Hoare Logic, Part II{{ fun st ⇒ st Y = (pow2 (st X + 1))-1 ∧ 1 = pow2 (st X) }};;
Z ::= 1
{{ fun st ⇒ st Y = (pow2 (st X + 1))-1 ∧ st Z = pow2 (st X) }};;
- WHILE !(X = n) DO
+ WHILE ~(X = n) DO
{{ fun st ⇒ (st Y = (pow2 (st X + 1))-1 ∧ st Z = pow2 (st X))
- ∧ st X ≠ n }} ->>
+ ∧ st X ≠ n }} ->>
{{ fun st ⇒ st Y + 2 * st Z = (pow2 (st X + 2))-1
∧ 2 * st Z = pow2 (st X + 1) }}
Z ::= 2 * Z
@@ -2551,14 +2565,14 @@Hoare2Hoare Logic, Part IIst Z = pow2 (st X) }}
END
{{ fun st ⇒ (st Y = (pow2 (st X + 1))-1 ∧ st Z = pow2 (st X))
- ∧ st X = n }} ->>
+ ∧ st X = n }} ->>
{{ fun st ⇒ st Y = pow2 (n+1) - 1 }}.
-Lemma pow2_plus_1 : ∀ n,
+Lemma pow2_plus_1 : ∀n,
pow2 (n+1) = pow2 n + pow2 n.
Proof. induction n; simpl. reflexivity. omega. Qed.
-Lemma pow2_le_1 : ∀ n, pow2 n ≥ 1.
+Lemma pow2_le_1 : ∀n, pow2 n ≥ 1.
Proof. induction n. simpl. constructor. simpl. omega. Qed.
-Theorem dpow2_down_correct : ∀ n,
+Theorem dpow2_down_correct : ∀n,
dec_correct (dpow2_down n).
Proof.
intro m. verify.
@@ -2582,11 +2596,11 @@Hoare2Hoare Logic, Part II
-diff --git a/plf-current/Hoare2.v b/plf-current/Hoare2.v index 798859d8..b1cb0fae 100644 --- a/plf-current/Hoare2.v +++ b/plf-current/Hoare2.v @@ -1,14 +1,15 @@ (** * Hoare2: Hoare Logic, Part II *) Set Warnings "-notation-overridden,-parsing". -Require Import Coq.Bool.Bool. -Require Import Coq.Arith.Arith. -Require Import Coq.Arith.EqNat. -Require Import Coq.Arith.PeanoNat. Import Nat. -Require Import Coq.omega.Omega. +From Coq Require Import Strings.String. From PLF Require Import Maps. -From PLF Require Import Imp. +From Coq Require Import Bool.Bool. +From Coq Require Import Arith.Arith. +From Coq Require Import Arith.EqNat. +From Coq Require Import Arith.PeanoNat. Import Nat. +From Coq Require Import omega.Omega. From PLF Require Import Hoare. +From PLF Require Import Imp. (* ################################################################# *) (** * Decorated Programs *) @@ -24,12 +25,11 @@ From PLF Require Import Hoare. Such a _decorated program_ carries within it an argument for its own correctness. *) -(** For example, consider the program: *) -(** +(** For example, consider the program: X ::= m;; Z ::= p; - WHILE !(X = 0) DO + WHILE ~(X = 0) DO Z ::= Z - 1;; X ::= X - 1 END @@ -37,22 +37,20 @@ From PLF Require Import Hoare. (Note the _parameters_ [m] and [p], which stand for fixed-but-arbitrary numbers. Formally, they are simply Coq variables of type [nat].) -*) -(** Here is one possible specification for this program: *) -(** + + Here is one possible specification for this program: {{ True }} X ::= m;; Z ::= p; - WHILE !(X = 0) DO + WHILE ~(X = 0) DO Z ::= Z - 1;; X ::= X - 1 END {{ Z = p - m }} -*) -(** Here is a decorated version of the program, embodying a - proof of this specification: *) -(** + + Here is a decorated version of the program, embodying a + proof of this specification: {{ True }} ->> {{ m = m }} @@ -62,7 +60,7 @@ From PLF Require Import Hoare. Z ::= p; {{ X = m /\ Z = p }} ->> {{ Z - X = p - m }} - WHILE !(X = 0) DO + WHILE ~(X = 0) DO {{ Z - X = p - m /\ X <> 0 }} ->> {{ (Z - 1) - (X - 1) = p - m }} Z ::= Z - 1;; @@ -70,7 +68,8 @@ From PLF Require Import Hoare. X ::= X - 1 {{ Z - X = p - m }} END - {{ Z - X = p - m /\ ~ (X <> 0) }} ->> {{ Z = p - m }} + {{ Z - X = p - m /\ ~ (X <> 0) }} ->> + {{ Z = p - m }} *) (** Concretely, a decorated program consists of the program text @@ -111,7 +110,7 @@ From PLF Require Import Hoare. respect to [P /\ ~b] and [Q]): {{ P }} - IFB b THEN + TEST b THEN {{ P /\ b }} c1 {{ Q }} @@ -172,10 +171,8 @@ From PLF Require Import Hoare. Y ::= X - Y;; X ::= X - Y - We can prove using decorations that this program is correct -- - i.e., it always swaps the values of variables [X] and [Y]. -*) -(** + We can prove (informally) using decorations that this program is + correct -- i.e., it always swaps the values of variables [X] and [Y]. (1) {{ X = m /\ Y = n }} ->> (2) {{ (X + Y) - ((X + Y) - Y) = n /\ (X + Y) - Y = m }} @@ -219,7 +216,7 @@ From PLF Require Import Hoare. (** Here is a simple decorated program using conditionals: (1) {{True}} - IFB X <= Y THEN + TEST X <= Y THEN (2) {{True /\ X <= Y}} ->> (3) {{(Y - X) + X = Y \/ (Y - X) + Y = X}} Z ::= Y - X @@ -252,11 +249,12 @@ These decorations were constructed as follows: arbitrary natural numbers [n] and [m] (for example, [3 - 5 + 5 = 5]). *) -(** **** 练习:2 星 (if_minus_plus_reloaded) *) -(** Fill in valid decorations for the following program: +(** **** 练习:2 星, standard (if_minus_plus_reloaded) + + Fill in valid decorations for the following program: {{ True }} - IFB X <= Y THEN + TEST X <= Y THEN {{ }} ->> {{ }} Z ::= Y - X @@ -274,7 +272,6 @@ These decorations were constructed as follows: Definition manual_grade_for_decorations_in_if_minus_plus_reloaded : option (nat*string) := None. (** [] *) - (* ================================================================= *) (** ** Example: Reduce to Zero *) @@ -282,7 +279,7 @@ Definition manual_grade_for_decorations_in_if_minus_plus_reloaded : option (nat* invariant (i.e., the invariant [True] will do the job). (1) {{ True }} - WHILE !(X = 0) DO + WHILE ~(X = 0) DO (2) {{ True /\ X <> 0 }} ->> (3) {{ True }} X ::= X - 1 @@ -310,9 +307,9 @@ The decorations can be constructed as follows: programs. *) Definition reduce_to_zero' : com := - WHILE !(X = 0) DO + (WHILE ~(X = 0) DO X ::= X - 1 - END. + END)%imp. Theorem reduce_to_zero_correct' : {{fun st => True}} @@ -328,7 +325,7 @@ Proof. (* Need to massage precondition before [hoare_asgn] applies *) eapply hoare_consequence_pre. apply hoare_asgn. (* Proving trivial implication (2) ->> (3) *) - intros st [HT Hbp]. unfold assn_sub. apply I. + intros st [HT Hbp]. unfold assn_sub. constructor. - (* Invariant and negated guard imply postcondition *) intros st [Inv GuardFalse]. unfold bassn in GuardFalse. simpl in GuardFalse. @@ -356,9 +353,8 @@ Proof. remainder when [m] is divided by [n] and [Y] set to the quotient. *) - (** In order to give a specification to this program we need to - remember that dividing [m] by [n] produces a reminder [X] and a + remember that dividing [m] by [n] produces a remainder [X] and a quotient [Y] such that [n * Y + X = m /\ X < n]. It turns out that we get lucky with this program and don't have to @@ -418,15 +414,15 @@ Proof. correctness with respect to the pre- and postconditions shown: {{ X = m /\ Y = n }} - WHILE !(X = 0) DO + WHILE ~(X = 0) DO Y ::= Y - 1;; X ::= X - 1 END {{ Y = n - m }} *) -(** To verify this program, we need to find an invariant [I] for the - loop. As a first step we can leave [I] as an unknown and build a +(** To verify this program, we need to find an invariant [Inv] for the + loop. As a first step we can leave [Inv] as an unknown and build a _skeleton_ for the proof by applying the rules for local consistency (working from the end of the program to the beginning, as usual, and without any thinking at all yet). @@ -434,26 +430,26 @@ Proof. This leads to the following skeleton: (1) {{ X = m /\ Y = n }} ->> (a) - (2) {{ I }} - WHILE !(X = 0) DO - (3) {{ I /\ X <> 0 }} ->> (c) - (4) {{ I [X |-> X-1] [Y |-> Y-1] }} + (2) {{ Inv }} + WHILE ~(X = 0) DO + (3) {{ Inv /\ X <> 0 }} ->> (c) + (4) {{ Inv [X |-> X-1] [Y |-> Y-1] }} Y ::= Y - 1;; - (5) {{ I [X |-> X-1] }} + (5) {{ Inv [X |-> X-1] }} X ::= X - 1 - (6) {{ I }} + (6) {{ Inv }} END - (7) {{ I /\ ~ (X <> 0) }} ->> (b) + (7) {{ Inv /\ ~ (X <> 0) }} ->> (b) (8) {{ Y = n - m }} - By examining this skeleton, we can see that any valid [I] will + By examining this skeleton, we can see that any valid [Inv] will have to respect three conditions: - (a) it must be _weak_ enough to be implied by the loop's precondition, i.e., (1) must imply (2); - (b) it must be _strong_ enough to imply the program's postcondition, i.e., (7) must imply (8); - - (c) it must be _preserved_ by one iteration of the loop, i.e., (3) - must imply (4). *) + - (c) it must be _preserved_ by each iteration of the loop (given + that the loop guard evaluates to true), i.e., (3) must imply (4). *) (** These conditions are actually independent of the particular program and specification we are considering. Indeed, every loop @@ -467,12 +463,12 @@ Proof. For instance, in the reduce-to-zero example above, we saw that, for a very simple loop, choosing [True] as an invariant did the - job. So let's try instantiating [I] with [True] in the skeleton + job. So let's try instantiating [Inv] with [True] in the skeleton above and see what we get... (1) {{ X = m /\ Y = n }} ->> (a - OK) (2) {{ True }} - WHILE !(X = 0) DO + WHILE ~(X = 0) DO (3) {{ True /\ X <> 0 }} ->> (c - OK) (4) {{ True }} Y ::= Y - 1;; @@ -492,12 +488,12 @@ Proof. If we want (b) to hold, we need to strengthen the invariant so that it implies the postcondition (8). One simple way to do this is to let the invariant _be_ the postcondition. So let's - return to our skeleton, instantiate [I] with [Y = n - m], and + return to our skeleton, instantiate [Inv] with [Y = n - m], and check conditions (a) to (c) again. (1) {{ X = m /\ Y = n }} ->> (a - WRONG!) (2) {{ Y = n - m }} - WHILE !(X = 0) DO + WHILE ~(X = 0) DO (3) {{ Y = n - m /\ X <> 0 }} ->> (c - WRONG!) (4) {{ Y - 1 = n - m }} Y ::= Y - 1;; @@ -532,12 +528,12 @@ Proof. after two iterations [X = 0] and [Y = 3]; and then the loop stops. Notice that the difference between [Y] and [X] stays constant between iterations: initially, [Y = n] and [X = m], and the - difference is always [n - m]. So let's try instantiating [I] in + difference is always [n - m]. So let's try instantiating [Inv] in the skeleton above with [Y - X = n - m]. (1) {{ X = m /\ Y = n }} ->> (a - OK) (2) {{ Y - X = n - m }} - WHILE !(X = 0) DO + WHILE ~(X = 0) DO (3) {{ Y - X = n - m /\ X <> 0 }} ->> (c - OK) (4) {{ (Y - 1) - (X - 1) = n - m }} Y ::= Y - 1;; @@ -556,15 +552,16 @@ Proof. (* ================================================================= *) (** ** Exercise: Slow Assignment *) -(** **** 练习:2 星 (slow_assignment) *) -(** A roundabout way of assigning a number currently stored in [X] to +(** **** 练习:2 星, standard (slow_assignment) + + A roundabout way of assigning a number currently stored in [X] to the variable [Y] is to start [Y] at [0], then decrement [X] until it hits [0], incrementing [Y] at each step. Here is a program that implements this idea: {{ X = m }} Y ::= 0;; - WHILE !(X = 0) DO + WHILE ~(X = 0) DO X ::= X - 1;; Y ::= Y + 1 END @@ -582,11 +579,12 @@ Definition manual_grade_for_decorations_in_slow_assignment : option (nat*string) (* ================================================================= *) (** ** Exercise: Slow Addition *) -(** **** 练习:3 星, optional (add_slowly_decoration) *) -(** The following program adds the variable X into the variable Z +(** **** 练习:3 星, standard, optional (add_slowly_decoration) + + The following program adds the variable X into the variable Z by repeatedly decrementing X and incrementing Z. - WHILE !(X = 0) DO + WHILE ~(X = 0) DO Z ::= Z + 1;; X ::= X - 1 END @@ -596,8 +594,9 @@ Definition manual_grade_for_decorations_in_slow_assignment : option (nat*string) specification of [add_slowly]; then (informally) decorate the program accordingly. *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ================================================================= *) (** ** Example: Parity *) @@ -648,8 +647,9 @@ Fixpoint parity x := [parity]). For verifying (c), we observe that, when [2 <= X], we have [parity X = parity (X-2)]. *) -(** **** 练习:3 星, optional (parity_formal) *) -(** Translate this proof to Coq. Refer to the [reduce_to_zero] example +(** **** 练习:3 星, standard, optional (parity_formal) + + Translate this proof to Coq. Refer to the [reduce_to_zero] example for ideas. You may find the following two lemmas useful: *) Lemma parity_ge_2 : forall x, @@ -682,7 +682,6 @@ Proof. (* ================================================================= *) (** ** Example: Finding Square Roots *) - (** The following program computes the (integer) square root of [X] by naive iteration: @@ -714,13 +713,14 @@ Proof. Looking at condition (c), we see that the second conjunct of (4) is almost the same as the first conjunct of (5), except that (4) mentions [X] while (5) mentions [m]. But note that [X] is never - assigned in this program, so we should always have [X=m], but we - didn't propagate this information from (1) into the loop invariant. + assigned in this program, so we should always have [X=m]; we + didn't propagate this information from (1) into the loop + invariant, but we could! - Also, looking at the second conjunct of (8), it seems quite - hopeless as an invariant (why?); fortunately, we don't need it, - since we can obtain it from the negation of the guard -- the third - conjunct in (7) -- again under the assumption that [X=m]. + Also, we don't need the second conjunct of (8), since we can + obtain it from the negation of the guard -- the third conjunct + in (7) -- again under the assumption that [X=m]. This allows + us to simplify a bit. So we now try [X=m /\ Z*Z <= m] as the loop invariant: @@ -731,7 +731,7 @@ Proof. WHILE (Z+1)*(Z+1) <= X DO {{ X=m /\ Z*Z<=m /\ (Z+1)*(Z+1)<=X }} ->> (c - OK) {{ X=m /\ (Z+1)*(Z+1)<=m }} - Z ::= Z+1 + Z ::= Z + 1 {{ X=m /\ Z*Z<=m }} END {{ X=m /\ Z*Z<=m /\ X<(Z+1)*(Z+1) }} ->> (b - OK) @@ -740,7 +740,7 @@ Proof. This works, since conditions (a), (b), and (c) are now all trivially satisfied. - Very often, even if a variable is used in a loop in a read-only + Very often, if a variable is used in a loop in a read-only fashion (i.e., it is referred to by the program or by the specification and it is not changed by the loop), it is necessary to add the fact that it doesn't change to the loop invariant. *) @@ -748,13 +748,12 @@ Proof. (* ================================================================= *) (** ** Example: Squaring *) - (** Here is a program that squares [X] by repeated addition: {{ X = m }} Y ::= 0;; Z ::= 0;; - WHILE !(Y = X) DO + WHILE ~(Y = X) DO Z ::= Z + X;; Y ::= Y + 1 END @@ -774,7 +773,7 @@ Proof. {{ 0 = m*m /\ X = m }} Z ::= 0;; {{ Z = m*m /\ X = m }} - WHILE !(Y = X) DO + WHILE ~(Y = X) DO {{ Z = Y*m /\ X = m /\ Y <> X }} ->> (c - WRONG) {{ Z+X = m*m /\ X = m }} Z ::= Z + X;; @@ -785,7 +784,6 @@ Proof. {{ Z = m*m /\ X = m /\ ~(Y <> X) }} ->> (b - OK) {{ Z = m*m }} - Conditions (a) and (c) fail because of the [Z = m*m] part. While [Z] starts at [0] and works itself up to [m*m], we can't expect [Z] to be [m*m] from the start. If we look at how [Z] progresses @@ -800,7 +798,7 @@ Proof. {{ 0 = Y*m /\ X = m }} Z ::= 0;; {{ Z = Y*m /\ X = m }} - WHILE !(Y = X) DO + WHILE ~(Y = X) DO {{ Z = Y*m /\ X = m /\ Y <> X }} ->> (c - OK) {{ Z+X = (Y+1)*m /\ X = m }} Z ::= Z + X; @@ -811,41 +809,43 @@ Proof. {{ Z = Y*m /\ X = m /\ ~(Y <> X) }} ->> (b - OK) {{ Z = m*m }} - This new invariant makes the proof go through: all three conditions are easy to check. It is worth comparing the postcondition [Z = m*m] and the [Z = Y*m] conjunct of the invariant. It is often the case that one has - to replace parameters with variables -- or - with expressions involving both variables and parameters, like - [m - Y] -- when going from postconditions to invariants. *) + to replace parameters with variables -- or with expressions + involving both variables and parameters, like [m - Y] -- when + going from postconditions to invariants. *) (* ================================================================= *) (** ** Exercise: Factorial *) -(** **** 练习:3 星 (factorial) *) -(** Recall that [n!] denotes the factorial of [n] (i.e., [n! = +(** **** 练习:3 星, standard (factorial) + + Recall that [n!] denotes the factorial of [n] (i.e., [n! = 1*2*...*n]). Here is an Imp program that calculates the factorial of the number initially stored in the variable [X] and puts it in the variable [Y]: {{ X = m }} Y ::= 1 ;; - WHILE !(X = 0) + WHILE ~(X = 0) DO Y ::= Y * X ;; X ::= X - 1 END {{ Y = m! }} - Fill in the blanks in following decorated program: + Fill in the blanks in following decorated program. For full credit, + make sure all the arithmetic operations used in the assertions are + well-defined on natural numbers. {{ X = m }} ->> {{ }} Y ::= 1;; {{ }} - WHILE !(X = 0) + WHILE ~(X = 0) DO {{ }} ->> {{ }} Y ::= Y * X;; @@ -857,16 +857,24 @@ Proof. {{ Y = m! }} *) - (* 请勿修改下面这一行: *) Definition manual_grade_for_decorations_in_factorial : option (nat*string) := None. (** [] *) +(* LY: I saw one submission for [factorial_dec] use a program like that instead + of the one already given by the informal exercise. I accepted it because the + exercise does not require to reuse the given program, and we did not + strictly define what it means to "implement" factorial in Imp. + This other one "implements" factorial in the same way two_loops_dec + "implements" the sum (a + b + c). +*) + (* ================================================================= *) (** ** Exercise: Min *) -(** **** 练习:3 星 (Min_Hoare) *) -(** Fill in valid decorations for the following program. +(** **** 练习:3 星, standard (Min_Hoare) + + Fill in valid decorations for the following program. For the [=>] steps in your annotations, you may rely (silently) on the following facts about min @@ -885,7 +893,7 @@ Definition manual_grade_for_decorations_in_factorial : option (nat*string) := No {{ }} Z ::= 0;; {{ }} - WHILE !(X = 0) && !(Y = 0) DO + WHILE ~(X = 0) && ~(Y = 0) DO {{ }} ->> {{ }} X := X - 1;; @@ -899,57 +907,57 @@ Definition manual_grade_for_decorations_in_factorial : option (nat*string) := No {{ Z = min a b }} *) - (* 请勿修改下面这一行: *) Definition manual_grade_for_decorations_in_Min_Hoare : option (nat*string) := None. (** [] *) -(** **** 练习:3 星 (two_loops) *) -(** Here is a very inefficient way of adding 3 numbers: +(** **** 练习:3 星, standard (two_loops) - X ::= 0;; - Y ::= 0;; - Z ::= c;; - WHILE !(X = a) DO - X ::= X + 1;; - Z ::= Z + 1 - END;; - WHILE !(Y = b) DO - Y ::= Y + 1;; - Z ::= Z + 1 - END + Here is a very inefficient way of adding 3 numbers: + + X ::= 0;; + Y ::= 0;; + Z ::= c;; + WHILE ~(X = a) DO + X ::= X + 1;; + Z ::= Z + 1 + END;; + WHILE ~(Y = b) DO + Y ::= Y + 1;; + Z ::= Z + 1 + END Show that it does what it should by filling in the blanks in the following decorated program. - {{ True }} ->> - {{ }} - X ::= 0;; - {{ }} - Y ::= 0;; - {{ }} - Z ::= c;; - {{ }} - WHILE !(X = a) DO - {{ }} ->> - {{ }} - X ::= X + 1;; + {{ True }} ->> {{ }} - Z ::= Z + 1 + X ::= 0;; {{ }} - END;; - {{ }} ->> - {{ }} - WHILE !(Y = b) DO - {{ }} ->> + Y ::= 0;; {{ }} - Y ::= Y + 1;; + Z ::= c;; {{ }} - Z ::= Z + 1 + WHILE ~(X = a) DO + {{ }} ->> + {{ }} + X ::= X + 1;; + {{ }} + Z ::= Z + 1 + {{ }} + END;; + {{ }} ->> {{ }} - END - {{ }} ->> - {{ Z = a + b + c }} + WHILE ~(Y = b) DO + {{ }} ->> + {{ }} + Y ::= Y + 1;; + {{ }} + Z ::= Z + 1 + {{ }} + END + {{ }} ->> + {{ Z = a + b + c }} *) (* 请勿修改下面这一行: *) @@ -959,14 +967,15 @@ Definition manual_grade_for_decorations_in_two_loops : option (nat*string) := No (* ================================================================= *) (** ** Exercise: Power Series *) -(** **** 练习:4 星, optional (dpow2_down) *) -(** Here is a program that computes the series: +(** **** 练习:4 星, standard, optional (dpow2_down) + + Here is a program that computes the series: [1 + 2 + 2^2 + ... + 2^m = 2^(m+1) - 1] X ::= 0;; Y ::= 1;; Z ::= 1;; - WHILE !(X = m) DO + WHILE ~(X = m) DO Z ::= 2 * Z;; Y ::= Y + Z;; X ::= X + 1 @@ -974,8 +983,9 @@ Definition manual_grade_for_decorations_in_two_loops : option (nat*string) := No Write a decorated program for this. *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ################################################################# *) (** * Weakest Preconditions (Optional) *) @@ -1021,8 +1031,9 @@ Definition is_wp P c Q := _weakest_ (easiest to satisfy) assertion that guarantees that [Q] will hold after executing [c]. *) -(** **** 练习:1 星, optional (wp) *) -(** What are the weakest preconditions of the following commands +(** **** 练习:1 星, standard, optional (wp) + + What are the weakest preconditions of the following commands for the following postconditions? 1) {{ ? }} SKIP {{ X = 5 }} @@ -1032,7 +1043,7 @@ Definition is_wp P c Q := 3) {{ ? }} X ::= Y {{ X = Y }} 4) {{ ? }} - IFB X == 0 THEN Y ::= Z + 1 ELSE Y ::= W + 2 FI + TEST X = 0 THEN Y ::= Z + 1 ELSE Y ::= W + 2 FI {{ Y = 5 }} 5) {{ ? }} @@ -1043,11 +1054,13 @@ Definition is_wp P c Q := WHILE true DO X ::= 0 END {{ X = 0 }} *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) + +(** **** 练习:3 星, advanced, optional (is_wp_formal) -(** **** 练习:3 星, advanced, optional (is_wp_formal) *) -(** Prove formally, using the definition of [hoare_triple], that [Y <= 4] + Prove formally, using the definition of [hoare_triple], that [Y <= 4] is indeed the weakest precondition of [X ::= Y + 1] with respect to postcondition [X <= 5]. *) @@ -1058,8 +1071,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, advanced, optional (hoare_asgn_weakest) *) -(** Show that the precondition in the rule [hoare_asgn] is in fact the +(** **** 练习:2 星, advanced, optional (hoare_asgn_weakest) + + Show that the precondition in the rule [hoare_asgn] is in fact the weakest precondition. *) Theorem hoare_asgn_weakest : forall Q X a, @@ -1068,8 +1082,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:2 星, advanced, optional (hoare_havoc_weakest) *) -(** Show that your [havoc_pre] rule from the [himp_hoare] exercise +(** **** 练习:2 星, advanced, optional (hoare_havoc_weakest) + + Show that your [havoc_pre] rule from the [himp_hoare] exercise in the [Hoare] chapter returns the weakest precondition. *) Module Himp2. Import Himp. @@ -1082,9 +1097,8 @@ Proof. End Himp2. (** [] *) - (* ################################################################# *) -(** * Formal Decorated Programs (Optional) *) +(** * Formal Decorated Programs (Advanced) *) (** Our informal conventions for decorated programs amount to a way of displaying Hoare triples, in which commands are annotated @@ -1104,11 +1118,11 @@ End Himp2. (** We don't want both preconditions and postconditions on each command, because a sequence of two commands would contain - redundant decorations, the postcondition of the first likely - being the same as the precondition of the second. Instead, - decorations are added corresponding to each postcondition. - A separate type, [decorated], is used to add the precondition - for the entire program. **) + redundant decorations--the postcondition of the first likely being + the same as the precondition of the second. Instead, decorations + are added corresponding to postconditions only. A separate type, + [decorated], is used to add just one precondition for the entire + program. **) Inductive dcom : Type := | DCSkip : Assertion -> dcom @@ -1123,6 +1137,8 @@ Inductive dcom : Type := Inductive decorated : Type := | Decorated : Assertion -> dcom -> decorated. +Delimit Scope default with default. + Notation "'SKIP' {{ P }}" := (DCSkip P) (at level 10) : dcom_scope. @@ -1132,7 +1148,7 @@ Notation "l '::=' a {{ P }}" Notation "'WHILE' b 'DO' {{ Pbody }} d 'END' {{ Ppost }}" := (DCWhile b Pbody d Ppost) (at level 80, right associativity) : dcom_scope. -Notation "'IFB' b 'THEN' {{ P }} d 'ELSE' {{ P' }} d' 'FI' {{ Q }}" +Notation "'TEST' b 'THEN' {{ P }} d 'ELSE' {{ P' }} d' 'FI' {{ Q }}" := (DCIf b P d P' d' Q) (at level 80, right associativity) : dcom_scope. Notation "'->>' {{ P }} d" @@ -1150,6 +1166,14 @@ Notation "{{ P }} d" Delimit Scope dcom_scope with dcom. Open Scope dcom_scope. + +Example dec0 := + SKIP {{ fun st => True }}. +Example dec1 := + WHILE true DO {{ fun st => True }} SKIP {{ fun st => True }} END + {{ fun st => True }}. +Set Printing All. + (** To avoid clashing with the existing [Notation] definitions for ordinary [com]mands, we introduce these notations in a special scope called [dcom_scope], and we [Open] this scope for the @@ -1162,8 +1186,8 @@ Open Scope dcom_scope. of the program. *) Example dec_while : decorated := - {{ fun st => True }} - WHILE !(X = 0) + {{ fun st => True }} + WHILE ~(X = 0) DO {{ fun st => True /\ st X <> 0}} X ::= X - 1 @@ -1175,12 +1199,12 @@ Example dec_while : decorated := (** It is easy to go from a [dcom] to a [com] by erasing all annotations. *) -Fixpoint extract (d:dcom) : com := +Fixpoint extract (d : dcom) : com := match d with | DCSkip _ => SKIP | DCSeq d1 d2 => (extract d1 ;; extract d2) | DCAsgn X a _ => X ::= a - | DCIf b _ d1 _ d2 _ => IFB b THEN extract d1 ELSE extract d2 FI + | DCIf b _ d1 _ d2 _ => TEST b THEN extract d1 ELSE extract d2 FI | DCWhile b _ d _ => WHILE b DO extract d END | DCPre _ d => extract d | DCPost d _ => extract d @@ -1191,7 +1215,6 @@ Definition extract_dec (dec : decorated) : com := | Decorated P d => extract d end. - (** The choice of exactly where to put assertions in the definition of [dcom] is a bit subtle. The simplest thing to do would be to annotate every [dcom] with a precondition and postcondition. But @@ -1216,7 +1239,7 @@ Definition extract_dec (dec : decorated) : com := triple [{{P}} (extract d) {{post d}}], where [post] is defined as follows: *) -Fixpoint post (d:dcom) : Assertion := +Fixpoint post (d : dcom) : Assertion := match d with | DCSkip P => P | DCSeq d1 d2 => post d2 @@ -1268,8 +1291,7 @@ Definition dec_correct (dec : decorated) := add some uses of the rule of consequence, but the correspondence should be clear.) *) -Fixpoint verification_conditions (P : Assertion) (d:dcom) - : Prop := +Fixpoint verification_conditions (P : Assertion) (d : dcom) : Prop := match d with | DCSkip Q => (P ->> Q) @@ -1310,7 +1332,7 @@ Proof. apply hoare_skip. assumption. - (* Seq *) - inversion H as [H1 H2]. clear H. + destruct H as [H1 H2]. eapply hoare_seq. apply IHd2. apply H2. apply IHd1. apply H1. @@ -1319,8 +1341,7 @@ Proof. apply hoare_asgn. assumption. - (* If *) - inversion H as [HPre1 [HPre2 [Hd1 [Hd2 [HThen HElse]]]]]. - clear H. + destruct H as [HPre1 [HPre2 [Hd1 [Hd2 [HThen HElse]]]]]. apply IHd1 in HThen. clear IHd1. apply IHd2 in HElse. clear IHd2. apply hoare_if. @@ -1329,16 +1350,16 @@ Proof. + eapply hoare_consequence_post with (Q':=post d2); eauto. eapply hoare_consequence_pre; eauto. - (* While *) - inversion H as [Hpre [Hbody1 [Hpost1 Hd]]]. clear H. + destruct H as [Hpre [Hbody1 [Hpost1 Hd]]]. eapply hoare_consequence_pre; eauto. eapply hoare_consequence_post; eauto. apply hoare_while. eapply hoare_consequence_pre; eauto. - (* Pre *) - inversion H as [HP Hd]; clear H. + destruct H as [HP Hd]. eapply hoare_consequence_pre. apply IHd. apply Hd. assumption. - (* Post *) - inversion H as [Hd HQ]; clear H. + destruct H as [Hd HQ]. eapply hoare_consequence_post. apply IHd. apply Hd. assumption. Qed. @@ -1364,15 +1385,16 @@ Qed. Eval simpl in (verification_conditions_dec dec_while). (** - ==> + ===> (((fun _ : state => True) ->> (fun _ : state => True)) /\ - ((fun st : state => True /\ bassn (! (X = 0)) st) ->> + ((fun st : state => True /\ bassn (~(X = 0)) st) ->> (fun st : state => True /\ st X <> 0)) /\ - ((fun st : state => True /\ ~ bassn (! (X = 0)) st) ->> + ((fun st : state => True /\ ~ bassn (~(X = 0)) st) ->> (fun st : state => True /\ st X = 0)) /\ (fun st : state => True /\ st X <> 0) ->> (fun _ : state => True) [X |-> X - 1]) /\ - (fun st : state => True /\ st X = 0) ->> (fun st : state => st X = 0) + (fun st : state => True /\ st X = 0) ->> + (fun st : state => st X = 0) *) (** In principle, we could work with such propositions using just the @@ -1414,8 +1436,8 @@ Tactic Notation "verify" := (** What's left after [verify] does its thing is "just the interesting parts" of checking that the decorations are correct. For very - simple examples [verify] immediately solves the goal (provided - that the annotations are correct!). *) + simple examples, [verify] sometimes even immediately solves the + goal (provided that the annotations are correct!). *) Theorem dec_while_correct : dec_correct dec_while. @@ -1424,10 +1446,10 @@ Proof. verify. Qed. (** Another example (formalizing a decorated program we've seen before): *) -Example subtract_slowly_dec (m:nat) (p:nat) : decorated := +Example subtract_slowly_dec (m : nat) (p : nat) : decorated := {{ fun st => st X = m /\ st Z = p }} ->> {{ fun st => st Z - st X = p - m }} - WHILE ! (X = 0) + WHILE ~(X = 0) DO {{ fun st => st Z - st X = p - m /\ st X <> 0 }} ->> {{ fun st => (st Z - 1) - (st X - 1) = p - m }} Z ::= Z - 1 @@ -1476,14 +1498,14 @@ Proof. intros; verify. Qed. (** *** Simple Conditionals *) Definition if_minus_plus_com := - IFB X <= Y + (TEST X <= Y THEN Z ::= Y - X ELSE Y ::= X + Z - FI. + FI)%imp. Definition if_minus_plus_dec := {{fun st => True}} - IFB X <= Y THEN + TEST X <= Y THEN {{ fun st => True /\ st X <= st Y }} ->> {{ fun st => st Y = st X + (st Y - st X) }} Z ::= Y - X @@ -1502,7 +1524,7 @@ Proof. verify. Qed. Definition if_minus_dec := {{fun st => True}} - IFB X <= Y THEN + TEST X <= Y THEN {{fun st => True /\ st X <= st Y }} ->> {{fun st => (st Y - st X) + st X = st Y \/ (st Y - st X) + st Y = st X}} @@ -1521,7 +1543,6 @@ Theorem if_minus_correct : dec_correct if_minus_dec. Proof. verify. Qed. - (* ----------------------------------------------------------------- *) (** *** Division *) @@ -1563,7 +1584,7 @@ Definition find_parity : com := Inductive ev : nat -> Prop := | ev_0 : ev O - | ev_SS : forall n:nat, ev n -> ev (S (S n)). + | ev_SS : forall n : nat, ev n -> ev (S (S n)). Definition find_parity_dec m : decorated := {{ fun st => st X = m}} ->> @@ -1749,7 +1770,7 @@ Definition square_dec (m : nat) : decorated := Z ::= 0 {{ fun st => st X = m /\ st Y = m /\ st Z = 0}} ->> {{ fun st => st Z + st X * st Y = m * m }};; - WHILE !(Y = 0) DO + WHILE ~(Y = 0) DO {{ fun st => st Z + st X * st Y = m * m /\ st Y <> 0 }} ->> {{ fun st => (st Z + st X) + st X * (st Y - 1) = m * m }} Z ::= Z + X @@ -1784,7 +1805,7 @@ Definition square_dec' (n : nat) : decorated := {{ fun st => st X = n /\ st Y = n /\ st Z = 0 }} ->> {{ fun st => st Z = st X * (st X - st Y) /\ st X = n /\ st Y <= st X }};; - WHILE !(Y = 0) DO + WHILE ~(Y = 0) DO {{ fun st => (st Z = st X * (st X - st Y) /\ st X = n /\ st Y <= st X) /\ st Y <> 0 }} @@ -1829,7 +1850,7 @@ Definition square_simpler_dec (m : nat) : decorated := Z ::= 0 {{ fun st => st Z = (st Y)*m /\ st X = m }}->> {{ fun st => st Z = (st Y)*m /\ st X = m }};; - WHILE !(Y = X) DO + WHILE ~(Y = X) DO {{ fun st => (st Z = (st Y)*m /\ st X = m) /\ st Y <> st X }} ->> {{ fun st => st Z + st X = ((st Y) + 1)*m /\ st X = m }} @@ -1861,7 +1882,7 @@ Definition two_loops_dec (a b c : nat) : decorated := {{ fun st => c = st X + c /\ st Y = 0 }};; Z ::= c {{ fun st => st Z = st X + c /\ st Y = 0 }};; - WHILE !(X = a) DO + WHILE ~(X = a) DO {{ fun st => (st Z = st X + c /\ st Y = 0) /\ st X <> a }} ->> {{ fun st => st Z + 1 = st X + 1 + c /\ st Y = 0 }} X ::= X + 1 @@ -1871,7 +1892,7 @@ Definition two_loops_dec (a b c : nat) : decorated := END {{ fun st => (st Z = st X + c /\ st Y = 0) /\ st X = a }} ->> {{ fun st => st Z = a + st Y + c }};; - WHILE !(Y = b) DO + WHILE ~(Y = b) DO {{ fun st => st Z = a + st Y + c /\ st Y <> b }} ->> {{ fun st => st Z + 1 = a + st Y + 1 + c }} Y ::= Y + 1 @@ -1895,7 +1916,7 @@ Fixpoint pow2 n := | S n' => 2 * (pow2 n') end. -Definition dpow2_down (n: nat) := +Definition dpow2_down (n : nat) := {{ fun st => True }} ->> {{ fun st => 1 = (pow2 (0 + 1))-1 /\ 1 = pow2 0 }} X ::= 0 @@ -1904,7 +1925,7 @@ Definition dpow2_down (n: nat) := {{ fun st => st Y = (pow2 (st X + 1))-1 /\ 1 = pow2 (st X) }};; Z ::= 1 {{ fun st => st Y = (pow2 (st X + 1))-1 /\ st Z = pow2 (st X) }};; - WHILE !(X = n) DO + WHILE ~(X = n) DO {{ fun st => (st Y = (pow2 (st X + 1))-1 /\ st Z = pow2 (st X)) /\ st X <> n }} ->> {{ fun st => st Y + 2 * st Z = (pow2 (st X + 2))-1 @@ -1955,14 +1976,15 @@ Qed. (* ================================================================= *) (** ** Further Exercises *) -(** **** 练习:3 星, advanced (slow_assignment_dec) *) -(** In the [slow_assignment] exercise above, we saw a roundabout way +(** **** 练习:3 星, advanced (slow_assignment_dec) + + In the [slow_assignment] exercise above, we saw a roundabout way of assigning a number currently stored in [X] to the variable [Y]: start [Y] at [0], then decrement [X] until it hits [0], incrementing [Y] at each step. Write a formal version of this decorated program and prove it correct. *) -Example slow_assignment_dec (m:nat) : decorated +Example slow_assignment_dec (m : nat) : decorated (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Theorem slow_assignment_dec_correct : forall m, @@ -1973,10 +1995,11 @@ Proof. (* 请在此处解答 *) Admitted. Definition manual_grade_for_check_defn_of_slow_assignment_dec : option (nat*string) := None. (** [] *) -(** **** 练习:4 星, advanced (factorial_dec) *) -(** Remember the factorial function we worked with before: *) +(** **** 练习:4 星, advanced (factorial_dec) -Fixpoint real_fact (n:nat) : nat := + Remember the factorial function we worked with before: *) + +Fixpoint real_fact (n : nat) : nat := match n with | O => 1 | S n' => n * (real_fact n') @@ -1992,8 +2015,9 @@ Fixpoint real_fact (n:nat) : nat := Definition manual_grade_for_factorial_dec : option (nat*string) := None. (** [] *) -(** **** 练习:4 星, advanced, optional (fib_eqn) *) -(** The Fibonacci function is usually written like this: +(** **** 练习:4 星, advanced, optional (fib_eqn) + + The Fibonacci function is usually written like this: Fixpoint fib n := match n with @@ -2014,8 +2038,6 @@ Fixpoint fib n := end end. - - (** Prove that [fib] satisfies the following equation: *) Lemma fib_eqn : forall n, @@ -2025,15 +2047,16 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced, optional (fib) *) -(** The following Imp program leaves the value of [fib n] in the +(** **** 练习:4 星, advanced, optional (fib) + + The following Imp program leaves the value of [fib n] in the variable [Y] when it terminates: X ::= 1;; Y ::= 1;; Z ::= 1;; - WHILE !(X = n+1) DO - T ::= Z; + WHILE ~(X = n + 1) DO + T ::= Z;; Z ::= Z + Y;; Y ::= T;; X ::= X + 1 @@ -2042,12 +2065,12 @@ Proof. Fill in the following definition of [dfib] and prove that it satisfies this specification: - {{True}} dfib {{ Y = fib n }} + {{ True }} dfib {{ Y = fib n }} *) Definition T : string := "T". -Definition dfib (n:nat) : decorated +Definition dfib (n : nat) : decorated (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Theorem dfib_correct : forall n, @@ -2055,8 +2078,9 @@ Theorem dfib_correct : forall n, (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:5 星, advanced, optional (improve_dcom) *) -(** The formal decorated programs defined in this section are intended +(** **** 练习:5 星, advanced, optional (improve_dcom) + + The formal decorated programs defined in this section are intended to look as similar as possible to the informal ones defined earlier in the chapter. If we drop this requirement, we can eliminate almost all annotations, just requiring final postconditions and @@ -2065,16 +2089,18 @@ Theorem dfib_correct : forall n, rest of the formal development leading up to the [verification_correct] theorem. *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 -(** **** 练习:4 星, advanced, optional (implement_dcom) *) -(** Adapt the parser for Imp presented in chapter [ImpParser] + [] *) + +(** **** 练习:4 星, advanced, optional (implement_dcom) + + Adapt the parser for Imp presented in chapter [ImpParser] of _Logical Foundations_ to parse decorated commands (either ours or, even better, the ones you defined in the previous exercise). *) -(* 请在此处解答 *) -(** [] *) - +(* 请在此处解答 + [] *) +(* Sat Jan 26 15:15:43 UTC 2019 *) diff --git a/plf-current/Hoare2Test.v b/plf-current/Hoare2Test.v index 1db33516..0944821a 100644 --- a/plf-current/Hoare2Test.v +++ b/plf-current/Hoare2Test.v @@ -128,3 +128,5 @@ Print Assumptions slow_assignment_dec_correct. idtac "---------- factorial_dec ---------". idtac "MANUAL". Abort. + +(* Sat Jan 26 15:15:59 UTC 2019 *) diff --git a/plf-current/HoareAsLogic.html b/plf-current/HoareAsLogic.html index ca5943f8..43e04a8c 100644 --- a/plf-current/HoareAsLogic.html +++ b/plf-current/HoareAsLogic.html @@ -58,30 +58,30 @@Further Exercises
+Further Exercises
-练习:3 星, advanced (slow_assignment_dec)
+练习:3 星, advanced (slow_assignment_dec)
In the slow_assignment exercise above, we saw a roundabout way of assigning a number currently stored in X to the variable Y: start Y at 0, then decrement X until it hits 0, @@ -2595,9 +2609,9 @@Hoare2Hoare Logic, Part II
-Example slow_assignment_dec (m:nat) : decorated
+Example slow_assignment_dec (m : nat) : decorated
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem slow_assignment_dec_correct : ∀ m,
+Theorem slow_assignment_dec_correct : ∀m,
dec_correct (slow_assignment_dec m).
Proof. (* 请在此处解答 *) Admitted.
(* 请勿修改下面这一行: *)
@@ -2608,12 +2622,12 @@Hoare2Hoare Logic, Part II
-练习:4 星, advanced (factorial_dec)
+练习:4 星, advanced (factorial_dec)
Remember the factorial function we worked with before:-Fixpoint real_fact (n:nat) : nat :=
+Fixpoint real_fact (n : nat) : nat :=
match n with
| O ⇒ 1
| S n' ⇒ n * (real_fact n')
@@ -2636,7 +2650,7 @@Hoare2Hoare Logic, Part II
-练习:4 星, advanced, optional (fib_eqn)
+练习:4 星, advanced, optional (fib_eqn)
The Fibonacci function is usually written like this:@@ -2663,7 +2677,7 @@Hoare2Hoare Logic, Part II | S n'' ⇒ fib n' + fib n''
end
- end.
+ end.
@@ -2671,7 +2685,7 @@@@ -2727,7 +2741,7 @@Hoare2Hoare Logic, Part II
-Lemma fib_eqn : ∀ n,
+Lemma fib_eqn : ∀n,
n > 0 →
fib n + fib (Init.Nat.pred n) = fib (n + 1).
Proof.
@@ -2682,7 +2696,7 @@Hoare2Hoare Logic, Part II
-练习:4 星, advanced, optional (fib)
+练习:4 星, advanced, optional (fib)
The following Imp program leaves the value of fib n in the variable Y when it terminates: @@ -2692,8 +2706,8 @@Hoare2Hoare Logic, Part IIX ::= 1;;
Y ::= 1;;
Z ::= 1;;
- WHILE !(X = n+1) DO
- T ::= Z;
+ WHILE ~(X = n + 1) DO
+ T ::= Z;;
Z ::= Z + Y;;
Y ::= T;;
X ::= X + 1
@@ -2707,7 +2721,7 @@Hoare2Hoare Logic, Part II
- {{True}} dfib {{ Y = fib n }} + {{ True }} dfib {{ Y = fib n }}@@ -2716,9 +2730,9 @@Hoare2Hoare Logic, Part II Definition T : string := "T".
-Definition dfib (n:nat) : decorated
+Definition dfib (n : nat) : decorated
(* 将本行替换成 ":= _你的_定义_ ." *). Admitted.
-Theorem dfib_correct : ∀ n,
+Theorem dfib_correct : ∀n,
dec_correct (dfib n).
(* 请在此处解答 *) Admitted.
Hoare2Hoare Logic, Part II
-练习:5 星, advanced, optional (improve_dcom)
+练习:5 星, advanced, optional (improve_dcom)
The formal decorated programs defined in this section are intended to look as similar as possible to the informal ones defined earlier in the chapter. If we drop this requirement, we can eliminate @@ -2746,7 +2760,7 @@Hoare2Hoare Logic, Part II
-练习:4 星, advanced, optional (implement_dcom)
+练习:4 星, advanced, optional (implement_dcom)
Adapt the parser for Imp presented in chapter ImpParser of _Logical Foundations_ to parse decorated commands (either ours or, even better, the ones you defined in the previous exercise). @@ -2757,6 +2771,10 @@Hoare2Hoare Logic, Part II ☐ +
+ +(* Sat Jan 26 15:15:43 UTC 2019 *)
+HoareAsLogic证明论霍尔逻辑
@@ -91,9 +91,9 @@
Inductive hoare_proof : Assertion → com → Assertion → Type :=
- | H_Skip : ∀ P,
+ | H_Skip : ∀P,
hoare_proof P (SKIP) P
- | H_Asgn : ∀ Q V a,
+ | H_Asgn : ∀Q V a,
hoare_proof (assn_sub V a Q) (V ::= a) Q
- | H_Seq : ∀ P c Q d R,
+ | H_Seq : ∀P c Q d R,
hoare_proof P c Q → hoare_proof Q d R → hoare_proof P (c;;d) R
- | H_If : ∀ P Q b c1 c2,
+ | H_If : ∀P Q b c1 c2,
hoare_proof (fun st ⇒ P st ∧ bassn b st) c1 Q →
hoare_proof (fun st ⇒ P st ∧ ~(bassn b st)) c2 Q →
- hoare_proof P (IFB b THEN c1 ELSE c2 FI) Q
- | H_While : ∀ P b c,
+ hoare_proof P (TEST b THEN c1 ELSE c2 FI) Q
+ | H_While : ∀P b c,
hoare_proof (fun st ⇒ P st ∧ bassn b st) c P →
- hoare_proof P (WHILE b DO c END) (fun st ⇒ P st ∧ ¬ (bassn b st))
- | H_Consequence : ∀ (P Q P' Q' : Assertion) c,
+ hoare_proof P (WHILE b DO c END) (fun st ⇒ P st ∧ ¬(bassn b st))
+ | H_Consequence : ∀(P Q P' Q' : Assertion) c,
hoare_proof P' c Q' →
- (∀ st, P st → P' st) →
- (∀ st, Q' st → Q st) →
+ (∀st, P st → P' st) →
+ (∀st, Q' st → Q st) →
hoare_proof P c Q.
HoareAsLogic证明论霍尔逻辑
-Lemma H_Consequence_pre : ∀ (P Q P': Assertion) c,
+Lemma H_Consequence_pre : ∀(P Q P': Assertion) c,
hoare_proof P' c Q →
- (∀ st, P st → P' st) →
+ (∀st, P st → P' st) →
hoare_proof P c Q.
@@ -103,9 +103,9 @@diff --git a/plf-current/HoareAsLogic.v b/plf-current/HoareAsLogic.v index 829a9d48..2f652ca4 100644 --- a/plf-current/HoareAsLogic.v +++ b/plf-current/HoareAsLogic.v @@ -27,7 +27,7 @@ Inductive hoare_proof : Assertion -> com -> Assertion -> Type := | H_If : forall P Q b c1 c2, hoare_proof (fun st => P st /\ bassn b st) c1 Q -> hoare_proof (fun st => P st /\ ~(bassn b st)) c2 Q -> - hoare_proof P (IFB b THEN c1 ELSE c2 FI) Q + hoare_proof P (TEST b THEN c1 ELSE c2 FI) Q | H_While : forall P b c, hoare_proof (fun st => P st /\ bassn b st) c P -> hoare_proof P (WHILE b DO c END) (fun st => P st /\ ~ (bassn b st)) @@ -94,8 +94,9 @@ Print sample_proof. (* ################################################################# *) (** * 性质 *) -(** **** 练习:2 星 (hoare_proof_sound) *) -(** 证明这些证明对象是正确的断言。 *) +(** **** 练习:2 星, standard (hoare_proof_sound) + + 证明这些证明对象是正确的断言。 *) Theorem hoare_proof_sound : forall P c Q, hoare_proof P c Q -> {{P}} c {{Q}}. @@ -132,7 +133,7 @@ Proof. apply (IHc1 (fun _ => True)). apply IHc2. intros. apply I. - - (* IFB *) + - (* TEST *) apply H_Consequence_pre with (fun _ => True). apply H_If. apply IHc1. @@ -167,7 +168,7 @@ Proof. - (* SKIP *) pre_false_helper H_Skip. - (* ::= *) pre_false_helper H_Asgn. - (* ;; *) pre_false_helper H_Seq. apply IHc1. apply IHc2. - - (* IFB *) + - (* TEST *) apply H_If; eapply H_Consequence_pre. apply IHc1. intro. eapply False_and_P_imp. apply IHc2. intro. eapply False_and_P_imp. @@ -195,16 +196,16 @@ Qed. [P' -> P]。我们可以更加直接地将其定义为: *) Definition wp (c:com) (Q:Assertion) : Assertion := - fun s => forall s', c / s \\ s' -> Q s'. + fun s => forall s', s =[ c ]=> s' -> Q s'. -(** **** 练习:1 星 (wp_is_precondition) *) +(** **** 练习:1 星, standard (wp_is_precondition) *) Lemma wp_is_precondition: forall c Q, {{wp c Q}} c {{Q}}. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:1 星 (wp_is_weakest) *) +(** **** 练习:1 星, standard (wp_is_weakest) *) Lemma wp_is_weakest: forall c Q P', {{P'}} c {{Q}} -> forall st, P' st -> wp c Q st. @@ -220,8 +221,9 @@ Proof. Qed. (** [] *) -(** **** 练习:5 星 (hoare_proof_complete) *) -(** 完成如下定理的证明。 *) +(** **** 练习:5 星, standard (hoare_proof_complete) + + 完成如下定理的证明。 *) Theorem hoare_proof_complete: forall P c Q, {{P}} c {{Q}} -> hoare_proof P c Q. @@ -262,3 +264,4 @@ Proof. 满意:这太冗长了。在 [Hoare2] 一章中的关于形式化修饰程序的章节会向我们展 示如何做的更好。 *) +(* Sat Jan 26 15:15:43 UTC 2019 *) diff --git a/plf-current/HoareAsLogicTest.v b/plf-current/HoareAsLogicTest.v index 92ca4f53..9832716f 100644 --- a/plf-current/HoareAsLogicTest.v +++ b/plf-current/HoareAsLogicTest.v @@ -106,3 +106,5 @@ Print Assumptions hoare_proof_complete. idtac "". idtac "********** Advanced **********". Abort. + +(* Sat Jan 26 15:16:00 UTC 2019 *) diff --git a/plf-current/HoareTest.v b/plf-current/HoareTest.v index 2e480a7e..48ec8dba 100644 --- a/plf-current/HoareTest.v +++ b/plf-current/HoareTest.v @@ -192,3 +192,5 @@ Print Assumptions hoare_asgn_fwd. idtac "---------- hoare_repeat ---------". idtac "MANUAL". Abort. + +(* Sat Jan 26 15:15:55 UTC 2019 *) diff --git a/plf-current/Imp.v b/plf-current/Imp.v index 7b397ef0..ddfd0d54 100644 --- a/plf-current/Imp.v +++ b/plf-current/Imp.v @@ -1,13 +1,13 @@ (** * Imp: 简单的指令式程序 *) -(** 在本章中,我们会更加认真地看待如何用 Coq 来研究自身以外的有趣的东西。 +(** 在本章中,我们会更加认真地看待如何用 Coq 来研究其它东西。 我们的案例研究是一个名为 Imp 的_'简单的指令式编程语言'_, 它包含了传统主流语言(如 C 和 Java)的一小部分核心片段。下面是一个用 Imp 编写的常见数学函数: Z ::= X;; Y ::= 1;; - WHILE ! (Z = 0) DO + WHILE ~(Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 END @@ -19,12 +19,13 @@ _'霍尔逻辑(Hoare Logic)'_,它是一种广泛用于推理指令式程序的逻辑。 *) Set Warnings "-notation-overridden,-parsing". -Require Import Coq.Bool.Bool. -Require Import Coq.Init.Nat. -Require Import Coq.Arith.Arith. -Require Import Coq.Arith.EqNat. -Require Import Coq.omega.Omega. -Require Import Coq.Lists.List. +From Coq Require Import Bool.Bool. +From Coq Require Import Init.Nat. +From Coq Require Import Arith.Arith. +From Coq Require Import Arith.EqNat. +From Coq Require Import omega.Omega. +From Coq Require Import Lists.List. +From Coq Require Import Strings.String. Import ListNotations. From PLF Require Import Maps. @@ -58,11 +59,11 @@ Inductive bexp : Type := | BAnd (b1 b2 : bexp). (** 在本章中,我们省略了大部分从程序员实际编写的具体语法到其抽象语法树的翻译 - -- 例如,它会将字符串 ["1+2*3"] 翻译成如下 AST: + -- 例如,它会将字符串 ["1 + 2 * 3"] 翻译成如下 AST: APlus (ANum 1) (AMult (ANum 2) (ANum 3)). - 可选的章节 [ImpParser] 中开发了一个简单的词法分析器和解析器的实现, + 可选的章节 [ImpParser] 中开发了一个简单的词法分析器和解析器, 它可以进行这种翻译。你_'无需'_通过理解该章来理解本章, 但如果你没有上过涵盖这些技术的课程(例如编译器课程),可能想要略读一下该章节。 *) @@ -77,26 +78,26 @@ Inductive bexp : Type := | false | a = a | a <= a - | not b - | b and b + | ~ b + | b && b *) (** 与前面的 Coq 版本相对比... - BNF 是非形式化的 -- 例如,它给出了表达式表面上的语法的建议 - (例如加法运算写作 [+] 且它是一个中缀符),而没有指定词法分析和解析的其它方面 + (例如加法运算符写作中缀的 [+]),而没有指定词法分析和解析的其它方面 (如 [+]、[-] 和 [*] 的相对优先级,用括号来明确子表达式的分组等)。 在实现编译器时,需要一些附加的信息(以及人类的智慧) 才能将此描述转换成形式化的定义。 Coq 版本则始终忽略了所有这些信息,只专注于抽象语法。 - - 另一方面 BNF 版本则更加清晰易读。它的非形式化使其更加灵活, + - 反之,BNF 版本则更加清晰易读。它的非形式化使其更加灵活, 在讨论和在黑板上书写时,它有很大的优势, 此时传达一般的概念要比精确定下所有细节更加重要。 确实,存在很多种类似 BNF 的记法,人们可以随意使用它们, - 而无需关心具体使用了哪种 BNF 的形式,因为没有必要: + 而无需关心具体使用了哪种 BNF,因为没有必要: 大致的理解是非常重要的。 适应这两种记法都很有必要:非形式化的用语人类之间的交流, @@ -110,9 +111,9 @@ Inductive bexp : Type := Fixpoint aeval (a : aexp) : nat := match a with | ANum n => n - | APlus a1 a2 => (aeval a1) + (aeval a2) - | AMinus a1 a2 => (aeval a1) - (aeval a2) - | AMult a1 a2 => (aeval a1) * (aeval a2) + | APlus a1 a2 => (aeval a1) + (aeval a2) + | AMinus a1 a2 => (aeval a1) - (aeval a2) + | AMult a1 a2 => (aeval a1) * (aeval a2) end. Example test_aeval1: @@ -136,20 +137,15 @@ Fixpoint beval (b : bexp) : bool := (** 我们尚未定义太多东西,不过从这些定义出发,已经能前进不少了。 假设我们定义了一个接收算术表达式并对它稍微进行化简的函数,即将所有的 - [0+e](如 [(APlus (ANum 0) e])化简为 [e]。 *) + [0 + e](如 [(APlus (ANum 0) e])化简为 [e]。 *) Fixpoint optimize_0plus (a:aexp) : aexp := match a with - | ANum n => - ANum n - | APlus (ANum 0) e2 => - optimize_0plus e2 - | APlus e1 e2 => - APlus (optimize_0plus e1) (optimize_0plus e2) - | AMinus e1 e2 => - AMinus (optimize_0plus e1) (optimize_0plus e2) - | AMult e1 e2 => - AMult (optimize_0plus e1) (optimize_0plus e2) + | ANum n => ANum n + | APlus (ANum 0) e2 => optimize_0plus e2 + | APlus e1 e2 => APlus (optimize_0plus e1) (optimize_0plus e2) + | AMinus e1 e2 => AMinus (optimize_0plus e1) (optimize_0plus e2) + | AMult e1 e2 => AMult (optimize_0plus e1) (optimize_0plus e2) end. (** 要保证我们的优化是正确的,可以在某些示例中测试它并观察其输出出否正确。 *) @@ -209,16 +205,16 @@ Proof. (** *** [try] 泛策略 *) (** 如果 [T] 是一个策略,那么 [try T] 是一个和 [T] 一样的策略,只是如果 - [T] 失败的话,[try T] 就会_'成功地'_什么也不做(而非失败)。 *) + [T] 失败的话,[try T] 就会_'成功地'_什么也不做(而非失败)。*) Theorem silly1 : forall ae, aeval ae = aeval ae. -Proof. try reflexivity. (* 它和 [reflexivity] 做的一样 *) Qed. +Proof. try reflexivity. (* 它和 [reflexivity] 做的一样。 *) Qed. Theorem silly2 : forall (P : Prop), P -> P. Proof. intros P HP. - try reflexivity. (* 和 [reflexivity] 失败时一样 *) - apply HP. (* 我们仍然可以换种方式来结束此证明 *) + try reflexivity. (* 和 [reflexivity] 失败时一样。 *) + apply HP. (* 我们仍然可以换种方式来结束此证明。 *) Qed. (** 我们并没有真正的理由在像这样的手动证明中使用 [try],不过在连同 @@ -235,7 +231,7 @@ Qed. Lemma foo : forall n, 0 <=? n = true. Proof. intros. - destruct n eqn:E. + destruct n. (* 会产生两个执行过程相同的子目标... *) - (* n=0 *) simpl. reflexivity. - (* n=Sn' *) simpl. reflexivity. @@ -370,11 +366,12 @@ Qed. 那么重复 [T] 会永远循环(例如 [repeat simpl] 会一直循环,因为 [simpl] 总是会成功)。虽然 Coq 的主语言 Gallina 中的求值保证会终止, 然而策略却不会!然而这并不会影响 Coq 的逻辑一致性,因为 [repeat] - 和其它策略的工作就是指导 Coq 去构造证明;如果构造过程发散(即不终止), + 和其它策略的工作就是指导 Coq 去构造证明;如果构造过程发散(即不停机), 那就意味着我们构造证明失败,而非构造出了错误的证明。 *) -(** **** 练习:3 星 (optimize_0plus_b_sound) *) -(** 由于 [optimize_0plus] 变换不会改变 [aexp] 的值, +(** **** 练习:3 星, standard (optimize_0plus_b_sound) + + 由于 [optimize_0plus] 变换不会改变 [aexp] 的值, 因此我们可以将它应用到所有出现在 [bexp] 中的 [aexp] 上而不改变 [bexp] 的值。请编写一个对 [bexp] 执行此变换的函数,并证明它的可靠性。 利用我们刚学过的泛策略来构造一个尽可能优雅的证明。 *) @@ -388,13 +385,15 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, optional (optimizer) *) -(** _'设计练习'_:[optimize_0plus] 函数只是众多算术和布尔表达式优化的方法之一。 +(** **** 练习:4 星, standard, optional (optimize) + + _'设计练习'_:[optimize_0plus] 函数只是众多算术和布尔表达式优化的方法之一。 请编写一个更加聪明的优化器并证明它的正确性。(最容易的方法就是从小处着手: 一开始只添加单个简单的优化并证明它的正确性,然后逐渐增加其它更有趣的优化。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) (* ================================================================= *) (** ** 定义新的策略记法 *) @@ -449,7 +448,7 @@ Proof. intros. omega. Qed. -(** (注意本文件顶部 [Require Import Coq.omega.Omega.]。)*) +(** (注意本文件顶部 [From Coq Require Import omega.Omega.]。)*) (* ================================================================= *) (** ** 更多方便的策略 *) @@ -458,10 +457,10 @@ Qed. - [clear H]:从上下文中删除前提 [H]。 - - [subst x]:在上下文中查找假设 [x = e] 或 [e = x], + - [subst x]:对于变量 [x],在上下文中查找假设 [x = e] 或 [e = x], 将整个上下文和当前目标中的所有 [x] 替换为 [e] 并清除该假设。 - - [subst]:替换掉_'所有'_形如 [x = e] 或 [e = x] 的假设。 + - [subst]:替换掉_'所有'_形如 [x = e] 或 [e = x] 的假设(其中 [x] 为变量)。 - [rename... into...]:更改证明上下文中前提的名字。例如, 如果上下文中包含名为 [x] 的变量,那么 [rename x into y] @@ -477,7 +476,7 @@ Qed. 定义中查找可用于解决当前目标的构造子 [c]。如果找到了,那么其行为与 [apply c] 相同。 - 我们之后会看到它们的例子。 *) + 我们之后会看到所有它们的例子。 *) (* ################################################################# *) (** * 求值作为关系 *) @@ -505,6 +504,35 @@ Inductive aevalR : aexp -> nat -> Prop := aevalR e2 n2 -> aevalR (AMult e1 e2) (n1 * n2). +Module TooHardToRead. + +(* A small notational aside. We would previously have written the + definition of [aevalR] like this, with explicit names for the + hypotheses in each case: *) + +Inductive aevalR : aexp -> nat -> Prop := + | E_ANum n : + aevalR (ANum n) n + | E_APlus (e1 e2: aexp) (n1 n2: nat) + (H1 : aevalR e1 n1) + (H2 : aevalR e2 n2) : + aevalR (APlus e1 e2) (n1 + n2) + | E_AMinus (e1 e2: aexp) (n1 n2: nat) + (H1 : aevalR e1 n1) + (H2 : aevalR e2 n2) : + aevalR (AMinus e1 e2) (n1 - n2) + | E_AMult (e1 e2: aexp) (n1 n2: nat) + (H1 : aevalR e1 n1) + (H2 : aevalR e2 n2) : + aevalR (AMult e1 e2) (n1 * n2). + +(** Instead, we've chosen to leave the hypotheses anonymous, just + giving their types. This style gives us less control over the + names that Coq chooses during proofs involving [aevalR], but it + makes the definition itself quite a bit lighter. *) + +End TooHardToRead. + (** 如果 [aevalR] 有中缀记法的话会很方便。我们用 [e \\ n] 表示算术表达式 [e] 求值为 [n]。 *) @@ -521,16 +549,16 @@ End aevalR_first_try. 具体做法是,我们先“保留”该记法,然后在给出定义的同时声明它的意义。*) -Reserved Notation "e '\\' n" (at level 50, left associativity). +Reserved Notation "e '\\' n" (at level 90, left associativity). Inductive aevalR : aexp -> nat -> Prop := - | E_ANum n : + | E_ANum (n : nat) : (ANum n) \\ n - | E_APlus e1 e2 n1 n2 : + | E_APlus (e1 e2 : aexp) (n1 n2 : nat) : (e1 \\ n1) -> (e2 \\ n2) -> (APlus e1 e2) \\ (n1 + n2) - | E_AMinus e1 e2 n1 n2 : + | E_AMinus (e1 e2 : aexp) (n1 n2 : nat) : (e1 \\ n1) -> (e2 \\ n2) -> (AMinus e1 e2) \\ (n1 - n2) - | E_AMult e1 e2 n1 n2 : + | E_AMult (e1 e2 : aexp) (n1 n2 : nat) : (e1 \\ n1) -> (e2 \\ n2) -> (AMult e1 e2) \\ (n1 * n2) where "e '\\' n" := (aevalR e n) : type_scope. @@ -554,7 +582,7 @@ Inductive aevalR : aexp -> nat -> Prop := e1 \\ n1 e2 \\ n2 - -------------------- (E_APlus) + -------------------- (E_APlus) APlus e1 e2 \\ n1+n2 *) @@ -588,6 +616,27 @@ Inductive aevalR : aexp -> nat -> Prop := AMult e1 e2 \\ n1*n2 *) +(** **** 练习:1 星, standard, optional (beval_rules) + + 下面是 Coq 中 [beval] 函数的定义: + + Fixpoint beval (e : bexp) : bool := + match e with + | BTrue => true + | BFalse => false + | BEq a1 a2 => (aeval a1) =? (aeval a2) + | BLe a1 a2 => (aeval a1) <=? (aeval a2) + | BNot b1 => negb (beval b1) + | BAnd b1 b2 => andb (beval b1) (beval b2) + end. + + 请用推理规则记法将布尔求值的定义写成关系的形式。 *) +(* 请在此处解答 *) + +(* 请勿修改下面这一行: *) +Definition manual_grade_for_beval_rules : option (nat*string) := None. +(** [] *) + (* ================================================================= *) (** ** 定义的等价关系 *) @@ -643,8 +692,9 @@ Proof. try apply IHa1; try apply IHa2; reflexivity. Qed. -(** **** 练习:3 星 (bevalR) *) -(** 用和 [aevalR] 同样的方式写出关系 [bevalR],并证明它等价于 [beval]。 *) +(** **** 练习:3 星, standard (bevalR) + + 用和 [aevalR] 同样的方式写出关系 [bevalR],并证明它等价于 [beval]。 *) Inductive bevalR: bexp -> bool -> Prop := (* 请在此处解答 *) @@ -668,31 +718,31 @@ End AExp. Module aevalR_division. -(** 例如,假设我们想要用除法运算来扩展算术运算: *) +(** 例如,假设我们想要用除法来扩展算术运算: *) Inductive aexp : Type := | ANum (n : nat) | APlus (a1 a2 : aexp) | AMinus (a1 a2 : aexp) | AMult (a1 a2 : aexp) - | ADiv (a1 a2 : aexp). (* <--- 新增 *) + | ADiv (a1 a2 : aexp). (* <--- 新增 *) (** 扩展 [aeval] 的定义来处理此讯算并不是很直观(我们要返回什么作为 [ADiv (ANum 5) (ANum 0)] 的结果?)。然而扩展 [aevalR] 却很直观。*) Reserved Notation "e '\\' n" - (at level 50, left associativity). + (at level 90, left associativity). Inductive aevalR : aexp -> nat -> Prop := - | E_ANum : forall (n:nat), + | E_ANum (n : nat) : (ANum n) \\ n - | E_APlus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_APlus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (APlus a1 a2) \\ (n1 + n2) - | E_AMinus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMinus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMinus a1 a2) \\ (n1 - n2) - | E_AMult : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMult (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMult a1 a2) \\ (n1 * n2) - | E_ADiv : forall (a1 a2: aexp) (n1 n2 n3: nat), + | E_ADiv (a1 a2 : aexp) (n1 n2 n3 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (n2 > 0) -> (mult n2 n3 = n1) -> (ADiv a1 a2) \\ n3 @@ -702,15 +752,15 @@ End aevalR_division. Module aevalR_extended. -(** 假设,我们转而想要用非确定性的数值生成器 [any] 来扩展算术运算, +(** 假设我们想要用非确定性的数值生成器 [any] 来扩展算术运算, 该生成器会在求值时产生任何数。(注意,这不同于在所有可能的数值中作出 - _'概率上的'_选择 -- 我们没有为结果指定任何具体的分布,只是说了 + _'概率上的'_选择 -- 我们没有为结果指定任何具体的概率分布,只是说了 _'可能的结果'_。) *) -Reserved Notation "e '\\' n" (at level 50, left associativity). +Reserved Notation "e '\\' n" (at level 90, left associativity). Inductive aexp : Type := - | AAny (* <--- NEW *) + | AAny (* <--- NEW *) | ANum (n : nat) | APlus (a1 a2 : aexp) | AMinus (a1 a2 : aexp) @@ -720,15 +770,15 @@ Inductive aexp : Type := 而扩展 [aevalR] 则无此问题... *) Inductive aevalR : aexp -> nat -> Prop := - | E_Any : forall (n:nat), - AAny \\ n (* <--- new *) - | E_ANum : forall (n:nat), + | E_Any (n : nat) : + AAny \\ n (* <--- NEW *) + | E_ANum (n : nat) : (ANum n) \\ n - | E_APlus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_APlus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (APlus a1 a2) \\ (n1 + n2) - | E_AMinus : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMinus (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMinus a1 a2) \\ (n1 - n2) - | E_AMult : forall (a1 a2: aexp) (n1 n2 : nat), + | E_AMult (a1 a2 : aexp) (n1 n2 : nat) : (a1 \\ n1) -> (a2 \\ n2) -> (AMult a1 a2) \\ (n1 * n2) where "a '\\' n" := (aevalR a n) : type_scope. @@ -736,7 +786,7 @@ where "a '\\' n" := (aevalR a n) : type_scope. End aevalR_extended. (** 这时你可能会问:默认情况下应该使用哪种风格? - 上面的例子表明关系式定义从根本上要比函数式的更加强大。 + 我们刚看到的例子表明关系式的定义反而比函数式的更加有用。 对于这种定义的东西不太容易用函数表达,或者确实_'不是'_函数的情况来说, 明显别无选择。但如果两种风格均可行呢? @@ -749,7 +799,7 @@ End aevalR_extended. 我们需要这些性质时必须显式地证明它们。 - 有了函数,我们还可以利用 Coq 的计算机制在证明过程中简化表达式。 - 此外,函数还可以直“提取为”OCaml 或 Haskell 的可执行代码。 *) + 此外,函数还可以直接从 Gallina“提取”出 OCaml 或 Haskell 的可执行代码。 *) (** 最终,选择视具体情况而定,或者只是品味问题。确实,在大型的 Coq 开发中,经常可以看到一个定义同时给出了函数式和关系式_'两种'_风格, @@ -784,7 +834,7 @@ Definition state := total_map nat. Inductive aexp : Type := | ANum (n : nat) - | AId (x : string) (* <----- 新增 *) + | AId (x : string) (* <--- 新增 *) | APlus (a1 a2 : aexp) | AMinus (a1 a2 : aexp) | AMult (a1 a2 : aexp). @@ -811,35 +861,53 @@ Inductive bexp : Type := | BAnd (b1 b2 : bexp). (* ================================================================= *) -(** ** 记法 *) -(** 要让 Imp 程序更易读写,我们引入了一些记法和隐式转换(Coercion)。 +(** ** 记法 + + 要让 Imp 程序更易读写,我们引入了一些记法和隐式转换(Coercion)。 - 在本章中你无需理解以下声明具体做了些什么。简言而之,Coq 中的 [Coercion] + 你无需理解以下声明具体做了些什么。简言而之,Coq 中的 [Coercion] 声明规定了一个函数(或构造子)可以被类型系统隐式地用于将一个输入类型的值 转换成输出类型的值。例如,[AId] 的转换声明在需要一个 [aexp] 时直接使用普通的字符串,该字符串会被隐式地用 [AId] 来包装。 *) (** 下列记法在具体的_'记法作用域'_中声明,以避免与其它符号相同的解释相冲突。 - 同样,你也暂时无需理解其中的细节。 *) + 同样,你暂时也无需理解其中的细节,但要意识到到我们为 [+]、[-]、[*]、[=]、[<=] + 等运算符定义了_'新的'_解释十分重要。 *) Coercion AId : string >-> aexp. Coercion ANum : nat >-> aexp. -Definition bool_to_bexp (b: bool) : bexp := + +Definition bool_to_bexp (b : bool) : bexp := if b then BTrue else BFalse. Coercion bool_to_bexp : bool >-> bexp. -Bind Scope aexp_scope with aexp. -Infix "+" := APlus : aexp_scope. -Infix "-" := AMinus : aexp_scope. -Infix "*" := AMult : aexp_scope. -Bind Scope bexp_scope with bexp. -Infix "<=" := BLe : bexp_scope. -Infix "=" := BEq : bexp_scope. -Infix "&&" := BAnd : bexp_scope. -Notation "'!' b" := (BNot b) (at level 60) : bexp_scope. +Bind Scope imp_scope with aexp. +Bind Scope imp_scope with bexp. +Delimit Scope imp_scope with imp. + +Notation "x + y" := (APlus x y) (at level 50, left associativity) : imp_scope. +Notation "x - y" := (AMinus x y) (at level 50, left associativity) : imp_scope. +Notation "x * y" := (AMult x y) (at level 40, left associativity) : imp_scope. +Notation "x <= y" := (BLe x y) (at level 70, no associativity) : imp_scope. +Notation "x = y" := (BEq x y) (at level 70, no associativity) : imp_scope. +Notation "x && y" := (BAnd x y) (at level 40, left associativity) : imp_scope. +Notation "'~' b" := (BNot b) (at level 75, right associativity) : imp_scope. (** 现在我们可以用 [3 + (X * 2)] 来代替 [APlus 3 (AMult X 2)] 了,同样可以用 - [true && !(X <= 4)] 来代替 [BAnd true (BNot (BLe X 4))] *) + [true && !(X <= 4)] 来代替 [BAnd true (BNot (BLe X 4))]。 *) + +Definition example_aexp := (3 + (X * 2))%imp : aexp. +Definition example_bexp := (true && ~(X <= 4))%imp : bexp. + +(** 强制转换有一点不便之处,即它会略微提高人类推导表达式类型的难度。 + 如果你感到有点困惑,请用 [Set Printing Coercions] 来查看具体发生了什么。 *) + +Set Printing Coercions. + +Print example_bexp. +(* ===> example_bexp = bool_to_bexp true && ~ (AId X <= ANum 4) *) + +Unset Printing Coercions. (* ================================================================= *) (** ** 求值 *) @@ -850,7 +918,7 @@ Notation "'!' b" := (BNot b) (at level 60) : bexp_scope. Fixpoint aeval (st : state) (a : aexp) : nat := match a with | ANum n => n - | AId x => st x (* <----- 新增 *) + | AId x => st x (* <--- 新增 *) | APlus a1 a2 => (aeval st a1) + (aeval st a2) | AMinus a1 a2 => (aeval st a1) - (aeval st a2) | AMult a1 a2 => (aeval st a1) * (aeval st a2) @@ -866,28 +934,21 @@ Fixpoint beval (st : state) (b : bexp) : bool := | BAnd b1 b2 => andb (beval st b1) (beval st b2) end. -(** 我们为具体状态的全映射声明具体的记法,即使用 [{ --> 0 }] 作为空状态。 *) - -Notation "{ a --> x }" := - (t_update { --> 0 } a x) (at level 0). -Notation "{ a --> x ; b --> y }" := - (t_update ({ a --> x }) b y) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z }" := - (t_update ({ a --> x ; b --> y }) c z) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z ; d --> t }" := - (t_update ({ a --> x ; b --> y ; c --> z }) d t) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }" := - (t_update ({ a --> x ; b --> y ; c --> z ; d --> t }) e u) (at level 0). -Notation "{ a --> x ; b --> y ; c --> z ; d --> t ; e --> u ; f --> v }" := - (t_update ({ a --> x ; b --> y ; c --> z ; d --> t ; e --> u }) f v) (at level 0). +(** 我们为具体状态的全映射声明具体的记法,即使用 [(_ !-> 0)] 作为空状态。 *) + +Definition empty_st := (_ !-> 0). + +(** 现在我们可以为“单例状态(singleton state)”添加新的记法了, + 即只有一个绑定到值的变量。 *) +Notation "a '!->' x" := (t_update empty_st a x) (at level 100). Example aexp1 : - aeval { X --> 5 } (3 + (X * 2)) + aeval (X !-> 5) (3 + (X * 2))%imp = 13. Proof. reflexivity. Qed. Example bexp1 : - beval { X --> 5 } (true && !(X <= 4)) + beval (X !-> 5) (true && ~(X <= 4))%imp = true. Proof. reflexivity. Qed. @@ -900,19 +961,18 @@ Proof. reflexivity. Qed. (* ================================================================= *) (** ** 语法 *) -(** 指令 [c] 可以用以下 BNF 文法非形式化地描述。(为了能够使用 Coq - 的记法机制来定义 Imp 语法,我们选择了这种略尴尬的具体语法。具体来说, - 我们使用了 [IFB] 来避免与表中库中的 [if] 记法相冲突。) +(** 指令 [c] 可以用以下 BNF 文法非形式化地描述。 - c ::= SKIP | x ::= a | c ;; c | IFB b THEN c ELSE c FI + c ::= SKIP | x ::= a | c ;; c | TEST b THEN c ELSE c FI | WHILE b DO c END -*) -(** + + (为了能够使用 Coq 的记法机制来定义 Imp 语法,我们选择了这种略尴尬的具体语法。 + 具体来说,我们使用了 [TEST] 来避免与表中库中的 [if] 记法相冲突。) 例如,下面是用 Imp 编写的阶乘: Z ::= X;; Y ::= 1;; - WHILE ! (Z = 0) DO + WHILE ~(Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 END @@ -930,30 +990,102 @@ Inductive com : Type := (** 至于表达式,我们可以用一些 [Notation] 声明来让 Imp 程序的读写更加方便。 *) -Bind Scope com_scope with com. +Bind Scope imp_scope with com. Notation "'SKIP'" := - CSkip : com_scope. + CSkip : imp_scope. Notation "x '::=' a" := - (CAss x a) (at level 60) : com_scope. + (CAss x a) (at level 60) : imp_scope. Notation "c1 ;; c2" := - (CSeq c1 c2) (at level 80, right associativity) : com_scope. + (CSeq c1 c2) (at level 80, right associativity) : imp_scope. Notation "'WHILE' b 'DO' c 'END'" := - (CWhile b c) (at level 80, right associativity) : com_scope. -Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" := - (CIf c1 c2 c3) (at level 80, right associativity) : com_scope. - -(** 以下声明可以让这些记法在模式匹配中使用。 *) -Open Scope com_scope. + (CWhile b c) (at level 80, right associativity) : imp_scope. +Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" := + (CIf c1 c2 c3) (at level 80, right associativity) : imp_scope. (** 例如,下面是个阶乘函数,写成 Coq 的形式化定义: *) Definition fact_in_coq : com := - Z ::= X;; + (Z ::= X;; Y ::= 1;; - WHILE ! (Z = 0) DO + WHILE ~(Z = 0) DO Y ::= Y * Z;; Z ::= Z - 1 - END. + END)%imp. + +(* ================================================================= *) +(** ** 脱糖记法 *) + +(** Coq 为管理日益复杂的工作对象提供了丰富的特性,例如隐式转换和记法。 + 然而,过度使用它们会产生繁杂的语法。为了教学,我们通常会用以下命令来 + “关闭”这些特性以获得对事物更加本质的描述: + + - [Unset Printing Notations](用 [Set Printing Notations] 撤销) + - [Set Printing Coercions](用 [Unset Printing Coercions] 撤销) + - [Set Printing All](用 [Unset Printing All] 撤销) + + 这些命令也可在证明过程中详述当前目标和上下文。 *) + +Unset Printing Notations. +Print fact_in_coq. +(* ===> + fact_in_coq = + CSeq (CAss Z X) + (CSeq (CAss Y (S O)) + (CWhile (BNot (BEq Z O)) + (CSeq (CAss Y (AMult Y Z)) + (CAss Z (AMinus Z (S O)))))) + : com *) +Set Printing Notations. + +Set Printing Coercions. +Print fact_in_coq. +(* ===> + fact_in_coq = + (Z ::= AId X;; + Y ::= ANum 1;; + WHILE ~ (AId Z = ANum 0) DO + Y ::= AId Y * AId Z;; + Z ::= AId Z - ANum 1 + END)%imp + : com *) +Unset Printing Coercions. + +(* ================================================================= *) +(** ** [Locate] 命令 *) + +(* ----------------------------------------------------------------- *) +(** *** 查询记法 *) + +(** 当遇到未知记法时,可使用 [Locate] 后跟一个包含其符号的_'字符串'_ + 来查看其可能的解释。 *) +Locate "&&". +(* ===> + Notation "x && y" := andb x y : bool_scope (default interpretation) *) + +Locate ";;". +(* ===> + Notation "c1 ;; c2" := CSeq c1 c2 : imp_scope (default interpretation) *) + +Locate "WHILE". +(* ===> + Notation "'WHILE' b 'DO' c 'END'" := CWhile b c : imp_scope + (default interpretation) *) + +(* ----------------------------------------------------------------- *) +(** *** 查询标识符 *) + +(** 当以标示符使用 [Locate] 时,它会打印作用域中同名的所有值的完成路径。 + 它很适合解决由变量覆盖所引起的问题。 *) +Locate aexp. +(* ===> + Inductive Top.aexp + Inductive Top.AExp.aexp + (shorter name to refer to it in current context is AExp.aexp) + Inductive Top.aevalR_division.aexp + (shorter name to refer to it in current context is aevalR_division.aexp) + Inductive Top.aevalR_extended.aexp + (shorter name to refer to it in current context is aevalR_extended.aexp) +*) (* ================================================================= *) (** ** 更多示例 *) @@ -971,12 +1103,12 @@ Definition subtract_slowly_body : com := X ::= X - 1. (* ----------------------------------------------------------------- *) -(** *** Loops *) +(** *** 循环 *) Definition subtract_slowly : com := - WHILE ! (X = 0) DO + (WHILE ~(X = 0) DO subtract_slowly_body - END. + END)%imp. Definition subtract_3_from_5_slowly : com := X ::= 3 ;; @@ -984,7 +1116,7 @@ Definition subtract_3_from_5_slowly : com := subtract_slowly. (* ----------------------------------------------------------------- *) -(** *** An infinite loop: *) +(** *** 无限循环: *) Definition loop : com := WHILE true DO @@ -1002,23 +1134,26 @@ Definition loop : com := (** 下面是一次为指令定义求值函数的尝试,我们忽略了 [WHILE] 的情况。 *) +(** 为了在模式匹配中使用记法,我们需要以下声明。 *) +Open Scope imp_scope. Fixpoint ceval_fun_no_while (st : state) (c : com) : state := match c with | SKIP => st | x ::= a1 => - st & { x --> (aeval st a1) } + (x !-> (aeval st a1) ; st) | c1 ;; c2 => let st' := ceval_fun_no_while st c1 in ceval_fun_no_while st' c2 - | IFB b THEN c1 ELSE c2 FI => + | TEST b THEN c1 ELSE c2 FI => if (beval st b) then ceval_fun_no_while st c1 else ceval_fun_no_while st c2 | WHILE b DO c END => st (* 假装能用 *) end. +Close Scope imp_scope. (** 在 OCaml 或 Haskell 这类传统的函数式编程语言中,我们可以像下面这样添加 [WHILE] 的情况: @@ -1028,7 +1163,7 @@ Fixpoint ceval_fun_no_while (st : state) (c : com) ... | WHILE b DO c END => if (beval st b) - then ceval_fun st (c;; WHILE b DO c END) + then ceval_fun st (c ;; WHILE b DO c END) else st end. @@ -1059,7 +1194,7 @@ Fixpoint ceval_fun_no_while (st : state) (c : com) [any] 这样非确定性的特性,我们需要让求值的定义也是非确定性的 -- 即,它不仅会有不完全性,甚至还可以不是个函数! *) -(** 我们将使用记法 [c / st \\ st'] 来表示 [ceval] 这种关系:[c / st \\ st'] +(** 我们将使用记法 [st =[ c ]=> st'] 来表示 [ceval] 这种关系:[st =[ c ]=> st'] 表示在开始状态 [st] 下启动程序并在结束状态 [st'] 下产生结果。它可以读作: “[c] 将状态 [st] 变成 [st']”。 *) @@ -1068,111 +1203,116 @@ Fixpoint ceval_fun_no_while (st : state) (c : com) (** 下面是求值的非形式化定义,为了可读性表示成推理规则: - ---------------- (E_Skip) - SKIP / st \\ st + ----------------- (E_Skip) + st =[ SKIP ]=> st aeval st a1 = n - -------------------------------- (E_Ass) - x := a1 / st \\ st & { x --> n } + -------------------------------- (E_Ass) + st =[ x := a1 ]=> (x !-> n ; st) - c1 / st \\ st' - c2 / st' \\ st'' - ------------------- (E_Seq) - c1;;c2 / st \\ st'' + st =[ c1 ]=> st' + st' =[ c2 ]=> st'' + --------------------- (E_Seq) + st =[ c1;;c2 ]=> st'' beval st b1 = true - c1 / st \\ st' - ------------------------------------- (E_IfTrue) - IF b1 THEN c1 ELSE c2 FI / st \\ st' + st =[ c1 ]=> st' + --------------------------------------- (E_IfTrue) + st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st' beval st b1 = false - c2 / st \\ st' - ------------------------------------- (E_IfFalse) - IF b1 THEN c1 ELSE c2 FI / st \\ st' + st =[ c2 ]=> st' + --------------------------------------- (E_IfFalse) + st =[ TEST b1 THEN c1 ELSE c2 FI ]=> st' beval st b = false - ------------------------------ (E_WhileFalse) - WHILE b DO c END / st \\ st + ----------------------------- (E_WhileFalse) + st =[ WHILE b DO c END ]=> st beval st b = true - c / st \\ st' - WHILE b DO c END / st' \\ st'' - --------------------------------- (E_WhileTrue) - WHILE b DO c END / st \\ st'' + st =[ c ]=> st' + st' =[ WHILE b DO c END ]=> st'' + -------------------------------- (E_WhileTrue) + st =[ WHILE b DO c END ]=> st'' *) (** 下面是它的形式化定义。请确保你理解了它是如何与以上推理规则相对应的。 *) -Reserved Notation "c1 '/' st '\\' st'" - (at level 40, st at level 39). +Reserved Notation "st '=[' c ']=>' st'" + (at level 40). Inductive ceval : com -> state -> state -> Prop := | E_Skip : forall st, - SKIP / st \\ st + st =[ SKIP ]=> st | E_Ass : forall st a1 n x, aeval st a1 = n -> - (x ::= a1) / st \\ st & { x --> n } + st =[ x ::= a1 ]=> (x !-> n ; st) | E_Seq : forall c1 c2 st st' st'', - c1 / st \\ st' -> - c2 / st' \\ st'' -> - (c1 ;; c2) / st \\ st'' + st =[ c1 ]=> st' -> + st' =[ c2 ]=> st'' -> + st =[ c1 ;; c2 ]=> st'' | E_IfTrue : forall st st' b c1 c2, beval st b = true -> - c1 / st \\ st' -> - (IFB b THEN c1 ELSE c2 FI) / st \\ st' + st =[ c1 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' | E_IfFalse : forall st st' b c1 c2, beval st b = false -> - c2 / st \\ st' -> - (IFB b THEN c1 ELSE c2 FI) / st \\ st' + st =[ c2 ]=> st' -> + st =[ TEST b THEN c1 ELSE c2 FI ]=> st' | E_WhileFalse : forall b st c, beval st b = false -> - (WHILE b DO c END) / st \\ st + st =[ WHILE b DO c END ]=> st | E_WhileTrue : forall st st' st'' b c, beval st b = true -> - c / st \\ st' -> - (WHILE b DO c END) / st' \\ st'' -> - (WHILE b DO c END) / st \\ st'' + st =[ c ]=> st' -> + st' =[ WHILE b DO c END ]=> st'' -> + st =[ WHILE b DO c END ]=> st'' - where "c1 '/' st '\\' st'" := (ceval c1 st st'). + where "st =[ c ]=> st'" := (ceval c st st'). (** 将求值定义成关系而非函数的代价是,我们需要自己为某个程序求值成某种结束状态_'构造证明'_, 而不能只是交给 Coq 的计算机制去做了。 *) Example ceval_example1: - (X ::= 2;; - IFB X <= 1 + empty_st =[ + X ::= 2;; + TEST X <= 1 THEN Y ::= 3 ELSE Z ::= 4 - FI) - / { --> 0 } \\ { X --> 2 ; Z --> 4 }. + FI + ]=> (Z !-> 4 ; X !-> 2). Proof. (* 我们必须提供中间状态 *) - apply E_Seq with { X --> 2 }. + apply E_Seq with (X !-> 2). - (* 赋值指令 *) apply E_Ass. reflexivity. - (* if 指令 *) apply E_IfFalse. - reflexivity. - apply E_Ass. reflexivity. Qed. + reflexivity. + apply E_Ass. reflexivity. +Qed. -(** **** 练习:2 星 (ceval_example2) *) +(** **** 练习:2 星, standard (ceval_example2) *) Example ceval_example2: - (X ::= 0;; Y ::= 1;; Z ::= 2) / { --> 0 } \\ - { X --> 0 ; Y --> 1 ; Z --> 2 }. + empty_st =[ + X ::= 0;; Y ::= 1;; Z ::= 2 + ]=> (Z !-> 2 ; Y !-> 1 ; X !-> 0). Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (pup_to_n) *) -(** 写一个 Imp 程序对从 [1] 到 [X] 进行求值(包括:将 [1 + 2 + ... + X]) 赋予变量 [Y]。 +(** **** 练习:3 星, standard, optional (pup_to_n) + + 写一个 Imp 程序对从 [1] 到 [X] 进行求值(包括:将 [1 + 2 + ... + X]) 赋予变量 [Y]。 证明此程序对于 [X] = [2] 会按预期执行(这可能比你预想的还要棘手)。 *) Definition pup_to_n : com (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Theorem pup_to_2_ceval : - pup_to_n / { X --> 2 } - \\ { X --> 2 ; Y --> 0 ; Y --> 2 ; X --> 1 ; Y --> 3 ; X --> 0 }. + (X !-> 2) =[ + pup_to_n + ]=> (X !-> 0 ; Y !-> 3 ; X !-> 1 ; Y !-> 2 ; Y !-> 0 ; X !-> 2). Proof. (* 请在此处解答 *) Admitted. (** [] *) @@ -1189,8 +1329,8 @@ Proof. 实际上这不可能发生,因为 [ceval] _'确实'_是一个偏函数: *) Theorem ceval_deterministic: forall c st st1 st2, - c / st \\ st1 -> - c / st \\ st2 -> + st =[ c ]=> st1 -> + st =[ c ]=> st2 -> st1 = st2. Proof. intros c st st1 st2 E1 E2. @@ -1232,8 +1372,8 @@ Proof. Theorem plus2_spec : forall st n st', st X = n -> - plus2 / st \\ st' -> - st' X = (n + 2). + st =[ plus2 ]=> st' -> + st' X = n + 2. Proof. intros st n st' HX Heval. @@ -1244,8 +1384,9 @@ Proof. inversion Heval. subst. clear Heval. simpl. apply t_update_eq. Qed. -(** **** 练习:3 星, recommended (XtimesYinZ_spec) *) -(** 叙述并证明 [XtimesYinZ] 的规范(Specification)。 *) +(** **** 练习:3 星, standard, recommended (XtimesYinZ_spec) + + 叙述并证明 [XtimesYinZ] 的规范(Specification)。 *) (* 请在此处解答 *) @@ -1253,12 +1394,12 @@ Proof. Definition manual_grade_for_XtimesYinZ_spec : option (nat*string) := None. (** [] *) -(** **** 练习:3 星, recommended (loop_never_stops) *) +(** **** 练习:3 星, standard, recommended (loop_never_stops) *) Theorem loop_never_stops : forall st st', - ~(loop / st \\ st'). + ~(st =[ loop ]=> st'). Proof. intros st st' contra. unfold loop in contra. - remember (WHILE true DO SKIP END) as loopdef + remember (WHILE true DO SKIP END)%imp as loopdef eqn:Heqloopdef. (** 归纳讨论假设“[loopdef] 会终止”之构造,其中多数情形的矛盾显而易见, @@ -1267,9 +1408,11 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星 (no_whiles_eqv) *) -(** 考虑以下函数: *) +(** **** 练习:3 星, standard (no_whiles_eqv) + + 考虑以下函数: *) +Open Scope imp_scope. Fixpoint no_whiles (c : com) : bool := match c with | SKIP => @@ -1278,11 +1421,12 @@ Fixpoint no_whiles (c : com) : bool := true | c1 ;; c2 => andb (no_whiles c1) (no_whiles c2) - | IFB _ THEN ct ELSE cf FI => + | TEST _ THEN ct ELSE cf FI => andb (no_whiles ct) (no_whiles cf) | WHILE _ DO _ END => false end. +Close Scope imp_scope. (** 此断言只对没有 [WHILE] 循环的程序产生 [true]。请用 [Inductive] 写出一个性质 [no_whilesR] 使得 [no_whilesR c] 仅当 [c] 是个没有 @@ -1298,10 +1442,12 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星 (no_whiles_terminating) *) -(** 不涉及 [WHILE] 循环的 Imp 程序一定会终止。请陈述并证明定理 - [no_whiles_terminating] 来说明这一点。 *) -(** 按照你的偏好使用 [no_whiles] 或 [no_whilesR]。 *) +(** **** 练习:4 星, standard (no_whiles_terminating) + + 不涉及 [WHILE] 循环的 Imp 程序一定会终止。请陈述并证明定理 + [no_whiles_terminating] 来说明这一点。 + + 按照你的偏好使用 [no_whiles] 或 [no_whilesR]。 *) (* 请在此处解答 *) @@ -1312,8 +1458,9 @@ Definition manual_grade_for_no_whiles_terminating : option (nat*string) := None. (* ################################################################# *) (** * 附加练习 *) -(** **** 练习:3 星 (stack_compiler) *) -(** 旧式惠普计算器的编程语言类似于 Forth 和 Postscript,而其抽象机器类似于 +(** **** 练习:3 星, standard (stack_compiler) + + 旧式惠普计算器的编程语言类似于 Forth 和 Postscript,而其抽象机器类似于 Java 虚拟机,即所有对算术表达式的求值都使用_'栈'_来进行。例如,表达式 (2*3)+(3*(4-2)) @@ -1364,13 +1511,13 @@ Fixpoint s_execute (st : state) (stack : list nat) (* 将本行替换成 ":= _你的_定义_ ." *). Admitted. Example s_execute1 : - s_execute { --> 0 } [] + s_execute empty_st [] [SPush 5; SPush 3; SPush 1; SMinus] = [2; 5]. (* 请在此处解答 *) Admitted. Example s_execute2 : - s_execute { X --> 3 } [3;4] + s_execute (X !-> 3) [3;4] [SPush 4; SLoad X; SMult; SPlus] = [15; 4]. (* 请在此处解答 *) Admitted. @@ -1384,13 +1531,14 @@ Fixpoint s_compile (e : aexp) : list sinstr (** 在定义完 [s_compile] 之后,请证明以下示例来测试它是否起作用。 *) Example s_compile1 : - s_compile (X - (2 * Y)) + s_compile (X - (2 * Y))%imp = [SLoad X; SPush 2; SLoad Y; SMult; SMinus]. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:4 星, advanced (stack_compiler_correct) *) -(** 现在我们将证明在之前练习中实现的编译器的正确性。记住当栈中的元素少于两个时, +(** **** 练习:4 星, advanced (stack_compiler_correct) + + 现在我们将证明在之前练习中实现的编译器的正确性。记住当栈中的元素少于两个时, 规范并未指定 [SPlus]、[SMinus] 或 [SMult] 指令的行为。 (为了让正确性证明更加容易,你可能需要返回去修改你的实现!) @@ -1403,8 +1551,9 @@ Proof. (* 请在此处解答 *) Admitted. (** [] *) -(** **** 练习:3 星, optional (short_circuit) *) -(** 大部分现代编程语言对布尔 [and] 运算提供了“短路求值”的方法:要对 +(** **** 练习:3 星, standard, optional (short_circuit) + + 大部分现代编程语言对布尔 [and] 运算提供了“短路求值”的方法:要对 [BAnd b1 b2] 进行求值,首先对 [b1] 求值。如果结果为 [false],那么整个 [BAnd] 表达式的求值就是 [false],而无需对 [b2] 求值。否则,[b2] 的求值结果就决定了 [BAnd] 表达式的值。 @@ -1414,17 +1563,19 @@ Proof. 在更大的语言中该表达式可能会发散,此时短路求值的 [BAnd] _'并不'_ 等价于原始版本,因为它能让更多程序终止。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) Module BreakImp. -(** **** 练习:4 星, advanced (break_imp) *) -(** 像 C 和 Java 这样的指令式语言通常会包含 [break] 或类似地语句来中断循环的执行。 +(** **** 练习:4 星, advanced (break_imp) + + 像 C 和 Java 这样的指令式语言通常会包含 [break] 或类似地语句来中断循环的执行。 在本练习中,我们考虑如何为 Imp 加上 [break]。首先,我们需要丰富语言的指令。 *) Inductive com : Type := | CSkip - | CBreak (* <-- 新增 *) + | CBreak (* <--- 新增 *) | CAss (x : string) (a : aexp) | CSeq (c1 c2 : com) | CIf (b : bexp) (c1 c2 : com) @@ -1440,7 +1591,7 @@ Notation "c1 ;; c2" := (CSeq c1 c2) (at level 80, right associativity). Notation "'WHILE' b 'DO' c 'END'" := (CWhile b c) (at level 80, right associativity). -Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" := +Notation "'TEST' c1 'THEN' c2 'ELSE' c3 'FI'" := (CIf c1 c2 c3) (at level 80, right associativity). (** 接着,我们需要定义 [BREAK] 的行为。非形式化地说,只要 [BREAK] @@ -1453,8 +1604,8 @@ Notation "'IFB' c1 'THEN' c2 'ELSE' c3 'FI'" := X ::= 0;; Y ::= 1;; - WHILE 0 <> Y DO - WHILE TRUE DO + WHILE ~(0 = Y) DO + WHILE true DO BREAK END;; X ::= 1;; @@ -1470,15 +1621,15 @@ Inductive result : Type := | SContinue | SBreak. -Reserved Notation "c1 '/' st '\\' s '/' st'" - (at level 40, st, s at level 39). +Reserved Notation "st '=[' c ']=>' st' '/' s" + (at level 40, st' at next level). -(** 直觉上说,[c / st \\ s / st'] 表示如果 [c] 在 [st] 状况下开始, +(** 直觉上说,[st =[ c ]=> st' / s] 表示如果 [c] 在 [st] 状况下开始, 它会在 [st'] 状态下终止,围绕它的最内层循环(或整个程序) 要么收到立即退出的信号([s = SBreak]),要么继续正常执行([s = SContinue])。 - “[c / st \\ s / st']”关系的定义非常类似于之前我们为一般求值关系 - ([c / st \\ st'])给出的定义 -- 我们只需要恰当地处理终止信号。 + “[st =[ c ]=> st' / s]”关系的定义非常类似于之前我们为一般求值关系 + ([st =[ c ]=> st'])给出的定义 -- 我们只需要恰当地处理终止信号。 - 若指令为 [SKIP],则状态不变,任何围绕它的循环继续正常执行。 @@ -1486,7 +1637,7 @@ Reserved Notation "c1 '/' st '\\' s '/' st'" - 若指令为赋值,则根据状态更新该变量绑定的值,并发出继续正常执行的信号。 - - 若指令为 [IFB b THEN c1 ELSE c2 FI] 的形式,则按照 Imp 的原始语义更新状态, + - 若指令为 [TEST b THEN c1 ELSE c2 FI] 的形式,则按照 Imp 的原始语义更新状态, 除此之外我们还要从被选择执行的分支中传播信号。 - 若指令为一系列 [c1 ;; c2],我们首先执行 [c1]。如果它产生了 @@ -1504,46 +1655,46 @@ Reserved Notation "c1 '/' st '\\' s '/' st'" Inductive ceval : com -> state -> result -> state -> Prop := | E_Skip : forall st, - CSkip / st \\ SContinue / st + st =[ CSkip ]=> st / SContinue (* 请在此处解答 *) - where "c1 '/' st '\\' s '/' st'" := (ceval c1 st s st'). + where "st '=[' c ']=>' st' '/' s" := (ceval c st s st'). (** 现在证明你定义的 [ceval] 的如下性质: *) Theorem break_ignore : forall c st st' s, - (BREAK;; c) / st \\ s / st' -> + st =[ BREAK;; c ]=> st' / s -> st = st'. Proof. (* 请在此处解答 *) Admitted. Theorem while_continue : forall b c st st' s, - (WHILE b DO c END) / st \\ s / st' -> + st =[ WHILE b DO c END ]=> st' / s -> s = SContinue. Proof. (* 请在此处解答 *) Admitted. Theorem while_stops_on_break : forall b c st st', beval st b = true -> - c / st \\ SBreak / st' -> - (WHILE b DO c END) / st \\ SContinue / st'. + st =[ c ]=> st' / SBreak -> + st =[ WHILE b DO c END ]=> st' / SContinue. Proof. (* 请在此处解答 *) Admitted. (** [] *) (** **** 练习:3 星, advanced, optional (while_break_true) *) Theorem while_break_true : forall b c st st', - (WHILE b DO c END) / st \\ SContinue / st' -> + st =[ WHILE b DO c END ]=> st' / SContinue -> beval st' b = true -> - exists st'', c / st'' \\ SBreak / st'. + exists st'', st'' =[ c ]=> st' / SBreak. Proof. (* 请在此处解答 *) Admitted. (** [] *) (** **** 练习:4 星, advanced, optional (ceval_deterministic) *) Theorem ceval_deterministic: forall (c:com) st st1 st2 s1 s2, - c / st \\ s1 / st1 -> - c / st \\ s2 / st2 -> + st =[ c ]=> st1 / s1 -> + st =[ c ]=> st2 / s2 -> st1 = st2 /\ s1 = s2. Proof. (* 请在此处解答 *) Admitted. @@ -1551,8 +1702,9 @@ Proof. (** [] *) End BreakImp. -(** **** 练习:4 星, optional (add_for_loop) *) -(** 为该语言添加 C 风格的 [for] 循环指令,更新 [ceval] 的定义来定义 +(** **** 练习:4 星, standard, optional (add_for_loop) + + 为该语言添加 C 风格的 [for] 循环指令,更新 [ceval] 的定义来定义 [for] 循环,按需添加 [for] 循环的情况使得本文件中的所有证明都被 Coq 所接受。 @@ -1561,7 +1713,9 @@ End BreakImp. (c) 一个在循环的每次迭代最后执行的语句,以及 (d) 一个创建循环体的语句 (你不必关心为 [for] 构造一个具体的记法,不过如果你喜欢,可以随意去做。) *) -(* 请在此处解答 *) -(** [] *) +(* 请在此处解答 + + [] *) +(* Sat Jan 26 15:15:42 UTC 2019 *) diff --git a/plf-current/ImpTest.v b/plf-current/ImpTest.v index 02affaef..f9e7fba6 100644 --- a/plf-current/ImpTest.v +++ b/plf-current/ImpTest.v @@ -64,8 +64,8 @@ idtac " ". idtac "#> ceval_example2". idtac "Possible points: 2". check_type @ceval_example2 ( -((X ::= 0;; Y ::= 1;; Z ::= 2) / @Maps.t_empty nat 0 \\ - {X --> 0; Y --> 1; Z --> 2})). +(empty_st =[ X ::= 0;; Y ::= 1;; Z ::= 2 + ]=> @Maps.t_update nat (@Maps.t_update nat (X !-> 0) Y 1) Z 2)). idtac "Assumptions:". Abort. Print Assumptions ceval_example2. @@ -85,7 +85,7 @@ idtac " ". idtac "#> loop_never_stops". idtac "Possible points: 3". -check_type @loop_never_stops ((forall st st' : state, ~ loop / st \\ st')). +check_type @loop_never_stops ((forall st st' : state, ~ st =[ loop ]=> st')). idtac "Assumptions:". Abort. Print Assumptions loop_never_stops. @@ -118,7 +118,7 @@ idtac " ". idtac "#> s_execute1". idtac "Possible points: 0.5". check_type @s_execute1 ( -(s_execute (@Maps.t_empty nat 0) (@nil nat) +(s_execute empty_st (@nil nat) (SPush 5 :: (SPush 3 :: SPush 1 :: SMinus :: @nil sinstr)%list) = (2 :: 5 :: @nil nat)%list)). idtac "Assumptions:". @@ -130,7 +130,7 @@ idtac " ". idtac "#> s_execute2". idtac "Possible points: 0.5". check_type @s_execute2 ( -(s_execute {X --> 3} (3 :: (4 :: @nil nat)%list) +(s_execute (X !-> 3) (3 :: (4 :: @nil nat)%list) (SPush 4 :: (SLoad X :: SMult :: SPlus :: @nil sinstr)%list) = (15 :: 4 :: @nil nat)%list)). idtac "Assumptions:". @@ -245,3 +245,5 @@ Print Assumptions BreakImp.while_continue. idtac "---------- BreakImp.while_stops_on_break ---------". Print Assumptions BreakImp.while_stops_on_break. Abort. + +(* Sat Jan 26 15:15:50 UTC 2019 *) diff --git a/plf-current/LICENSE b/plf-current/LICENSE index 15ebac8e..568f5c1d 100644 --- a/plf-current/LICENSE +++ b/plf-current/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018 +Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/plf-current/LibTactics.html b/plf-current/LibTactics.html index 8f32fe35..01b3b4d0 100644 --- a/plf-current/LibTactics.html +++ b/plf-current/LibTactics.html @@ -157,7 +157,7 @@HoareAsLogic证明论霍尔逻辑
-Lemma H_Consequence_post : ∀ (P Q Q' : Assertion) c,
+Lemma H_Consequence_post : ∀(P Q Q' : Assertion) c,
hoare_proof P c Q' →
- (∀ st, Q' st → Q st) →
+ (∀st, Q' st → Q st) →
hoare_proof P c Q.
@@ -121,7 +121,7 @@HoareAsLogic证明论霍尔逻辑
- {{(X=3) [X |-> X + 2] [X |-> X + 1]}}+
+ {{(X=3) [X ⊢> X + 2] [X ⊢> X + 1]}}
X::=X+1 ;; X::=X+2
{{X=3}}.@@ -133,7 +133,7 @@HoareAsLogic证明论霍尔逻辑Example sample_proof :
hoare_proof
- ((fun st:state ⇒ st X = 3) [X |-> X + 2] [X |-> X + 1])
+ ((fun st:state ⇒ st X = 3) [X ⊢> X + 2] [X ⊢> X + 1])
(X ::= X + 1;; X ::= X + 2)
(fun st:state ⇒ st X = 3).
Proof.
@@ -144,13 +144,13 @@HoareAsLogic证明论霍尔逻辑 ====>
H_Seq
- (((fun st : state => st X = 3) X |-> X + 2) X |-> X + 1)
+ (((fun st : state => st X = 3) X ⊢> X + 2) X ⊢> X + 1)
(X ::= X + 1)
- ((fun st : state => st X = 3) X |-> X + 2)
+ ((fun st : state => st X = 3) X ⊢> X + 2)
(X ::= X + 2)
(fun st : state => st X = 3)
(H_Asgn
- ((fun st : state => st X = 3) X |-> X + 2)
+ ((fun st : state => st X = 3) X ⊢> X + 2)
X (X + 1))
(H_Asgn
(fun st : state => st X = 3)
@@ -159,16 +159,16 @@HoareAsLogic证明论霍尔逻辑
-Theorem hoare_proof_sound : ∀ P c Q,
+Theorem hoare_proof_sound : ∀P c Q,
hoare_proof P c Q → {{P}} c {{Q}}.
Proof.
(* 请在此处解答 *) Admitted.
@@ -191,7 +191,7 @@HoareAsLogic证明论霍尔逻辑 Theorem H_Post_True_deriv:
- ∀ c P, hoare_proof P c (fun _ ⇒ True).
+ ∀c P, hoare_proof P c (fun _ ⇒ True).
Proof.
intro c.
induction c; intro P.
@@ -211,7 +211,7 @@HoareAsLogic证明论霍尔逻辑apply (IHc1 (fun _ ⇒ True)).
apply IHc2.
intros. apply I.
- - (* IFB *)
+ - (* TEST *)
apply H_Consequence_pre with (fun _ ⇒ True).
apply H_If.
apply IHc1.
@@ -231,7 +231,7 @@HoareAsLogic证明论霍尔逻辑
-Lemma False_and_P_imp: ∀ P Q,
+Lemma False_and_P_imp: ∀P Q,
False ∧ P → Q.
Proof.
intros P Q [CONTRA HP].
@@ -241,14 +241,14 @@HoareAsLogic证明论霍尔逻辑eapply H_Consequence_pre;
[eapply CONSTR | intros ? CONTRA; destruct CONTRA].
Theorem H_Pre_False_deriv:
- ∀ c Q, hoare_proof (fun _ ⇒ False) c Q.
+ ∀c Q, hoare_proof (fun _ ⇒ False) c Q.
Proof.
intros c.
induction c; intro Q.
- (* SKIP *) pre_false_helper H_Skip.
- (* ::= *) pre_false_helper H_Asgn.
- (* ;; *) pre_false_helper H_Seq. apply IHc1. apply IHc2.
- - (* IFB *)
+ - (* TEST *)
apply H_If; eapply H_Consequence_pre.
apply IHc1. intro. eapply False_and_P_imp.
apply IHc2. intro. eapply False_and_P_imp.
@@ -286,17 +286,17 @@HoareAsLogic证明论霍尔逻辑 Definition wp (c:com) (Q:Assertion) : Assertion :=
- fun s ⇒ ∀ s', c / s \\ s' → Q s'.
+ fun s ⇒ ∀s', s =[ c ]⇒ s' → Q s'.
@@ -305,14 +305,14 @@
-Lemma wp_is_precondition: ∀ c Q,
+Lemma wp_is_precondition: ∀c Q,
{{wp c Q}} c {{Q}}.
(* 请在此处解答 *) Admitted.
HoareAsLogic证明论霍尔逻辑
-练习:1 星 (wp_is_weakest)
+练习:1 星, standard (wp_is_weakest)
@@ -321,7 +321,7 @@
-Lemma wp_is_weakest: ∀ c Q P',
- {{P'}} c {{Q}} → ∀ st, P' st → wp c Q st.
+Lemma wp_is_weakest: ∀c Q P',
+ {{P'}} c {{Q}} → ∀st, P' st → wp c Q st.
(* 请在此处解答 *) Admitted.
HoareAsLogic证明论霍尔逻辑
-Lemma bassn_eval_false : ∀ b st, ¬ bassn b st → beval st b = false.
+Lemma bassn_eval_false : ∀b st, ¬bassn b st → beval st b = false.
Proof.
intros b st H. unfold bassn in H. destruct (beval st b).
exfalso. apply H. reflexivity.
@@ -333,12 +333,12 @@HoareAsLogic证明论霍尔逻辑
-练习:5 星 (hoare_proof_complete)
+练习:5 星, standard (hoare_proof_complete)
完成如下定理的证明。-Theorem hoare_proof_complete: ∀ P c Q,- 类似地,三元组 {{True}} SKIP {{P}} 是合法的当且仅当 ∀s, P s 是合法的,其中 P + 类似地,三元组 {{True}} SKIP {{P}} 是合法的当且仅当 ∀ s, P s 是合法的,其中 P 是Coq逻辑的任意一个断言。但是我们已知对于这个逻辑并没有任何的决定性过程。
+Theorem hoare_proof_complete: ∀P c Q,
{{P}} c {{Q}} → hoare_proof P c Q.
Proof.
intros P c. generalize dependent P.
@@ -377,7 +377,7 @@HoareAsLogic证明论霍尔逻辑
@@ -387,6 +387,10 @@HoareAsLogic证明论霍尔逻辑Hoare2 一章中的关于形式化修饰程序的章节会向我们展 示如何做的更好。
+ +(* Sat Jan 26 15:15:43 UTC 2019 *)
+LibTacticsA Collection of Handy Gene
Inductive Boxer : Type :=
- | boxer : ∀ (A:Type), A → Boxer.
+ | boxer : ∀(A:Type), A → Boxer.
@@ -229,7 +229,7 @@LibTacticsA Collection of Handy Gene
Ltac gen_until_mark :=@@ -457,7 +457,7 @@
- match goal with H: ?T |- _ ⇒
+ match goal with H: ?T ⊢ _ ⇒
match T with
| ltac_Mark ⇒ clear H
| _ ⇒ generalize H; clear H; gen_until_mark
@@ -244,7 +244,7 @@LibTacticsA Collection of Handy Gene
Ltac gen_until_mark_with_processing cont :=@@ -416,7 +416,7 @@
- match goal with H: ?T |- _ ⇒
+ match goal with H: ?T ⊢ _ ⇒
match T with
| ltac_Mark ⇒ clear H
| _ ⇒ cont H; generalize H; clear H;
@@ -262,7 +262,7 @@LibTacticsA Collection of Handy Gene Ltac intro_until_mark :=
match goal with
- | |- (ltac_Mark → _) ⇒ intros _
+ | ⊢ (ltac_Mark → _) ⇒ intros _
| _ ⇒ intro; intro_until_mark
end.
LibTacticsA Collection of Handy Gene Definition ltac_database (D:Boxer) (T:Boxer) (A:Boxer) := Ltac_database_token.
Notation "'Register' D T" := (ltac_database (boxer D) (boxer T) _)
(at level 69, D at level 0, T at level 0).
-Lemma ltac_database_provide : ∀ (A:Boxer) (D:Boxer) (T:Boxer),
+Lemma ltac_database_provide : ∀(A:Boxer) (D:Boxer) (T:Boxer),
ltac_database D T A.
Proof using. split. Qed.
Ltac Provide T := apply (@ltac_database_provide (boxer T)).
@@ -429,7 +429,7 @@LibTacticsA Collection of Handy Gene generalize L end; clear H ].
(* Note for a possible alternative implementation of the ltac_database_token:
Inductive Ltac_database : Type :=
- | ltac_database : forall A, A -> Ltac_database.
+ | ltac_database : forall A, A -> Ltac_database.
Implicit Arguments ltac_database A.
*)
LibTacticsA Collection of Handy Gene Ltac rm_term E :=
let T := type of E in
- match goal with H: T |- _ ⇒ try clear H end.
+ match goal with H: T ⊢ _ ⇒ try clear H end.
@@ -608,7 +608,7 @@LibTacticsA Collection of Handy Gene
-Lemma dup_lemma : ∀ P, P → P → P.
+Lemma dup_lemma : ∀P, P → P → P.
Proof using. auto. Qed.
Ltac dup_tactic N :=
match number_to_nat N with
@@ -661,7 +661,7 @@LibTacticsA Collection of Handy Gene Ltac check_noevar_hyp H :=
let T := type of H in check_noevar T.
Ltac check_noevar_goal :=
- match goal with |- ?G ⇒ check_noevar G end.
+ match goal with ⊢ ?G ⇒ check_noevar G end.
@@ -693,7 +693,7 @@LibTacticsA Collection of Handy Gene
Ltac get_last_hyp tt :=
- match goal with H: _ |- _ ⇒ constr:(H) end.
+ match goal with H: _ ⊢ _ ⇒ constr:(H) end.
@@ -719,7 +719,7 @@LibTacticsA Collection of Handy Gene Definition ltac_to_generalize (A:Type) (x:A) := x.
Ltac gen_to_generalize :=
repeat match goal with
- H: ltac_to_generalize _ |- _ ⇒ generalize H; clear H end.
+ H: ltac_to_generalize _ ⊢ _ ⇒ generalize H; clear H end.
Ltac mark_to_generalize H :=
let T := type of H in
change T with (ltac_to_generalize T) in H.
@@ -789,7 +789,7 @@LibTacticsA Collection of Handy Gene Tactic Notation "ltac_action_at" constr(K) "of" constr(E) "do" tactic(Tac) :=
let p := fresh "TEMP" in ltac_pattern E at K;
- match goal with |- ?P _ ⇒ set (p:=P) end;
+ match goal with ⊢ ?P _ ⇒ set (p:=P) end;
Tac; unfold p; clear p.
Tactic Notation "ltac_action_at" constr(K) "of" constr(E) "in" hyp(H) "do" tactic(Tac) :=
let p := fresh "TEMP" in ltac_pattern E at K in H;
@@ -838,17 +838,17 @@LibTacticsA Collection of Handy Gene
Ltac jauto_set_hyps :=
- repeat match goal with H: ?T |- _ ⇒
+ repeat match goal with H: ?T ⊢ _ ⇒
match T with
| _ ∧ _ ⇒ destruct H
- | ∃ a, _ ⇒ destruct H
+ | ∃a, _ ⇒ destruct H
| _ ⇒ generalize H; clear H
end
end.
Ltac jauto_set_goal :=
repeat match goal with
- | |- ∃ a, _ ⇒ esplit
- | |- _ ∧ _ ⇒ split
+ | ⊢ ∃a, _ ⇒ esplit
+ | ⊢ _ ∧ _ ⇒ split
end.
Ltac jauto_set :=
intros; jauto_set_hyps;
@@ -1000,7 +1000,7 @@LibTacticsA Collection of Handy Gene asserts H: T is another syntax for assert (H : T), which also works with introduction patterns. For instance, one can write: - asserts \[x P\] (∃n, n = 3), or + asserts \[x P\] (∃ n, n = 3), or asserts \[H|H\] (n = 0 ∨ n = 1).
@@ -1101,7 +1101,7 @@LibTacticsA Collection of Handy Gene The instantiation tactics are used to instantiate a lemma E (whose type is a product) on some arguments. The type of E is made of implications and universal quantifications, e.g. - ∀x, P x → ∀y z, Q x y z → R z. + ∀ x, P x → ∀ y z, Q x y z → R z.
@@ -1156,7 +1156,7 @@LibTacticsA Collection of Handy Gene let rec go t :=
match type of t with
| ?P → ?Q ⇒ app_assert t P go
- | ∀ _:?A, _ ⇒ app_evar t A go
+ | ∀_:?A, _ ⇒ app_evar t A go
| _ ⇒ final t
end in
go t.
@@ -1188,14 +1188,14 @@LibTacticsA Collection of Handy Gene | ltac_wild ⇒
match T with
| ?P → ?Q ⇒ first [ app_assert t P cont' | fail 3 ]
- | ∀ _:?A, _ ⇒ first [ app_evar t A cont' | fail 3 ]
+ | ∀_:?A, _ ⇒ first [ app_evar t A cont' | fail 3 ]
end
| _ ⇒
match T with (* should test T for unifiability *)
| U → ?Q ⇒ first [ app_assert t U cont' | fail 3 ]
- | ∀ _:U, _ ⇒ first [ app_evar t U cont' | fail 3 ]
+ | ∀_:U, _ ⇒ first [ app_evar t U cont' | fail 3 ]
| ?P → ?Q ⇒ first [ app_assert t P cont | fail 3 ]
- | ∀ _:?A, _ ⇒ first [ app_evar t A cont | fail 3 ]
+ | ∀_:?A, _ ⇒ first [ app_evar t A cont | fail 3 ]
end
end
| fail 2 ]
@@ -1204,7 +1204,7 @@LibTacticsA Collection of Handy Gene | ?P → ?Q ⇒ first [ app_arg t P v cont'
| app_assert t P cont
| fail 3 ]
- | ∀ _:Type, _ ⇒
+ | ∀_:Type, _ ⇒
match type of v with
| Type ⇒ first [ cont' (t v)
| app_evar t Type cont
@@ -1212,7 +1212,7 @@LibTacticsA Collection of Handy Gene | _ ⇒ first [ app_evar t Type cont
| fail 3 ]
end
- | ∀ _:?A, _ ⇒
+ | ∀_:?A, _ ⇒
let V := type of v in
match type of V with
| Prop ⇒ first [ app_evar t A cont
@@ -1239,7 +1239,7 @@LibTacticsA Collection of Handy Gene let rec go t :=
match type of t with
| ?P → ?Q ⇒ app_assert t P go
- | ∀ _:?A, _ ⇒
+ | ∀_:?A, _ ⇒
first [ app_evar t A go
| app_typeclass t go
| fail 3 ]
@@ -1263,19 +1263,19 @@LibTacticsA Collection of Handy Gene | ltac_wild ⇒
match T with
| ?P → ?Q ⇒ first [ app_assert t P cont' | fail 3 ]
- | ∀ _:?A, _ ⇒ first [ app_typeclass t cont'
+ | ∀_:?A, _ ⇒ first [ app_typeclass t cont'
| app_evar t A cont'
| fail 3 ]
end
| _ ⇒
match T with (* should test T for unifiability *)
| U → ?Q ⇒ first [ app_assert t U cont' | fail 3 ]
- | ∀ _:U, _ ⇒ first
+ | ∀_:U, _ ⇒ first
[ app_typeclass t cont'
| app_evar t U cont'
| fail 3 ]
| ?P → ?Q ⇒ first [ app_assert t P cont | fail 3 ]
- | ∀ _:?A, _ ⇒ first
+ | ∀_:?A, _ ⇒ first
[ app_typeclass t cont
| app_evar t A cont
| fail 3 ]
@@ -1287,7 +1287,7 @@LibTacticsA Collection of Handy Gene | ?P → ?Q ⇒ first [ app_arg t P v cont'
| app_assert t P cont
| fail 3 ]
- | ∀ _:Type, _ ⇒
+ | ∀_:Type, _ ⇒
match type of v with
| Type ⇒ first [ cont' (t v)
| app_evar t Type cont
@@ -1295,7 +1295,7 @@LibTacticsA Collection of Handy Gene | _ ⇒ first [ app_evar t Type cont
| fail 3 ]
end
- | ∀ _:?A, _ ⇒
+ | ∀_:?A, _ ⇒
let V := type of v in
match type of V with
| Prop ⇒ first [ app_typeclass t cont
@@ -1329,20 +1329,20 @@LibTacticsA Collection of Handy Gene | ltac_wild ⇒ match T with | ?P → ?Q ⇒ first [ app_assert t P cont' | fail 3 ] - | ∀_:?A, _ ⇒ first [ app_evar t A cont' | fail 3 ] + | ∀ _:?A, _ ⇒ first [ app_evar t A cont' | fail 3 ] end | _ ⇒ match T with should test T for unifiability *)
| U → ?Q ⇒ first [ app_assert t U cont' | fail 3 ] - | ∀_:U, _ ⇒ first [ app_evar t U cont' | fail 3 ] + | ∀ _:U, _ ⇒ first [ app_evar t U cont' | fail 3 ] | ?P → ?Q ⇒ first [ app_assert t P cont | fail 3 ] - | ∀_:?A, _ ⇒ first [ app_evar t A cont | fail 3 ] + | ∀ _:?A, _ ⇒ first [ app_evar t A cont | fail 3 ] end end | fail 2
| _ =>
match T with
- | ?P -> ?Q => first app_arg t P v cont' + | ?P -> ?Q => first app_arg t P v cont' | app_assert t P cont | fail 3
| forall _:?A, _ => first cont' (t v) @@ -1662,7 +1662,7 @@LibTacticsA Collection of Handy Gene Ltac specializes_var_base H :=
match type of H with
| ?P → ?Q ⇒ fail 1
- | ∀ _:_, _ ⇒ specializes H __
+ | ∀_:_, _ ⇒ specializes H __
end.
Ltac specializes_vars_base H :=
repeat (specializes_var_base H).
@@ -1771,7 +1771,7 @@LibTacticsA Collection of Handy Gene subgoal ?a = y. The introduction of the evar ?a makes it possible to apply lemmas that would not apply to the original goal, for example a lemma of the form - ∀n m, P n n m, because x and y might be equal + ∀ n m, P n n m, because x and y might be equal but not convertible.
@@ -1785,36 +1785,36 @@LibTacticsA Collection of Handy Gene Section equatesLemma.
Variables (A0 A1 : Type).
-Variables (A2 : ∀ (x1 : A1), Type).
-Variables (A3 : ∀ (x1 : A1) (x2 : A2 x1), Type).
-Variables (A4 : ∀ (x1 : A1) (x2 : A2 x1) (x3 : A3 x2), Type).
-Variables (A5 : ∀ (x1 : A1) (x2 : A2 x1) (x3 : A3 x2) (x4 : A4 x3), Type).
-Variables (A6 : ∀ (x1 : A1) (x2 : A2 x1) (x3 : A3 x2) (x4 : A4 x3) (x5 : A5 x4), Type).
-Lemma equates_0 : ∀ (P Q:Prop),
+Variables (A2 : ∀(x1 : A1), Type).
+Variables (A3 : ∀(x1 : A1) (x2 : A2 x1), Type).
+Variables (A4 : ∀(x1 : A1) (x2 : A2 x1) (x3 : A3 x2), Type).
+Variables (A5 : ∀(x1 : A1) (x2 : A2 x1) (x3 : A3 x2) (x4 : A4 x3), Type).
+Variables (A6 : ∀(x1 : A1) (x2 : A2 x1) (x3 : A3 x2) (x4 : A4 x3) (x5 : A5 x4), Type).
+Lemma equates_0 : ∀(P Q:Prop),
P → P = Q → Q.
Proof. intros. subst. auto. Qed.
Lemma equates_1 :
- ∀ (P:A0→Prop) x1 y1,
+ ∀(P:A0→Prop) x1 y1,
P y1 → x1 = y1 → P x1.
Proof. intros. subst. auto. Qed.
Lemma equates_2 :
- ∀ y1 (P:A0→∀(x1:A1),Prop) x1 x2,
+ ∀y1 (P:A0→∀(x1:A1),Prop) x1 x2,
P y1 x2 → x1 = y1 → P x1 x2.
Proof. intros. subst. auto. Qed.
Lemma equates_3 :
- ∀ y1 (P:A0→∀(x1:A1)(x2:A2 x1),Prop) x1 x2 x3,
+ ∀y1 (P:A0→∀(x1:A1)(x2:A2 x1),Prop) x1 x2 x3,
P y1 x2 x3 → x1 = y1 → P x1 x2 x3.
Proof. intros. subst. auto. Qed.
Lemma equates_4 :
- ∀ y1 (P:A0→∀(x1:A1)(x2:A2 x1)(x3:A3 x2),Prop) x1 x2 x3 x4,
+ ∀y1 (P:A0→∀(x1:A1)(x2:A2 x1)(x3:A3 x2),Prop) x1 x2 x3 x4,
P y1 x2 x3 x4 → x1 = y1 → P x1 x2 x3 x4.
Proof. intros. subst. auto. Qed.
Lemma equates_5 :
- ∀ y1 (P:A0→∀(x1:A1)(x2:A2 x1)(x3:A3 x2)(x4:A4 x3),Prop) x1 x2 x3 x4 x5,
+ ∀y1 (P:A0→∀(x1:A1)(x2:A2 x1)(x3:A3 x2)(x4:A4 x3),Prop) x1 x2 x3 x4 x5,
P y1 x2 x3 x4 x5 → x1 = y1 → P x1 x2 x3 x4 x5.
Proof. intros. subst. auto. Qed.
Lemma equates_6 :
- ∀ y1 (P:A0→∀(x1:A1)(x2:A2 x1)(x3:A3 x2)(x4:A4 x3)(x5:A5 x4),Prop)
+ ∀y1 (P:A0→∀(x1:A1)(x2:A2 x1)(x3:A3 x2)(x4:A4 x3)(x5:A5 x4),Prop)
x1 x2 x3 x4 x5 x6,
P y1 x2 x3 x4 x5 x6 → x1 = y1 → P x1 x2 x3 x4 x5 x6.
Proof. intros. subst. auto. Qed.
@@ -1967,7 +1967,7 @@LibTacticsA Collection of Handy Gene
Ltac false_invert_iter :=
- match goal with H:_ |- _ ⇒
+ match goal with H:_ ⊢ _ ⇒
solve [ inversion H; false
| clear H; false_invert_iter
| fail 2 ] end.
@@ -1996,7 +1996,7 @@LibTacticsA Collection of Handy Gene