Chapter 1 - Types and Functions

1.1 Booleans


(* Commented because of naming conflicts with the Standard library: 
Inductive bool : Type :=
| true : bool
| false : bool.

Definition negb (x : bool) : bool :=
  match x with
    | true => false
    | false => true
  end. *)


Check negb.
Check negb (negb true).
Compute negb (negb true).

Lemma L1 :
  negb true = false.
Proof. simpl. reflexivity. Qed.

Lemma negb_negb (x : bool) :
  negb (negb x) = x.
Proof.
  destruct x.
  - reflexivity.
  - reflexivity.
Qed.

Goal (x: bool), negb (negb x) = x.
Proof.
  destruct x; reflexivity.
Qed.

(* Commented because of naming conflicts with the Standard library: 
Definition andb (x y : bool) : bool :=
  match x with
    | true => y
    | false => false
  end. *)


Print andb.

Lemma andb_com x y :
  andb x y = andb y x.
Proof.
  destruct x.
  - destruct y ; reflexivity.
  - destruct y ; reflexivity.
Qed.

Goal x y: bool,
       andb x y = andb y x.
Proof. destruct x, y; reflexivity. Qed.

(* Exercise 1.1.1 *)

(* Definition orb (x y: bool) :=
  (* ... *) *)


Goal x y: bool,
       orb x y = orb y x.
Abort.

(* Formulate and prove the De Morgan Law. *)

1.2 Cascaded Functions


Check andb.

Check fun x : boolx.

Compute (fun x : boolx) true.

Check andb true.

Compute andb true.

(* Commented because of naming conflicts with the Standard library: 
Definition andb : bool -> bool -> bool :=
  fun x : bool =>
    fun y : bool =>
      match x with
         | true => y
         | false => false
      end.
*)


Print negb.

Print andb.

1.3 Natural Numbers


(* Commented because of naming conflicts with the Standard library: 
Inductive nat : Type :=
| O : nat
| S : nat -> nat.

Definition pred (x : nat) : nat :=
  match x with
    | O => O
    | S x' => x'
  end.
 *)


Print nat.

Print Nat.pred.

Compute pred (S(S O)).

(* Commented because of naming conflicts with the Standard library: 
Fixpoint plus (x y : nat) : nat :=
  match x with
    | O => y
    | S x' => S (plus x' y)
  end.
 *)


Print plus.

Compute plus (S O) ( S O).

Fixpoint leb (x y: nat) : bool :=
  match x with
    | Otrue
    | S x'match y with
                | Ofalse
                | S y'leb x' y'
              end
  end.

Fixpoint leb' (x y: nat) : bool :=
  match x, y with
    | O, _true
    | _, Ofalse
    | S x', S y'leb' x' y'
  end.

(* Exercise 1.3.1 *)

(* Definition mult (x y: nat) : nat := 
 (* ... *) *)


1.4 Structural Induction and Rewriting


Lemma plus_O x :
  plus x O = x.
Proof.
  induction x ; simpl.
  - reflexivity.
  - rewrite IHx. reflexivity.
Qed.

Lemma plus_S x y :
  plus x (S y) = S (plus x y).
Proof.
  induction x ; simpl.
  - reflexivity.
  - rewrite IHx. reflexivity.
Qed.

Lemma plus_com x y :
  plus x y = plus y x.
Proof.
  induction x ; simpl.
  - rewrite plus_O. reflexivity.
  - rewrite plus_S. rewrite IHx. reflexivity.
Qed.

Lemma plus_asso x y z :
  plus (plus x y) z = plus x (plus y z).
Proof.
  induction x ; simpl.
  - reflexivity.
  - rewrite IHx. reflexivity.
Qed.

(* Exercise 1.4.1 *)

Goal x y, plus x y = plus y x.
Proof.
  induction y.
Abort.

1.5 More on Rewriting


Require Import Omega.

Lemma plus_AC x y z :
  plus y (plus x z) = plus (plus z y) x.
Proof.
  setoid_rewrite plus_com at 3.
  setoid_rewrite plus_com at 1.
  apply plus_asso.
Qed.

