離散數學——coq學習筆記(一)


OMG,沒學離散數學之前覺得這就是門數學,學了之後被邏輯和編程同時吊打,這裏根據一些資料把之前學的coq相關規則回顧一遍,畢竟要準備期末考試複習了,這學期東西又難又是在線上教學,一定要好好加油鴨。(鬼姐姐根本沒在怕的)
所用參考書目爲《Logic Foundations》

BASICS

函數編程

函數編程強調讓我們瞭解如何將輸入映射到輸出,同時將函數(方法)作爲一級值(類似於數字,集合都屬於數學中某一級別的值),也就是將函數作爲數據來處理。
函數式編程思想也包括我們在OOP中涉及到的多態,代碼重用,但是函數式編程是通過函數將程序模塊化。

枚舉類型

coq內置特性非常少,並沒有像高級語言一樣已經定義了常用的數據類型,而是提供了一種強大的機制來從頭定義新的數據類型。
當然coq標準庫提供了原始的數據類型,但我們這裏選擇顯式地重述定義。

引例:Days of the week(定義一個類型)

defining a new set of data values-a type

Coq < Inductive day:Type:=
Coq < |monday
Coq < |tuesday
Coq < |wednesday
Coq < |thursday
Coq < |friday
Coq < |saturday
Coq < |sunday.
day is defined
day_rect is defined
day_ind is defined
day_rec is defined
  1. coq代碼中經常會用數據:類型的格式展現一個數據和其相應的類型
  2. “:=”在coq中表示等於,用"."結束語句
  3. 這裏定義了一個新的類型,名字是day,有七個成員
    用coq定義一個函數對這些數據進行操作
Definition next_weekday (d:day) : day :=
  match d with
  | monday => tuesday
  | tuesday => wednesday
  | wednesday => thursday
  | thursday => friday
  | friday => monday
  | saturday => monday
  | sunday => monday
  end.

1 定義函數 Definition fun_name (輸入):(返回),注意這裏的輸入輸出依然採用數據名稱:數據類型的格式,但是一旦命名的數據名稱必須在環境中使用(比如d),對於輸入,一般都需要使用一個數據,需要說明數據,但是類型可有可無,對於輸出,必須說明其類型(coq可以進行類型判斷,但是我們一般會包括他們,使閱讀更加容易)
2 在定義每個情況的輸出類型時,必須定義所有可能的情況,比如這裏需要列舉所有星期對應的返回值。
定義好一個函數後,我們使用Compute命令對結果進行查詢。

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

調用函數的時候和高級語言格式很接近。
執行結果:
在這裏插入圖片描述
在這裏插入圖片描述

一些基礎語法定義

Type

每個表達式都有一個類型

  • New Types from Old
    就像前面定義的Days of week一樣,我們定義的都是枚舉類型的例子

Check命令

確定輸入內容的類型

  • 簡單的類型
Coq < Check True.
True
     : Prop

Coq < Check 3.
3
     : nat

Coq < Check 3+2.
3 + 2
     : nat
  • 有序數對
Coq < Check (2,3=5).
(2, 3 = 5)
     : nat * Prop
  • 函數類型
    1 使用關鍵字fun構造一個新函數,它將替換λlambda微積分(之前的博客有提到)和類似理論的符號。
    they are written with arrows.
Coq < Check (fun x:nat=>x=3).
fun x : nat => x = 3
     : nat -> Prop
Coq < Check (forall x:nat,x<3\/(exists y:nat,x=y+3)).
forall x : nat, x < 3 \/ (exists y : nat, x = y + 3)
     : Prop

2 let的使用(爲函數提供一個臨時的名字,之前的博客提到過)

Check (let f := fun x => (x * 3,x) in f 3).
let f := fun x : nat => (x * 3, x) in f 3 : nat * nat

3 構造枚舉類函數時其成員也可以定義成一個函數(constructor)

Inductive reb:Type :=
|red
|green
|blue.

Inductive color :Type:=
|black
|white
|primary (p:reb).
Check primary red.
Check primary blue.

多元組

多個參數單個構造函數用於創建元組類型
比如我們在用二進制編碼時,可以將某一位定義是取值爲0或1的函數,那樣我們表示一個字節時相當於八位的元組,很像在高級語言中的數組

Inductive bit:Type :=
|B0
|B1.
Inductive byte:Type :=
| bits(b0 b1 b2 b3 b4 b5 b6 b7:bit).
Check (bits B0 B1 B0 B1 B0 B1 B0 B1).

下劃線的使用,我們用下劃線代替未定義的變量,比如我們要檢查定義的字節是否各位爲全0

