函数程序设计语言 functional programing by coqlde

basic inctive logic relation list inp会有

一、basic

1.1 数据与函数

枚举类型

Inductive 定义一个数据集合

Inductive day : Type :=
  | monday
  | tuesday
  | wednesday
  | thursday
  | friday
  | saturday
  | sunday.

Definition 可以写一些操作函数

Definition next_weekday (d:day) : day :=
  match d with
  | monday ⇒ tuesday
  | tuesday ⇒ wednesday
  | wednesday ⇒ thursday
  | thursday ⇒ friday
  | friday ⇒ monday
  | saturday ⇒ monday
  | sunday ⇒ monday
  end.

在 Coq 中检验的方式一共有三种:

第一,用 Compute 指令来计算包含 next_weekday 的复合表达式

Compute (next_weekday friday).
Compute (next_weekday (next_weekday saturday)).

第二,将期望的结果写成 Coq 的示例

Example test_next_weekday:
  (next_weekday (next_weekday saturday)) = tuesday.

Proof. simpl. reflexivity.  Qed.

这段代码基本上可以读作“若等式两边的求值结果相同,该断言即可得证”

第三,我们可以让 Coq 从 Definition 中提取出用其它更加常规的编程语言编写的程序

布尔值

Inductive bool : Type :=
  | true
  | false.

布尔值的函数可按照同样的方式来定义

Definition negb (b:bool) : bool :=
  match b with
  | true ⇒ false
  | false ⇒ true
  end.
Definition andb (b1:bool) (b2:bool) : bool :=
  match b1 with
  | true ⇒ b2
  | false ⇒ false
  end.
Definition orb (b1:bool) (b2:bool) : bool :=
  match b1 with
  | true ⇒ true
  | false ⇒ b2
  end.

以下四个单元测试演示了多参数应用的语法

Example test_orb1: (orb true false) = true.
Proof. simpl. reflexivity. Qed.
Example test_orb2: (orb false false) = false.
Proof. simpl. reflexivity. Qed.
Example test_orb3: (orb false true) = true.
Proof. simpl. reflexivity. Qed.
Example test_orb4: (orb true true) = true.
Proof. simpl. reflexivity. Qed

Notation 能为既有的定义赋予新的中缀记法

Notation "x && y" := (andb x y).
Notation "x || y" := (orb x y).
Example test_orb5: false || false || true = true.
Proof. simpl. reflexivity. Qed.

类型

Check 指令会让 Coq 显示一个表达式的类型

Check true.
(* ===> true : bool *)

像 negb 这样的函数本身也有类型,被称为函数类型,用带箭头的类型表示

Check negb
    : bool → bool.
Check andb
    : bool → bool → bool.

由旧类型构造新类型

我们之前定义的枚举类型,每个元素都只是无参数构造子

下面的类型定义,会让其中一个构造子接受一个参数

Inductive rgb : Type :=
  | red
  | green
  | blue.
Inductive color : Type :=
  | black
  | white
  | primary (p : rgb).

最后一行表示若 p 是属于 rgb 的构造子表达式,则 primary p(构造子 primary 应用于参数 p)是属于集合 color 的构造子表达式

定义一个关于color的函数

Definition monochrome (c : color) : bool :=
  match c with
  | black ⇒ true
  | white ⇒ true
  | primary p ⇒ false
  end.
Definition isred (c : color) : bool :=
  match c with
  | black ⇒ false
  | white ⇒ false
  | primary red ⇒ true
  | primary _ ⇒ false
  end.

primary _ 是构造子 primary 应用到除 red 之外的任何 rgb 构造子上

元组

定义一个由四位字节组成的元组

Inductive bit : Type :=
  | B0
  | B1.
  
Inductive nybble : Type :=
  | bits (b0 b1 b2 b3 : bit).
  
Check (bits B1 B0 B1 B0)
    : nybble.
Definition all_zero (nb : nybble) : bool :=
  match nb with
    | (bits B0 B0 B0 B0) ⇒ true
    | (bits _ _ _ _) ⇒ false
  end.

数值

我们把这个部分放在一个模块中,这样我们自己对自然数的定义就不会干扰标准库中的自然数

Module NatPlayground.

大写字母O表示零,当S构造函数应用于自然数n的表示时,结果是n+1,其中S代表后继(successor),可被放在一个自然数之前产生另一个自然数