(* Commented because of naming conflicts with the Standard library: 
Fixpoint mult (x y : nat) : nat :=
    match x with
    O => O
   | S x' => plus y (mult x' y)
    end. *)


Lemma plus_AC' x y z :
  plus (plus (mult x y) (mult x z)) (plus y z) = plus (plus (mult x y) y) (plus (mult x z) z).
Proof.
  rewrite plus_asso. rewrite plus_asso. f_equal.
  setoid_rewrite plus_com at 1. rewrite plus_asso. f_equal.
  apply plus_com.
Qed.

Example Ex1 x y z :
  S (plus x (plus y z)) = S (plus (plus x y) z).
Proof. rewrite <- plus_asso. reflexivity. Qed.

(* Exercise 1.5.1 *)

Lemma mult_S' x y :
  mult x (S y) = plus (mult x y) x.
Abort.

(* Exercise 1.5.2 *)
Lemma mult_O (x : nat) :
  mult x O = O.
Abort.

Lemma mult_S (x y : nat) :
  mult x (S y) = plus (mult x y) x.
Abort.

Lemma mult_com (x y : nat) :
  mult x y = mult y x.
Abort.

Lemma mult_dist (x y z: nat) :
  mult (plus x y) z = plus (mult x z) (mult y z).
Abort.

Lemma mult_asso (x y z: nat) :
  mult (mult x y) z = mult x (mult y z).
Abort.

1.6 Recursive Abstractions


Print plus.

Compute plus O.

Compute plus (S (S O)).

Compute fun xplus (S x).

Goal plus O = fun xx.
Proof. compute. reflexivity. Qed.

Goal (fun xplus (S x)) = fun x yS (plus x y).
Proof. compute. reflexivity. Qed.

1.7 Defined Notations


(* Commented because of naming conflicts with the Standard library: 
Notation "x + y" := (plus x y)  (at level 50, left associativity).
Notation "x * y" := (mult x y) (at level 40, left associativity).
*)


Lemma mult_dist' x y z :
  x × (y + z) = x×y + x×z.
Proof.
  induction x ; simpl.
  - reflexivity.
  - rewrite IHx. rewrite plus_asso. rewrite plus_asso. f_equal.
    setoid_rewrite <- plus_asso at 2.
    setoid_rewrite plus_com at 4.
    symmetry. apply plus_asso.
Qed.

Set Printing All.
Check O + O × S O.

Unset Printing All.

(* Exercise 1.7.1 *)

Goal (x : nat),
  x × O = O.
Abort.

Goal x y: nat,
  x × (S y) = (x × y) + x.
Abort.

Goal x y: nat,
  x × y = y × x.
Abort.

Goal x y z: nat,
  (x + y) × z = (x × z) + (y × z).
Abort.

Goal x y z: nat,
  (x × y) × z = x × (y × z).
Abort.

(* Exercise 1.7.2 *)

Goal x y z: nat,
       x × (y × z) = x × y × z.
Abort.

(* Exercise 1.7.3 *)

Goal x,
       (x + x) + x = x + (x + x).
Proof.
  induction x.
  Restart.
Abort.

1.8 Standard Library.


Set Printing All.

Check 2 + 3×2.

Unset Printing All.

Locate "*".

Set Printing All.

Check if false then 0 else 1.

Unset Printing All.

Goal x y z, (x + y) + z = x + (y + z).
Proof. intros x y z. omega. Qed.

Goal x y, 2 × (x + y) = (y + x) × 2.
Proof. intros x y. omega. Qed.

1.9 Pairs and Implicit Arguments


(* Commented because of naming conflicts with the Standard library: 
Inductive prod (X Y : Type) : Type :=
| pair : X -> Y -> prod X Y. 

Arguments pair {X} {Y} _ _. *)


Check pair 0 true.
Check @pair nat.
Check @pair nat bool 0.

Set Printing All.
Check pair 0 true.
Unset Printing All.

About pair.

Set Implicit Arguments.
Unset Strict Implicit.

(* Commented because of naming conflicts with the Standard library: 
Definition fst (X Y : Type) (p : prod X Y) : X :=
  match p with pair x _ => x end.

Definition snd (X Y : Type) (p : prod X Y) : Y :=
  match p with pair _ y => y end. *)