Definition all_zero (input:byte):bool:=
match input with
|(bits B0 B0 B0 B0 B0 B0 B0 B0)=>true
|(bits _ _ _ _ _ _ _ _)=>false
end.
Compute all_zero(bits B1 B1 B1 B1 B1 B1 B1 B1).

Modules

本課程中涉及很少

Compute命令

定義一個新常量

Coq < Definition example:=fun x=>x*x.
example is defined

Coq < Compute example 1.
     = 1
     : nat

Coq < Compute example 3.
     = 9
     : nat

BOOLEANS

布爾表達式的構造

相關定義

  • 構建布爾集合,歸納定義布爾集合
Coq < Inductive bool:Type:=
Coq < |true
Coq < |false.
bool is defined
bool_rect is defined
bool_ind is defined
bool_rec is defined
  • 定義布爾運算
Coq < Definition negb b:=
Coq < match b with
Coq < |true=>false
Coq < |false=>true
Coq < end.
negb is defined

Coq <  Definition andb n m:=
Coq < match n with
Coq < |true=>m
Coq < |false=>false
Coq < end.
andb is defined

Coq < Definition orb n m :=
Coq < match n with
Coq < |true=>true
Coq < |false=>m
Coq < end.
orb is defined

Coq < Compute orb true false.
     = true
     : bool
Coq < Compute negb true.
     = false
     : bool

插入標記

Coq <  Notation "n | m" := (andb n m)(at level 85,right associativity).

Coq < Notation "n & m":=(andb n m)(at level 80,right associativity).

Coq <  Notation "\ n":=(negb n)(at level 70,right associativity).

Coq < Check true & false | \true.
(true & false) & \ true
     : bool

Coq < Compute true & false | \true.
     = false
     : bool

定義計算級別和結合順序

布爾表達式的相關運算律

用Example檢查計算結果是否符合預期

Coq < Example test1: orb true false=false.
test1 < Proof. simpl. reflexivity. Qed.

課堂實例

自然數和鏈表的遞歸構造

自然數

  • 自然數的構造
    1 自然數的內部表示
Inductive nat:Type:=
|o
|S(n:nat).
(*O和S只是一種表達方式,O是歸納基礎,S是構造算子,我們甚至可以這樣定義*)
Inductive nat':Type:=
|Lilghost
|darling (d:nat').
Check darling(darling(darling Lilghost)).

遞歸定義:O是歸納基礎,S是構造算子

Coq < Check 1.
1
     : nat
Coq <  Check S(S(S O)).
3
     : nat

coq內部用一進製表示自然數(上邊那個是O不是0)
我們使用命令

Print nat.

可以輸出nat的內部表示

Coq < Print nat.
Inductive nat : Set :=  O : nat | S : nat -> nat

For S: Argument scope is [nat_scope]

Unset Printing Notations.
Set Printing Notations.

表示打開其內部表示

Coq < Unset Printing Notations.

Coq < Check 3.
S (S (S O))
     : nat

2 一些關於自然數的函數

  • 前置函數
  • 利用遞歸函數確定給定自然數是否爲偶數

3 定義自然數的加法
加法的定義:取m的n次後繼
定義遞歸函數時用Fixpoint命令

Fixpoint plus n m := 
match n with
| O => m
| S n' => S (plus n' m)
end.
Compute plus 2 3.
Notation "x + y":=(plus x y).
Compute 2+3.

使用Notation能用符號表示函數

  • 練習:使用遞歸定義自然數乘法,減法
    練習答案:
Coq < Fixpoint plus n m:=
Coq < match n with
Coq < |O=>m
Coq < |S n'=>S (plus n' m)
Coq < end.
plus is defined
plus is recursively defined (decreasing on 1st argument)

Coq <  Fixpoint mulit n m:=
Coq < match n with
Coq < |1=>m
Coq < |S n'=>plus m (mulit n' m)
Coq < |O=>O
Coq < end.
mulit is defined
mulit is recursively defined (decreasing on 1st argument)

Coq < Compute mulit 3 5.
     = 15
     : nat

Coq < Notation "n * m":=(mulit n m).

Coq < Compute 3*0.
     = 0
     : nat

Coq < Compute 5*9.
     = 45
     : nat
Coq < Fixpoint sub n m :=
Coq < match n,m with
Coq < |O,_=>O
Coq < |_,O=> n
Coq < |S x',S y'=>sub x' y'
Coq < end.
sub is defined
sub is recursively defined (decreasing on 1st argument)

Coq < Compute sub 5 2.
     = 3
     : nat

遞歸是函數式編程的基本理念,保證函數的終止性,沒有傳統過程語言的循環結構