Inductive nat : Type :=
  | O
  | S (n : nat).

0 → O,1 → S O,2 → S(S O),3 → S(S(S O)),以此类推

定义自然数的前趋函数

Definition pred (n : nat) : nat :=
  match n with
    | O ⇒ O
    | S n' ⇒ n'
  end.

定义自然数减法函数

Definition minustwo (n : nat) : nat :=
  match n with
    | O ⇒ O
    | S O ⇒ O
    | S (S n') ⇒ n'
  end.
Compute (minustwo 4).
(* ===> 2 : nat *)
End NatPlayground.

Coq 会默认将自然数打印为十进制形式

Check (S (S (S (S O)))).
(* ===> 4 : nat *)

递归

关键字 Fixpoint 可用于定义递归函数

比如判断自然数是否为偶数

Fixpoint evenb (n:nat) : bool :=
  match n with
  | O ⇒ true
  | S O ⇒ false
  | S (S n') ⇒ evenb n'
  end.

判断自然数是否为奇数

Definition oddb (n:nat) : bool :=
  negb (evenb n).
Example test_oddb1: oddb 1 = true.
Proof. simpl. reflexivity. Qed.
Example test_oddb2: oddb 4 = false.
Proof. simpl. reflexivity. Qed.

递归多参数函数

Module NatPlayground2.

Fixpoint plus (n : nat) (m : nat) : nat :=
  match n with
    | O ⇒ m
    | S n' ⇒ S (plus n' m)
  end

两个自然数的乘法

Fixpoint mult (n m : nat) : nat :=
  match n with
    | O ⇒ O
    | S n' ⇒ plus m (mult n' m)
  end.
Example test_mult1: (mult 3 3) = 9.
Proof. simpl. reflexivity. Qed.

两个自然数相减

Fixpoint minus (n m:nat) : nat :=
  match n, m with
  | O , _ ⇒ O
  | S _ , O ⇒ n
  | S n', S m' ⇒ minus n' m'
  end.
  
End NatPlayground2.

自然数的幂

Fixpoint exp (base power : nat) : nat :=
  match power with
    | O ⇒ S O
    | S p ⇒ mult base (exp base p)
  end.

比较两个自然数是否相等

Fixpoint eqb (n m : nat) : bool :=
  match n with
  | O ⇒ match m with
         | O ⇒ true
         | S m' ⇒ false
         end
  | S n' ⇒ match m with
            | O ⇒ false
            | S m' ⇒ eqb n' m'
            end
  end.

第一个参数是否小于等于第二个参数

Fixpoint leb (n m : nat) : bool :=
  match n with
  | O ⇒ true
  | S n' ⇒
      match m with
      | O ⇒ false
      | S m' ⇒ leb n' m'
      end
  end.

第一个参数是否严格小于第二个参数

Definition ltb (n m:nat) : bool :=
  (negb(eqb n m)) && (leb n m)

为了方便我们引入notation来记这几个常用的函数

Notation "x + y" := (plus x y)
                       (at level 50, left associativity)
                       : nat_scope.
Notation "x - y" := (minus x y)
                       (at level 50, left associativity)
                       : nat_scope.
Notation "x * y" := (mult x y)
                       (at level 40, left associativity)
                       : nat_scope.
Notation "x =? y" := (eqb x y) (at level 70) : nat_scope.
Notation "x <=? y" := (leb x y) (at level 70) : nat_scope.

1.2 基于化简的证明

simpl 化简等式两边

reflexivity 检查两边是否具有相同的值,会自动做一些化简

intros n 假设存在一个任意自然数 n,将量词从证明目标转移到当前假设的上下文中

ExampleTheorem 表示完全一样的东西

策略是一条可以用在 Proof 和 Qed(证毕)之间的指令,告诉 Coq 如何来检验我们所下的断言的正确性

例如:

Theorem plus_O_n : forall n : nat, 0 + n = n.
Proof.
  intros n. reflexivity.  Qed.
Theorem plus_1_l : forall n:nat, 1 + n = S n.
Proof.
  intros n. reflexivity. Qed.
Theorem mult_0_l : forall n:nat, 0 * n = 0.
Proof.
  intros n. reflexivity. Qed.

后缀 _l 读作“在左边”

1.3 基于改写的证明