Compute fst (pair O true).

Compute snd (pair O true).

Lemma pair_eta (X Y : Type) (p : prod X Y) :
  pair (fst p) (snd p) = p.
Proof. destruct p as [x y]. simpl. reflexivity. Qed.

Definition swap (X Y : Type) (p : X × Y) : Y × X :=
  (snd p, fst p).

Compute swap (0, true).

Lemma swap_swap (X Y : Type) (p : X × Y) :
  swap (swap p) = p.
Proof. destruct p as [x y]. unfold swap. simpl. reflexivity. Qed.

Check (fun x : nat × nat × natfst x) (1, 2, 3).

(* Exercise 1.9.1 *)

(* Definition car (* ... *)

Definition cas (* ... *)

Lemma car_spec X Y Z (f: X -> Y -> Z) x y:
  car f (x,y) = f x y.
Abort.

Lemma cas_spec X Y Z (f: X * Y -> Z) x y:
  cas f x y = f (x, y).
Abort. *)


1.10 Lists


(* Commented because of naming conflicts with the Standard library: 
Inductive list (X : Type) : Type :=
| nil : list X
| cons : X -> list X -> list X. 

Arguments nil {X}. *)


Set Printing All.

Check cons 1 nil.

Unset Printing All.

Notation "x :: y" := (cons x y) (at level 60, right associativity).

Set Printing All.

Check 1::2::nil.

Unset Printing All.

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

Set Printing All.

Check [1;2].

Unset Printing All.

(* The following tends to crash CoqIDE.
   Toggle View -> Display all low-level contents instead! *)

(* Unset Printing All. *)

Fixpoint length (X : Type) (A : list X) : nat :=
  match A with
    | nilO
    | _ :: A'S (length A')
  end.

Notation "| A |" := (length A) (at level 70).

Fixpoint app (X : Type) (A B : list X) : list X :=
  match A with
    | nilB
    | x :: A'x :: app A' B
  end.

Notation "x ++ y" := (app x y) (at level 60, right associativity).

Fixpoint rev (X : Type) (A : list X) : list X :=
  match A with
    | nilnil
    | x :: A'rev A' ++ [x]
  end.

Compute rev [1;2;3].

Lemma app_nil (X : Type) (A : list X) :
  A ++ nil = A.
Proof.
  induction A as [|x A] ; simpl.
  - reflexivity.
  - rewrite IHA. reflexivity.
Qed.

(* Enabling these lines will mess things up in this file, 
   because we've defined many of the names that it imports.
   In order to avoid confusion, don't enable them. *)

(*
Require Import List.
Import ListNotations.
*)


(* Exercise 1.10.1 *)

(* Needed for section 1.11 *)
Lemma app_assoc (X : Type) (A B C : list X) :
  (A ++ B) ++ C = A ++ (B ++ C).
Admitted.

Lemma length_app (X : Type) (A B : list X) :
  |A ++ B| = |A| + |B|.
Abort.

Lemma rev_app (X : Type) (A B : list X) :
  rev (A ++ B) = rev B ++ rev A.
Abort.

Lemma rev_rev (X : Type) (A : list X) :
  rev (rev A) = A.
Abort.

1.11 Quantified Inductive Hypotheses


Fixpoint revi (X : Type) (A B : list X) : list X :=
  match A with
    | nilB
    | x :: A'revi A' (x :: B)
  end.

Lemma revi_rev (X : Type) (A B : list X) :
  revi A B = rev A ++ B.
Proof.
  revert B. induction A as [|x A] ; simpl.
  - reflexivity.
  - intros B. rewrite IHA. rewrite app_assoc. simpl. reflexivity.
Qed.

(* Exercise 1.11.1 *)

Lemma rev_revi (X : Type) (A : list X) :
  rev A = revi A nil.
Abort.

(* Exercise 1.11.2 *)

Fixpoint lengthi (X : Type) (A : list X) (n : nat) :=
  match A with
    | niln
    | _ :: A'lengthi A' (S n)
  end.

Lemma lengthi_length X (A : list X) n :
  lengthi A n = |A| + n.
Abort.

Lemma length_lengthi X (A : list X) :
  |A| = lengthi A 0.
Abort.

(* Exercise 1.11.3 *)

(* Fixpoint fact (n : nat) : nat :=
(* ... *)

Fixpoint facti (n a: nat) : nat := 
(* ... *)

Goal forall n, fact n = facti n 1. *)


1.12 Iteration as Polymorphic Higher-Order Function


Fixpoint iter (n : nat) (X : Type) (f : X X) (x : X) : X :=
  match n with
    | 0 ⇒ x
    | S n'f (iter n' f x)
  end.