鏈表的構造

Inductive natlist : Set :=
| nil : natlist
| cons : nat -> natlist -> natlist.

Definition l1 := cons 2 (cons 1 nil).

(* syntax tree of l1 is: 
           cons 
             |
       +-----+-----+ 
       |           |
       2         cons
                   |
               +---+---+
               |       |
               1      nil
*)

Definition l2 := cons 3 nil.

Compute l1.

Notation "[ ]" := nil.
Notation "[ a ; .. ; b ]" := (cons a .. (cons b nil) .. ).

Compute l1.

Fixpoint plus s t := match s with
                    | [] => t
                    | cons a s' => cons a (plus s' t)
                    end.

Compute plus [3] [2;1].

Notation "x + y" := (plus x y).

Compute l2 + l1.

Fixpoint rev s := match s with
                  | [] => []
                  | cons a s' => (rev s') + [a]
                  end.

Compute rev (l2 + l1).

  • 練習:計算鏈表長度,自然數鏈表元素求和。
Coq < Fixpoint plus n m:=
Coq < match n with
Coq < |O=>m
Coq < |S n'=>S(plus n' m)
Coq < end.
plus is defined
plus is recursively defined (decreasing on 1st argument)

Coq < Inductive list:Set:=
Coq < |nil:list
Coq < |cons :nat->list->list.
list is defined
list_rect is defined
list_ind is defined
list_rec is defined

Coq <  Definition l1:=cons 2(cons 1(cons 3 nil)).
l1 is defined

Coq <  Fixpoint nons s :=
Coq <  match s with
Coq < |nil=>O
Coq < |cons a s'=>plus 1 (nons s')
Coq < end.
nons is defined
nons is recursively defined (decreasing on 1st argument)

Coq < Compute nons l1.
     = 3
     : nat

Coq <  Fixpoint sum s :=
Coq < match s with
Coq < |nil=>O
Coq < |cons a s'=>plus a (sum s')
Coq < end.
sum is defined
sum is recursively defined (decreasing on 1st argument)

Coq < Compute sum l1.
     = 6
     : nat

參考書目課後題答案

  • EX1:standard (nandb)
Definition negb b:=
match b with
|true=>false
|false=>true
end.

Definition nandb (b1:bool) (b2:bool) : bool :=
match b1 with
|false=>true
|true=>negb b2
end.
Example test_nandb1: (nandb true false) = true.
Proof. simpl. reflexivity. Qed.
Example test_nandb2: (nandb false false) = true.
Proof. simpl. reflexivity. Qed.
Example test_nandb3: (nandb false true) = true.
Proof. simpl. reflexivity. Qed.
Example test_nandb4: (nandb true true) = false.
Proof. simpl. reflexivity. Qed.
  • EX2: standard (andb3)
Definition andb n m:=
match n with
|true=>m
|false=>false
end.

Definition andb3 (b1:bool) (b2:bool) (b3:bool) : bool :=
match b1 with
|false=>false
|true=>andb b2 b3
end.
Example test_andb31: (andb3 true true true) = true.
Proof. simpl. reflexivity. Qed.
Example test_andb32: (andb3 false true true) = false.
Proof. simpl. reflexivity. Qed.
Example test_andb33: (andb3 true false true) = false.
Proof. simpl. reflexivity. Qed.
Example test_andb34: (andb3 true true false) = false.
Proof. simpl. reflexivity. Qed.
  • EX3 standard (factorial)
Fixpoint muti m n:=
match m with
|O=>O
|S m'=>(plus n (muti m' n))
end.

Fixpoint factorial (n:nat) : nat:=
match n with 
|O=>1
|S n'=>(muti n (factorial n'))
end.
Example test_factorial1: (factorial 3) = 6.
Proof. simpl. reflexivity. Qed.
Example test_factorial2: (factorial 5) = (mult 10 12).
Proof. simpl. reflexivity. Qed.

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.

Compute (eqb 3 5).
  • EX4
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.

Definition ltb (n m : nat) : bool:=
match (minus n m)with 
|O=>(negb(eqb n m))
|_=>false
end.
Notation "x <? y" := (ltb x y) (at level 70) : nat_scope.
Example test_ltb1: (ltb 2 2) = false.
Proof. simpl. reflexivity. Qed.
Example test_ltb2: (ltb 2 4) = true.
Proof. simpl. reflexivity. Qed.
Example test_ltb3: (ltb 4 2) = false.
Proof. simpl. reflexivity. Qed.

終於結束第一部分了,接下來是coq獨特的證明功能,本篇代碼中間隱藏了數個小彩蛋,鬼姐姐們可以找找噢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章