intros 将前提从证明目标移到当前上下文的假设中

rewrite 用来告诉 Coq 执行这种替换的策略

Admitted 指令告诉 Coq 我们想要跳过此定理的证明

例子一:

Theorem plus_id_example : ∀ n m:nat,
  n = m →
  n + n = m + m.

该定理并未对自然数 n 和 m 所有可能的值做全称断言,而是讨论了仅当 n = m 时这一更加特定情况

Proof.
  (* 将两个量词移到上下文中: *)
  intros n m.
  (* 将前提移到上下文中,并将其命名为 H *)
  intros H.      
  (* 告诉 Coq 改写当前目标,把前提等式 H 的左边替换成右边 *)
  rewrite → H.    
  reflexivity. Qed.

→表示把左边替换成右边,←表示把右边替换成左边

便于理解,放个例子

引入前提 H : n = m

image-20211220155253820

如果是 -> ,代表把式子里面的n都换成m

image-20211220155353407

如果是 <-,表示把式子里的m都换成n,逆向替换

image-20211220160446719

例子二:

Theorem plus_id_exercise : forall n m o : nat,
  n = m -> m = o -> n + m = m + o.
Proof.
  intros n m o H H1.
  rewrite -> H.
  rewrite -> H1.
  reflexivity.
Qed.

为了便于理解,具体过程如下

引入前提

image-20211220160550092

根据前提 H1:n = m

把式子中的n换成m

image-20211220160640356

根据前提 H1:n = m

把式子中的m都换成o

image-20211220160733102

Check 命令

可用来检查以前声明的引理和定理

Check mult_n_O.
(* ===> forall n : nat, 0 = n * 0  *)
Check mult_n_Sm.
(* ===> forall n m : nat, n * m + n = n * S m  *)

除了上下文中现有的假设外,还可以通过 rewrite 策略来运用前期证明过的定理

例子三

Theorem mult_n_0_m_0 : ∀ n m : nat,
  (n × 0) + (m × 0) = 0.
Proof.
  intros n m.
  rewrite <- mult_n_O.
  rewrite <- mult_n_O.
  reflexivity. Qed.

例子四

Theorem mult_n_1 : ∀ n : nat,
  n × 1 = n.
Proof.
  intros.
  rewrite <- mult_n_Sm.
  rewrite <- mult_n_O.
  reflexivity. Qed.

例子五

Theorem mult_0_plus : forall n m : nat,
  (0 + n) * m = n * m.
Proof.
  intros n m.
  rewrite -> plus_O_n.
  reflexivity.  Qed.

例子六

Theorem mult_S_1 : forall n m : nat,
  m = S n ->
  m * (1 + n) = m * m.
Proof.
  intros n m H.
  simpl.
  rewrite <- H.
  reflexivity.
Qed.

1.4 基于情况分析的证明

destruct 分别对 n = 0 和 n = S n’ 这两种情况进行分析的策略

例一

Theorem plus_1_neq_0 : forall n : nat,
  beq_nat (n + 1) 0 = false.