Lemma iter_plus x y :
  x + y = iter x S y.
Proof. induction x ; simpl ; congruence. Qed.

Lemma iter_minus x y :
  x-y = iter y pred x.
Proof. induction y ; simpl ; omega. Qed.

(* Exercise 1.12.1 *)

Lemma iter_mult x y :
  x × y = iter x (plus y) 0.
Abort.

(* Exercise 1.12.2 *)

Lemma iter_shift X (f : X X) x n :
  iter (S n) f x = iter n f (f x).
Abort.

(* Exercise 1.12.3 *)

(* Fixpoint power (x n: nat) := 
(* ... *)

Lemma iter_power x n:
  power x n = iter n (mult x 1). *)


(* Exercise 1.12.4 *)

(* Definition step (p : nat * nat) : nat * nat :=
   (* ... *)
  
Lemma it_fac_step n :
  step (n, fac n) = (S n, fac (S n)).
Abort.

Lemma it_fac' n : 
  iter n step (O, S O) = (n, fac n).
Abort.
  
Lemma it_fac n :  
  fac n = snd (iter n step (O, S O)).
Abort.
*)


(* Exercise 1.12.5 *)
Definition Nat := X: Type, (X X) X X.

(* Fixpoint encode (n: nat) : Nat :=
  (* ... *)

Definition decode (N: Nat) : nat :=
  (* ... *)

Goal forall n: nat,
         decode (encode n) = n.
Abort. *)


1.13 Options and Finite Types


Inductive Empty_set : Type := .

Lemma vacuous_truth (x : Empty_set) :
  1 = 2.
Proof. destruct x. Qed.

Inductive option (X : Type) : Type :=
| Some : X option X
| None : option X.

Definition fin (n : nat) : Type :=
  Nat.iter n option Empty_set.

Definition a11 : fin 1 := @None Empty_set.
Definition a21: fin 2 := Some a11.
Definition a22 : fin 2 := @None (fin 1).
Definition a31: fin 3 := Some a21.
Definition a32 : fin 3 := Some a22.
Definition a33 : fin 3 := @None (fin 2).

Goal n, fin (2+n) = option (fin (S n)).
Proof. intros n. reflexivity. Qed.

Goal m n, fin (m+n) = fin (n+m).
Proof.
  intros m n. f_equal. omega.
Qed.

(* For Coq to get typing right, we had to replace None by a11 in this lemma: *)
Lemma fin1 (x : fin 1):
  x = a11.
Proof.
  destruct x as [x|].
  - simpl in x. destruct x.
  - reflexivity.
Qed.

(* Exercise 1.13.1 *)

(*Definition fromBool (b: bool) : fin 2 :=
  (* ... *)

Definition toBool (x: fin 2) : bool :=
  (* ... *)

Lemma bool_fin b: toBool (fromBool b) = b.
Abort.

Lemma fin_bool x: fromBool (toBool x) = x.
Abort. *)


(* Exercise 1.13.2 *)

(* Definition fromNat (n: nat) : option nat :=
  (* ... *)

Definition toNat (n: option nat) : nat :=
  (* ... *)

Goal forall n, toNat (fromNat n) = n.
Abort.

Goal forall n, fromNat (toNat n) = n.
Abort. *)


(* Exercise 1.13.3*)

(*
Fixpoint find (X: Type) (p: X -> bool) (A: list X) : option X :=
  (* ... *)

Fixpoint minus_opt (x y: nat) : option nat :=
 (* ... *) *)


1.14 More about Functions


Check x : nat, nat.