函数式编程

(* Final Exam --- February 26, 2023  
You are allowed to search and use any property provided in the 
standard library of Coq. *)

Require Import Nat.
Require Import List.

Notation "[ ]" := nil. 
Notation "[ x ; .. ; y ]" := (cons x .. (cons y nil) ..).

Definition admit {T: Type} : T.  Admitted.

(* 1. Prove the following fact about natural numbers by induction. *)
    
Lemma mul_2_r : forall  n : nat, 
  n * 2 = n + n.
Proof. 
  intros. induction n.
  - reflexivity.
  - simpl. rewrite IHn. rewrite <- plus_Sn_m. apply f_equal.
    rewrite PeanoNat.Nat.add_comm. reflexivity. Qed.

(* 2. Define a function called cubic so that (cubic n) returns true 
iff n is a cubic number, i.e. n = n' * n' * n' for some n'. *)

Fixpoint cubic_m_n (m:nat)(n:nat) : bool :=
  match m with
  | 0=> n=?0
  | S m' => if m*m*m=?n then true
            else cubic_m_n m' n
  end.

Definition cubic (n : nat) : bool :=
  cubic_m_n n n.
Example cubic_test1 : cubic 8 = true.
Proof. simpl. reflexivity. Qed.

Example cubic_test2 : cubic 25 = false.
Proof. simpl. reflexivity. Qed.


(* 3. Let two sequences of numbers F1(n) and F2(n) be given as follows.
   F1(0) = 1
   F1(n) = 2 * F1(n-1)   for n > 0.

   F2(0) = F2(1) = 1
   F2(n+2) = F2(n) + F2(n+1)    for n >= 0.

Define the function Seq such that (Seq n) returns the sequence

[F1(0); F2(0); F1(1); F2(1); ... ; F1(n); F2(n)].
*)
Fixpoint F1 (n:nat) : nat :=
  match n with
  |0=>1
  |S n'=> 2*(F1 n')
  end.

Fixpoint F2 (n:nat) :nat :=
  match n with
  | 0=>1
  |S 0=>1
  |S n'=>match n' with
        | 0 => 2
        | S n'' => F2 n' + F2 n''
        end
  end.

Fixpoint Seq (n:nat) : list nat :=
  match n with
  |0=>[1;1]
  | S n'=>(Seq n')++[F1 n;F2 n]
  end.

Example Seq_test :  Seq 5 = [1; 1; 2; 1; 4; 2; 8; 3; 16; 5; 32; 8].
Proof. simpl. reflexivity. Qed.

(* 4. Let lt be the predicate such that (lt n m) holds iff n is strictly
less than m. Prove the following theorem about lt. *)

Inductive lt : nat -> nat -> Prop :=
 | lt1 : forall n, lt n (S n)
 | lt2 : forall n m, lt n m -> lt n (S m).

Theorem n_lt_m__Sn_lt_Sm : forall n m,
  lt n m -> lt (S n) (S m).
Proof.
  intros.
  induction H.
  - apply lt1.
  - apply lt2. apply IHlt.
Qed.

Theorem lt_add_n: forall n p q,lt p q->lt (n+p) (n+q).
intros.
  induction n.
  - simpl. apply H.
  - simpl. apply n_lt_m__Sn_lt_Sm. apply IHn.
Qed.

Theorem lt_add : forall n m p q, lt n m -> lt p q -> lt (n+p) (m+q).
Proof.
  intros. induction H.
  - simpl. apply lt2. apply lt_add_n. apply H0.
  - simpl. apply lt2. apply IHlt.
Qed.
  


(* 5. Write a function (transform):

      transform : list nat -> list (list nat )

   which transforms a list into a list of 3 sublists. The first sublist
   contains all the odd numbers in the original list; the second sublist contains 
   all the numbers divisible by 3 in the original list; the last sublist contains 
   all the other numbers in the original list. 
   The order of elements in the three sublists should be the same as their 
   order in the original list. 

   Hint: You may use the Coq function (filter).
*)
Fixpoint is_odd_number(n:nat) : bool :=
  match n with
  |0=>false
  |S 0=>true
  |S (S n') =>  is_odd_number n'
  end.

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

Definition transform (l : list nat) : list (list nat) :=
  match l with
  |[]=>[[];[];[]]
  |_=>[filter is_odd_number l;filter divisible_by_three l;
      filter (fun n=> andb (negb (is_odd_number n)) (negb (divisible_by_three n))) l]
  end.

Example transform_test: 
transform [3;7;6;9;4;5;16;14;15] = [[3; 7; 9; 5; 15]; [3; 6; 9; 15]; [4; 16; 14]].
Proof. simpl. reflexivity. Qed.


(* 6. Prove the following fact about excluded middle. *)

Theorem de_morgan : 
   (forall P, P \/ ~P) -> (forall P Q, ~(~P \/ ~Q) -> P /\ Q).
Proof. 
  unfold not. intros. destruct (H P).
  - split.
    + apply H1.
    + destruct (H Q).
      {  apply H2. }
      { destruct H0. right. apply H2. }
  - split.
    + destruct H0. left. apply H1.
    + destruct (H Q).
      { apply H2. }
      { destruct H0. left. apply H1. }
Qed.


(* 7. Consider the following type btree about binary trees.
Define a function to give an inorder traversal of the tree and collect
all the odd numbers in a list. 
*)

Inductive btree : Set :=
 | leaf : nat -> btree 
 | node : nat -> btree -> btree -> btree.

Fixpoint inorder (t: btree) : list nat :=
  match t with
  | leaf n => if is_odd_number n then [n] else []
  | node n bt1 bt2 => if is_odd_number n then inorder bt1 ++ [n] ++ inorder bt2
                      else inorder bt1 ++ inorder bt2
end.

Example bt_test : inorder (node 5 (node 1 (leaf 0) (node 3 (leaf 2) (leaf 4))) 
                                   (node 9 (node 7 (leaf 6) (leaf 8)) (leaf 10))) 
                   = [1; 3; 5; 7; 9].
Proof. simpl. reflexivity. Qed.

(* 8. The following definitions specify the abstract syntax of
    some arithmetic expressions and an evaluation function. *)

Inductive aexp : Type :=
  | ANum : nat -> aexp
  | APlus : aexp -> aexp -> aexp
  | AMinus : aexp -> aexp -> aexp
  | AMult : aexp -> aexp -> aexp.

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)
  end.