Proof.
  intros n. destruct n as [| n'].
  - reflexivity.
  - reflexivity.
Qed.

destruct 生成两个子目标,然后我们分别证明

as [| n’] 是介绍模式,指出变量,变量之间用|分开。第一个组件是空的,因为O的构造函数是空的,第二个组件n’,因为S是一元构造函数

eqn:E 注释告诉析构函数给这个方程命名E

— 符号 标明这两个生成的子目标所对应的证明部分

image-20211220164854781

例二

证明布尔值的取反是对合(Involutive)的

Theorem negb_involutive : forall b : bool,
  negb (negb b) = b.
Proof.
  intros b. destruct b.
  - reflexivity.
  - reflexivity.  Qed.

destruct 没有 as 子句,因为此处 destruct 生成的子分类均无需绑定任何变量

b分成了true和false两种情况讨论

image-20211220165231404

例三

在一个子目标内调用 destruct,产生出更多的证明义务,使用不同的标号来标记目标的不同层级

Theorem andb_commutative : ∀ b c, andb b c = andb c b.
Proof.
  intros b c. destruct b
  - destruct c eqn:Ec.
    + reflexivity.
    + reflexivity.
  - destruct c eqn:Ec.
    + reflexivity.
    + reflexivity.
Qed.

具体过程如下:

引入变量b c

image-20211220165449153

分别讨论b为true和b为false两种情况

image-20211220165534214

在b为true的情况下,分别讨论c为true和c为false两种情况

image-20211220165618172

除了 - 和 + 之外,还可以使用 × – ***,也可以用花括号将每个子证明目标括起来

Theorem andb_commutative' : ∀ b c, andb b c = andb c b.
Proof.
  intros b c. destruct b
  { destruct c
    { reflexivity. }
    { reflexivity. } }
  { destruct c
    { reflexivity. }
    { reflexivity. } }
Qed.

花括号还允许我们在一个证明中的多个层级下使用同一个标号

Theorem andb3_exchange :
  ∀ 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.
    { destruct d eqn:Ed.
      - reflexivity.
      - reflexivity. }
    { destruct d eqn:Ed.
      - reflexivity.
      - reflexivity. }
  - destruct c eqn:Ec.
    { destruct d eqn:Ed.
      - reflexivity.
      - reflexivity. }
    { destruct d eqn:Ed.
      - reflexivity.
      - reflexivity. }
Qed.

最后说一种简便写法,很多证明在引入变量之后会立即对它进行情况分析:

intros x y. destruct y as [|y] eqn:E.

但可以通过使用介绍模式而不是变量名来对变量进行案例分析

Theorem plus_1_neq_0' : ∀ n : nat,
  (n + 1) =? 0 = false.
Proof.
  intros [|n].
  - reflexivity.
  - reflexivity. Qed.

如果没有需要命名的构造子参数,只需写上 [] 即可进行情况分析

Theorem andb_commutative'' :
  forall b c, andb b c = andb c b.
Proof.
  intros [] [].
  - reflexivity.
  - reflexivity.
  - reflexivity.
  - reflexivity.
Qed.

image-20211220171812434

练习一

Theorem zero_nbeq_plus_1 : forall n : nat,
  0 =? (n + 1) = false.
Proof.
  intros [| n'].
  -simpl. reflexivity.
  -simpl. reflexivity.
Qed.

熟练使用简化的引入写法

image-20211220172404962

练习二

Theorem andb_true_elim2 : forall b c : bool,
  andb b c = true -> c = true.
Proof.
  intros [] [].
  - reflexivity.
  - intro H.
    rewrite <- H.
    reflexivity.
  - reflexivity.
  - intro H.
    rewrite <- H.
    reflexivity.
Qed.

说明一下第二种情况和第四种情况的过程,之前一直无法理解

引入 false && false = true 的条件,想要证明的结论是 false = true

image-20211220172108234

把 条件中的true rewrite 为 false && false

image-20211220172211887

1.5 递归函数Fixpoint

1.6 更多练习

练习一

证明以下关于布尔函数的定理

Theorem identity_fn_applied_twice :
  forall (f : bool -> bool),
  (forall (x : bool), f x = x) ->
  forall (b : bool), f (f b) = b.
Proof.
  intros f H b.
  rewrite -> H.
  rewrite -> H.
  reflexivity.
Qed.

image-20211221005426342

image-20211221005440041

image-20211221005454137

练习二

Theorem negation_fn_applied_twice :
  forall (f : bool -> bool),
  (forall (x : bool), f x = negb x) ->
  forall (b : bool), f (f b) = b.
Proof.
  intros f H b.
  rewrite -> H.
  rewrite -> H.
  rewrite -> negb_involutive.
  reflexivity.
Qed.

其中
negb_involutive
     : forall b : bool, negb (negb b) = b

练习三

Theorem andb_eq_orb :
  forall (b c : bool),
  (andb b c = orb b c) ->
  b = c.
Proof.
  intros b c H.
  destruct b.
  - destruct c.
    + reflexivity.
    + simpl in H.
      rewrite -> H. reflexivity.
  - destruct c.
    + simpl in H.
      rewrite -> H. reflexivity.
    + reflexivity.
Qed.

二、归纳证明 induction

2.1 归纳证明

在开始之前把上一章所有的定义都导入进来

在 CoqIDE 中:Open Basics.v,complie → compile buffer → make makefile

然后 Open Induction.v

From LF Require Export Basics.

证明这种关于数字、列表等归纳定义的集合, 我们通常需要一个更强大的推理原理:归纳

方法:通过应用 induction,把它分为两个子目标:

  • 一个是我们必须证明 P(O) 成立
  • 另一个是我们必须证明 P(n’) → P(S n’)

例题

例子一:

Theorem plus_n_O : forall n:nat, n = n + 0.
Proof.
  intros n. induction n as [| n' IHn'].
  - (* n = 0 *)    reflexivity.
  - (* n = S n' *) simpl. rewrite <- IHn'. reflexivity.  Qed.

具体过程如下:

通过induction as分成两种情况,用|隔开

在第一个子目标中n被0取代

image-20211221192147740

在第二个目标中,n 被 S n’ 取代,IHn’ :n’ = n’ + 0 是已知前提

image-20211221192213502

待证目标变成了 (S n’) + 0 = S n’,它可被simpl化简为 S (n’ + 0) = S n’,而此结论可通过 IHn’ 得出

这里没太懂

image-20211221192228733

改写

image-20211221192244674

例子二

Theorem minus_diag : forall n,
  minus n n = 0.
Proof.
  intros n. induction n as [| n' IHn'].      // IHn' : n' - n' = 0
  - (* n = 0 *)
    simpl. reflexivity.
  - (* n = S n' *)            // S n' - S n' = 0
    simpl.                    // n' - n' = 0
    rewrite -> IHn'.          // 0 = 0
    reflexivity.  Qed.        

这里没懂

好像知道了simpl的作用,可以把 S n’ 化成 n’,不知道为啥

image-20211221193012713

image-20211221193023673

练习

练习一

Theorem mult_0_r : forall n:nat,
  n * 0 = 0.
Proof.
  intros n.
  induction n as [|n' IHn].
  - reflexivity.
  - simpl. rewrite -> IHn. reflexivity. Qed.

好像知道了simpl的作用,可以把 S n’ 化成 n’,不知道为啥

Theorem plus_n_Sm : forall n m : nat,
  S (n + m) = n + (S m).
Proof.
  intros n m.
  induction n as [|n' IHn].
  - reflexivity.
  - simpl. rewrite -> IHn. reflexivity.
Qed.

好像知道了simpl的另一个作用,可以把 S n’ + m 化成 S (n’ + m)

Theorem plus_comm : forall n m : nat,
  n + m = m + n.
Proof.
  intros n m.
  induction n as [|n' IHn].   //  IHn : n' + m = m + n'
  - (* n = 0 *)
    simpl.
    rewrite <- plus_n_O.
    reflexivity.
  - (* n = S n' *)             //  S n' + m = m + S n'
    simpl.                     //  S (n' + m) = m + S n'
    rewrite -> IHn.            //  S (m + n') = m + S n'
    rewrite -> plus_n_Sm.      //  m + S n' = m + S n'
    reflexivity.
Qed.

其中
plus_n_O
     : forall n : nat, n = n + 0
     
plus_n_Sm
     : forall n m : nat, S (n + m) = n + S m
Theorem plus_assoc : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof.
  intros n m p.
  induction n as [|n' IHn].                 // IHn : n' + (m + p) = n' + m + p
  - reflexivity.
  - (* n = S n' *)             //  S n' + (m + p) = S n' + m + p
    simpl.                     //  S (n' + (m + p)) = S (n' + m + p)
    rewrite -> IHn.            //  S (n' + m + p) = S (n' + m + p)
    reflexivity.
Qed.

练习二

前提

Fixpoint double (n:nat) :=
  match n with
  | O => O
  | S n' => S (S (double n'))
  end.

用归纳法证明

Lemma double_plus : forall n, double n = n + n .
Proof.
  intros n.
  induction n as [|n' IHn].      // double n' = n' + n'
  - (* n = 0 *)
    reflexivity.
  - (* n = S n' *)               // double (S n') = S n' + S n'
   simpl.                        // S (S (double n')) = S (n' + S n')
   rewrite -> IHn.               // S (S (n' + n')) = S (n' + S n')
   rewrite <- plus_n_Sm.         // S (S (n' + n')) = S (S (n' + n'))
   reflexivity.
Qed.


其中
     
plus_n_Sm
     : forall n m : nat, S (n + m) = n + S m

练习三

Check negb_involutive.
Theorem evenb_S : forall n : nat,
  evenb (S n) = negb (evenb n).
Proof.
  intros n.
  induction n as [|n' IHn].            //  IHn : evenb (S n') = negb (evenb n')
  - reflexivity.
  -                                    //  evenb (S (S n')) = negb (evenb (S n'))
    rewrite -> IHn.                    //  evenb (S (S n')) = negb (negb (evenb n'))
    rewrite -> negb_involutive.        //  evenb (S (S n')) = evenb n'
    reflexivity.
Qed.


其中
negb_involutive
     : forall b : bool, negb (negb b) = b

辨析

一直没懂什么时候用基于化简,什么时候用基于归纳

0在n左边的时候用化简,0在n右边的时候用归纳

0 + n = n ,n = 0 + n 用化简,n + 0 = n,n = n + 0用归纳

0 * n = 0 用化简,n * 0 = 0用归纳

因为 0 * n = 0 可以被simpl. 后者不行

前者 simpl 结果

image-20211221193905944

image-20211221193916639

后者 simpl 结果,没有变化,这只能用归纳了

image-20211221194000491

image-20211221194011773

2.2 证明里的证明

在 Coq 中,大的证明通常会被分为一系列定理, 后面的定理引用之前的定理

例如,我们之前对 mult_0_plus 定理的证明引用了前一个名为 plus_O_n 的定理

Theorem mult_0_plus : forall n m : nat,
  (0 + n) * m = n * m.
Proof.
  intros n m.
  rewrite -> plus_O_n.
  reflexivity.  Qed.

而我们只需使用 assert 就能陈述并证明 plus_O_n,后面的大括号内容是证明过程

Theorem mult_0_plus' : forall n m : nat,
  (0 + n) * m = n * m.
Proof.
  intros n m.
  assert (H: 0 + n = n). { reflexivity. }
  rewrite -> H.
  reflexivity.  Qed.

另一个例子

为了在需要的地方使用我们的小定理,可以引入一个局部引理来陈述 n + m = m + n,之后用 plus_comm 证明它, 并用它来进行期望的改写

Theorem plus_rearrange : forall n m p q : nat,
  (n + m) + (p + q) = (m + n) + (p + q).
Proof.
  intros n m p q.
  assert (H: n + m = m + n).
  { rewrite -> plus_comm. reflexivity. }
  rewrite -> H. reflexivity.  Qed.

2.3 形式化证明

形式化证明和非形式化证明的对比

非形式化证明是算法,形式化证明是代码

一方面,“读者”可以是像 Coq 这样的程序, 此时灌输的是 P 能够从一个确定的,由形式化逻辑规则组成的集合中机械地推导出来,而证明则是指导程序检验这一事实的方法。这种方法就是形式化证明

另一方面,读者也可以是人类,这种情况下证明可以用英语或其它自然语言写出, 因此必然是非形式化的

由于我们在本课程中使用 Coq,因此会重度使用形式化证明

但这并不意味着我们 可以完全忽略掉非形式化的证明过程!

2.4 更多练习

练习一

可以不用归纳

Theorem plus_swap : forall n m p : nat,
  n + (m + p) = m + (n + p).
Proof.
  intros n m p.                            //  n + (m + p) = m + (n + p)
  rewrite -> plus_assoc.                   //  n + m + p = m + (n + p)
  assert (H: n + m = m + n).            
  { rewrite -> plus_comm.  reflexivity. }
  rewrite -> H.                            //  n + m + p = n + (m + p)
  rewrite -> plus_assoc.                   //  n + m + p = n + m + p
  reflexivity.
Qed.

plus_assoc
     : forall n m p : nat, n + (m + p) = n + m + p
     
plus_comm
     : forall n m : nat, n + m = m + n

复习一下如果用归纳做,好像不是同一道题

Theorem plus_assoc : forall n m p : nat,
  n + (m + p) = (n + m) + p.
Proof.
  intros n m p.
  induction n as [|n' IHn].                 // IHn : n' + (m + p) = n' + m + p
  - reflexivity.
  - (* n = S n' *)             //  S n' + (m + p) = S n' + m + p
    simpl.                     //  S (n' + (m + p)) = S (n' + m + p)
    rewrite -> IHn.            //  S (n' + m + p) = S (n' + m + p)
    reflexivity.
Qed.

练习二

Theorem mult_n_Sm: forall n m : nat,
  n * S m = n + n * m.
Proof.
  intros n m.
  induction n as [|n' IHn].           //  IHn : n' * S m = n' + n' * m
  - (* n = 0 *)
    reflexivity.
  - (* n = S n' *)                    //  S n' * S m = S n' + S n' * m
    simpl.                            //  S (m + (n' + n' * m)) = S (n' + (m + n' * m)) 
    rewrite -> IHn.                   //  S (n' + (m + n' * m)) = S (n' + (m + n' * m))
    rewrite plus_swap.
    reflexivity.
Qed.

练习三

Theorem mult_comm : forall m n : nat,
  m * n = n * m.
Proof.
  intros n m.
  induction n as [|n' IHn].
  - rewrite -> mult_0_l.
    rewrite <- mult_n_O.
    reflexivity.
  - simpl.
    rewrite -> IHn.
    rewrite -> mult_n_Sm.
    reflexivity.
Qed.

练习四

区分什么时候该用什么方法

(a) 它能否能只用化简和改写来证明

(b) 它还需要分类讨论(destruct)

© 它还需要归纳证明

Theorem leb_refl : forall n:nat,
  true = leb n n.
Proof.
  intros n.
  induction n as [|n' IHn].
  - (* n = 0 *)
    reflexivity.
  - simpl. rewrite <- IHn. reflexivity.
Qed.
Theorem zero_nbeq_S : forall n:nat,
  beq_nat 0 (S n) = false.
Proof.
  intros n.
  simpl.
  reflexivity.
Qed.
Theorem S_nbeq_0 : forall n:nat,
  beq_nat (S n) 0 = false.
Proof.
  reflexivity.
Qed.

Theorem plus_ble_compat_l : forall n m p : nat,
  leb n m = true -> leb (p + n) (p + m) = true.
Proof.
  intros n m p H.
  induction p as [|p' IHp].
  - simpl.
    rewrite -> H.
    reflexivity.
  - simpl.
    rewrite -> IHp.
    reflexivity.
Qed.
Theorem mult_1_l : forall n:nat, 1 * n = n.
Proof.
  intros n.
  simpl. rewrite <- plus_n_O. reflexivity.
Qed.

这里simpl又可以把 1 * n = n 改写为 n + 0 = n,真是搞不懂

Theorem mult_plus_distr_r : forall n m p : nat,
  (n + m) * p = (n * p) + (m * p).
Proof.
  intros n m p.
  induction n as [|n' IHn].
  - reflexivity.
  - simpl.
    rewrite -> IHn.
    rewrite -> plus_assoc.
    reflexivity.
Qed.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Explore functional programming and discover new ways of thinking about code. You know you need to master functional programming, but learning one functional language is only the start. In this book, through articles drawn from PragPub magazine and articles written specifically for this book, you'll explore functional thinking and functional style and idioms across languages. Led by expert guides, you'll discover the distinct strengths and approaches of Clojure, Elixir, Haskell, Scala, and Swift and learn which best suits your needs. Contributing authors: Rich Hickey, Stuart Halloway, Aaron Bedra, Michael Bevilacqua-Linn, Venkat Subramaniam, Paul Callaghan, Jose Valim, Dave Thomas, Natasha Murashev, Tony Hillerson, Josh Chisholm, and Bruce Tate. Functional programming is on the rise because it lets you write simpler, cleaner code, and its emphasis on immutability makes it ideal for maximizing the benefits of multiple cores and distributed solutions. So far nobody's invented the perfect functional language - each has its unique strengths. In Functional Programming: A PragPub Anthology, you'll investigate the philosophies, tools, and idioms of five different functional programming languages. See how Swift, the development language for iOS, encourages you to build highly scalable apps using functional techniques like map and reduce. Discover how Scala allows you to transition gently but deeply into functional programming without losing the benefits of the JVM, while with Lisp-based Clojure, you can plunge fully into the functional style. Learn about advanced functional concepts in Haskell, a pure functional language making powerful use of the type system with type inference and type classes. And see how functional programming is becoming more elegant and friendly with Elixir, a new functional language built on the powerful Erlang base.The industry has been embracing functional programming more and more, driven by the need for concurrency and parallelism. This collection of articles will lead you to mastering the functional approach to problem solving. So put on your explorer's hat and prepare to be surprised. The goal of exploration is always discovery. What You Need: Familiarity with one or more programming languages.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值