函数编程强调让我们了解如何将输入映射到输出,同时将函数(方法)作为一级值(类似于数字,集合都属于数学中某一级别的值),也就是将函数作为数据来处理。
函数式编程思想也包括我们在OOP中涉及到的多态,代码重用,但是函数式编程是通过函数将程序模块化。
coq内置特性非常少,并没有像高级语言一样已经定义了常用的数据类型,而是提供了一种强大的机制来从头定义新的数据类型。
当然coq标准库提供了原始的数据类型,但我们这里选择显式地重述定义。
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
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)).
每个表达式都有一个类型
确定输入内容的类型
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
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).
本课程中涉及很少
Coq < Definition example:=fun x=>x*x.
example is defined
Coq < Compute example 1.
= 1
: nat
Coq < Compute example 3.
= 9
: nat
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
定义计算级别和结合顺序
Coq < Example test1: orb true false=false.
test1 < Proof. simpl. reflexivity. Qed.
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
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.
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.
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).
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独特的证明功能,本篇代码中间隐藏了数个小彩蛋,鬼姐姐们可以找找噢。