(* Suppose we define a function that takes an arithmetic expression 
   and slightly simplifies it, changing every occurrence of [e + 0],
   [e - 0], or [1 * e] into [e], and [0 * e] into [0]. *)

Fixpoint optimize (a:aexp) : aexp :=
  match a with
  | ANum n => ANum n
  | APlus e1 (ANum 0)=> optimize e1
  | AMinus e1 (ANum 0) => optimize e1
  | AMult  (ANum 0) e1  => ANum 0
  | AMult  (ANum 1) e1  => optimize e1
  | APlus  e1 e2 => APlus  (optimize e1) (optimize e2)
  | AMinus e1 e2 => AMinus (optimize e1) (optimize e2)
  | AMult  e1 e2 => AMult  (optimize e1) (optimize e2)
  end.

(* Prove the following theorem that states the correctness of the 
optimization with respect to the evaluation of arithmetic expressions. *)

Theorem optimize_sound: forall a,
  aeval (optimize a) = aeval a.
Proof. 
  intros. induction a.
  - simpl. reflexivity.
  - destruct a2;try(simpl; simpl in IHa2; rewrite IHa2; rewrite IHa1; reflexivity).
    + destruct n.
      { simpl; rewrite IHa1; rewrite PeanoNat.Nat.add_0_r; reflexivity. }
      { simpl; rewrite IHa1; reflexivity. }
  - destruct a2;try(simpl; simpl in IHa2; rewrite IHa2; rewrite IHa1; reflexivity).
    + destruct n.
      { simpl; rewrite IHa1; rewrite PeanoNat.Nat.sub_0_r; reflexivity. }
      { simpl; rewrite IHa1; reflexivity. }
  - destruct a1;try(simpl; simpl in IHa1; rewrite IHa1; rewrite IHa2; reflexivity).
    + destruct n as [|n'] eqn:Eqn'.
      { simpl; reflexivity. }
      { destruct n'.
        { simpl. rewrite IHa2.  rewrite PeanoNat.Nat.add_0_r. reflexivity. }
        { simpl. rewrite IHa2. reflexivity. }
      }
Qed.

(* 9. Define in OCaml the function (map2 f l1 l2), where f is a function 
that takes two parameters and l1 and l2 are lists, that calls f on each 
pair of corresponding elements from l1 and l2 and returns a list of the 
results. If l1 and l2 do not have the same number of elements. For example, 
the length is n1 for one list and n2 for the other, with n1 < n2, then f 
only operates on the first n1 elements for both lists. For example,

# map2 (fun x y -> x + y) [1;2;3;4] [5;6;7;8;9;10];;
  - : int list = [6; 8; 10; 12]

*) 
let rec map2 f l1 l2 =
  match l1,l2 with
  |[],_ -> []
  |_,[] -> [] 
  |n1::l1',n2::l2' -> (n1+n2)::(map2 f l1' l2')
;;
map2 (fun x y -> x + y) [1;2;3;4] [5;6;7;8;9;10];;
(* 10. We will define in OCaml the function (merge sort list), where list 
is an unsorted list of numbers, that implements merge sort and returns a 
new list containing the elements of list in sorted order. 
                                                     Let us proceed in three steps.

(a) Define a function (split l), where l is a list of integers, that returns a 
tuple of two lists, (l1, l2), such that half the elements of l are in l1 and half 
    are in l2, in alternating order. For example,
          
                  # split [1];;
- : int list * int list = ([1], [])
          
                          # split [1;7;2;6;8;3;9;5;4];;
- : int list * int list = ([1; 2; 8; 9; 4], [7; 6; 3; 5])

*)
let rec split l =
  match l with
  |[]->([] ,[])
  |n::l'-> match l' with
    |[] -> ([n],[])
    |m::l''->let (l,r)  = split l'' in
        (n::l,m::r)
;;
split [1];;  
split [1;7;2;6;8;3;9;5;4];;
(*
(b) Define a function (merge l1 l2) that merges two lists sorted in ascending 
order into a new list, still in ascending order. For example,
         
# merge [1;3;5] [2;6;8];;
- : int list = [1; 2; 3; 5; 6; 8]

*)
let rec merge l1 l2 =
  match l1,l2 with
  |[],_->l2
  |_,[]->l1
  |n1::l1',n2::l2'->if n1<n2 then n1::merge l1' l2
      else n2::merge l1 l2'
;;
merge [] [1];;
merge [1;3;5] [2;6;8];;
(*
(c) Now define the function (merge sort list) by making use of the two functions 
split and merge defined above to sort the list list. For example,

# merge_sort [2;4;1;6;9;6;4;1;3;5;10] ;;
- : int list = [1; 1; 2; 3; 4; 4; 5; 6; 6; 9; 10]
*)

let rec mergesort list =
  match list with
  | [] -> []
  |[x] -> [x]
  | h::tl -> let (l , r) = split list in 
      merge (mergesort l) (mergesort r);;
mergesort[2;4;1;6;9;6;4;1;3;5;10] ;;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值