(** * ImpParser: Lexing and Parsing in Coq *)

(** The development of the Imp language in [Imp.v] completely ignores
    issues of concrete syntax -- how an ascii string that a programmer
    might write gets translated into abstract syntax trees defined by
    the datatypes [aexp], [bexp], and [com].  In this chapter, we
    illustrate how the rest of the story can be filled in by building
    a simple lexical analyzer and parser using Coq's functional
    programming facilities.

    It is not important to understand all the details here (and
    accordingly, the explanations are fairly terse and there are no
    exercises).  The main point is simply to demonstrate that it can
    be done.  You are invited to look through the code -- most of it
    is not very complicated, though the parser relies on some
    "monadic" programming idioms that may require a little work to
    make out -- but most readers will probably want to just skim down
    to the Examples section at the very end to get the punchline. *)

(* DROP *)

(* ################################################################# *)
(** * Internals *)

Set Warnings "-notation-overridden,-parsing,-deprecated-implicit-arguments".
Require Import Coq.Strings.String.
Require Import Coq.Strings.Ascii.
Require Import Coq.Arith.Arith.
Require Import Coq.Arith.EqNat.
Require Import Coq.Lists.List.
Import ListNotations.
Require Import Maps.
Require Import Imp.

(* ================================================================= *)
(** ** Lexical Analysis *)

Definition isWhite (c : ascii) : bool :=
  let n := nat_of_ascii c in
  orb (orb (beq_nat n 32)   (* space *)
           (beq_nat n 9))   (* tab *)
      (orb (beq_nat n 10)   (* linefeed *)
           (beq_nat n 13)). (* Carriage return. *)

Notation "x '<=?' y" := (leb x y)
  (at level 70, no associativity) : nat_scope.

Definition isLowerAlpha (c : ascii) : bool :=
  let n := nat_of_ascii c in
    andb (97 <=? n) (n <=? 122).

Definition isAlpha (c : ascii) : bool :=
  let n := nat_of_ascii c in
    orb (andb (65 <=? n) (n <=? 90))
        (andb (97 <=? n) (n <=? 122)).

Definition isDigit (c : ascii) : bool :=
  let n := nat_of_ascii c in
     andb (48 <=? n) (n <=? 57).

Inductive chartype := white | alpha | digit | other.

Definition classifyChar (c : ascii) : chartype :=
  if isWhite c then
    white
  else if isAlpha c then
    alpha
  else if isDigit c then
    digit
  else
    other.

Fixpoint list_of_string (s : string) : list ascii :=
  match s with
  | EmptyString => []
  | String c s => c :: (list_of_string s)
  end.

Fixpoint string_of_list (xs : list ascii) : string :=
  fold_right String EmptyString xs.

Definition token := string.

Fixpoint tokenize_helper (cls : chartype) (acc xs : list ascii)
                       : list (list ascii) :=
  let tk := match acc with [] => [] | _::_ => [rev acc] end in
  match xs with
  | [] => tk
  | (x::xs') =>
    match cls, classifyChar x, x with
    | _, _, "("      =>
      tk ++ ["("]::(tokenize_helper other [] xs')
    | _, _, ")"      =>
      tk ++ [")"]::(tokenize_helper other [] xs')
    | _, white, _    =>
      tk ++ (tokenize_helper white [] xs')
    | alpha,alpha,x  =>
      tokenize_helper alpha (x::acc) xs'
    | digit,digit,x  =>
      tokenize_helper digit (x::acc) xs'
    | other,other,x  =>
      tokenize_helper other (x::acc) xs'
    | _,tp,x         =>
      tk ++ (tokenize_helper tp [x] xs')
    end
  end %char.

Definition tokenize (s : string) : list string :=
  map string_of_list (tokenize_helper white [] (list_of_string s)).

Example tokenize_ex1 :
    tokenize "abc12==3  223*(3+(a+c))" %string
  = ["abc"; "12"; "=="; "3"; "223";
       "*"; "("; "3"; "+"; "(";
       "a"; "+"; "c"; ")"; ")"]%string.
Proof. reflexivity. Qed.

(* ================================================================= *)
(** ** Parsing *)

(* ----------------------------------------------------------------- *)
(** *** Options With Errors *)

(** An [option] type with error messages: *)

Inductive optionE (X:Type) : Type :=
  | SomeE : X -> optionE X
  | NoneE : string -> optionE X.

Implicit Arguments SomeE [[X]].
Implicit Arguments NoneE [[X]].

(** Some syntactic sugar to make writing nested match-expressions on
    optionE more convenient. *)

Notation "'DO' ( x , y ) <== e1 ; e2"
   := (match e1 with
         | SomeE (x,y) => e2
         | NoneE err => NoneE err
       end)
   (right associativity, at level 60).

Notation "'DO' ( x , y ) <-- e1 ; e2 'OR' e3"
   := (match e1 with
         | SomeE (x,y) => e2
         | NoneE err => e3
       end)
   (right associativity, at level 60, e2 at next level).

(* ----------------------------------------------------------------- *)
(** *** Generic Combinators for Building Parsers *)

Open Scope string_scope.

Definition parser (T : Type) :=
  list token -> optionE (T * list token).

Fixpoint many_helper {T} (p : parser T) acc steps xs :=
  match steps, p xs with
  | 0, _ =>
      NoneE "Too many recursive calls"
  | _, NoneE _ =>
      SomeE ((rev acc), xs)
  | S steps', SomeE (t, xs') =>
      many_helper p (t::acc) steps' xs'
  end.

(** A (step-indexed) parser that expects zero or more [p]s: *)

Fixpoint many {T} (p : parser T) (steps : nat) : parser (list T) :=
  many_helper p [] steps.

(** A parser that expects a given token, followed by [p]: *)

Definition firstExpect {T} (t : token) (p : parser T)
                     : parser T :=
  fun xs => match xs with
            | x::xs' =>
              if string_dec x t
              then p xs'
              else NoneE ("expected '" ++ t ++ "'.")
            | [] =>
              NoneE ("expected '" ++ t ++ "'.")
            end.

(** A parser that expects a particular token: *)

Definition expect (t : token) : parser unit :=
  firstExpect t (fun xs => SomeE(tt, xs)).

(* ----------------------------------------------------------------- *)
(** *** A Recursive-Descent Parser for Imp *)

(** Identifiers: *)

Definition parseIdentifier (xs : list token)
                         : optionE (id * list token) :=
match xs with
| [] => NoneE "Expected identifier"
| x::xs' =>
    if forallb isLowerAlpha (list_of_string x) then
      SomeE (Id x, xs')
    else
      NoneE ("Illegal identifier:'" ++ x ++ "'")
end.

(** Numbers: *)

Definition parseNumber (xs : list token)
                     : optionE (nat * list token) :=
match xs with
| [] => NoneE "Expected number"
| x::xs' =>
    if forallb isDigit (list_of_string x) then
      SomeE (fold_left
               (fun n d =>
                  10 * n + (nat_of_ascii d -
                            nat_of_ascii "0"%char))
               (list_of_string x)
               0,
             xs')
    else
      NoneE "Expected number"
end.

(** Parse arithmetic expressions *)

Fixpoint parsePrimaryExp (steps:nat)
                         (xs : list token)
                       : optionE (aexp * list token) :=
  match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
      DO (i, rest) <-- parseIdentifier xs ;
          SomeE (AId i, rest)
      OR DO (n, rest) <-- parseNumber xs ;
          SomeE (ANum n, rest)
                OR (DO (e, rest) <== firstExpect "("
                       (parseSumExp steps') xs;
          DO (u, rest') <== expect ")" rest ;
          SomeE(e,rest'))
  end

with parseProductExp (steps:nat)
                     (xs : list token) :=
  match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
    DO (e, rest) <==
      parsePrimaryExp steps' xs ;
    DO (es, rest') <==
       many (firstExpect "*" (parsePrimaryExp steps'))
            steps' rest;
    SomeE (fold_left AMult es e, rest')
  end

with parseSumExp (steps:nat) (xs : list token)  :=
  match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
    DO (e, rest) <==
      parseProductExp steps' xs ;
    DO (es, rest') <==
      many (fun xs =>
        DO (e,rest') <--
           firstExpect "+"
             (parseProductExp steps') xs;
           SomeE ( (true, e), rest')
        OR DO (e,rest') <==
        firstExpect "-"
           (parseProductExp steps') xs;
            SomeE ( (false, e), rest'))
        steps' rest;
      SomeE (fold_left (fun e0 term =>
                          match term with
                            (true,  e) => APlus e0 e
                          | (false, e) => AMinus e0 e
                          end)
                       es e,
             rest')
  end.

Definition parseAExp := parseSumExp.

(** Parsing boolean expressions: *)

Fixpoint parseAtomicExp (steps:nat)
                        (xs : list token)  :=
match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
     DO    (u,rest) <-- expect "true" xs;
         SomeE (BTrue,rest)
     OR DO (u,rest) <-- expect "false" xs;
         SomeE (BFalse,rest)
     OR DO (e,rest) <--
            firstExpect "not"
               (parseAtomicExp steps')
               xs;
         SomeE (BNot e, rest)
     OR DO (e,rest) <--
              firstExpect "("
                (parseConjunctionExp steps') xs;
          (DO (u,rest') <== expect ")" rest;
              SomeE (e, rest'))
     OR DO (e, rest) <== parseProductExp steps' xs;
            (DO (e', rest') <--
              firstExpect "=="
                (parseAExp steps') rest;
              SomeE (BEq e e', rest')
             OR DO (e', rest') <--
               firstExpect "<="
                 (parseAExp steps') rest;
               SomeE (BLe e e', rest')
             OR
               NoneE
      "Expected '==' or '<=' after arithmetic expression")
end

with parseConjunctionExp (steps:nat)
                         (xs : list token) :=
  match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
    DO (e, rest) <==
      parseAtomicExp steps' xs ;
    DO (es, rest') <==
       many (firstExpect "&&"
               (parseAtomicExp steps'))
            steps' rest;
    SomeE (fold_left BAnd es e, rest')
  end.

Definition parseBExp := parseConjunctionExp.

Check parseConjunctionExp.

Definition testParsing {X : Type}
           (p : nat ->
                list token ->
                optionE (X * list token))
           (s : string) :=
  let t := tokenize s in
  p 100 t.

(*
Eval compute in
  testParsing parseProductExp "x*y*(x*x)*x".

Eval compute in
  testParsing parseConjunctionExp "not((x==x||x*x<=(x*x)*x)&&x==x".
*)

(** Parsing commands: *)

Fixpoint parseSimpleCommand (steps:nat)
                            (xs : list token) :=
  match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
    DO (u, rest) <-- expect "SKIP" xs;
      SomeE (SKIP, rest)
    OR DO (e,rest) <--
         firstExpect "IF" (parseBExp steps') xs;
       DO (c,rest')  <==
         firstExpect "THEN"
           (parseSequencedCommand steps') rest;
       DO (c',rest'') <==
         firstExpect "ELSE"
           (parseSequencedCommand steps') rest';
       DO (u,rest''') <==
         expect "END" rest'';
       SomeE(IFB e THEN c ELSE c' FI, rest''')
    OR DO (e,rest) <--
         firstExpect "WHILE"
           (parseBExp steps') xs;
       DO (c,rest') <==
         firstExpect "DO"
           (parseSequencedCommand steps') rest;
       DO (u,rest'') <==
         expect "END" rest';
       SomeE(WHILE e DO c END, rest'')
    OR DO (i, rest) <==
         parseIdentifier xs;
       DO (e, rest') <==
         firstExpect ":=" (parseAExp steps') rest;
       SomeE(i ::= e, rest')
  end

with parseSequencedCommand (steps:nat)
                           (xs : list token) :=
  match steps with
  | 0 => NoneE "Too many recursive calls"
  | S steps' =>
      DO (c, rest) <==
        parseSimpleCommand steps' xs;
      DO (c', rest') <--
        firstExpect ";"
          (parseSequencedCommand steps') rest;
        SomeE(c ;; c', rest')
      OR
        SomeE(c, rest)
  end.

Definition bignumber := 1000.

Definition parse (str : string) : optionE (com * list token) :=
  let tokens := tokenize str in
  parseSequencedCommand bignumber tokens.

(* ################################################################# *)
(** * Examples *)

(*
Compute parse "
  IF x == y + 1 + 2 - y * 6 + 3 THEN
    x := x * 1;;
    y := 0
  ELSE
    SKIP
  END  ".
====>
  SomeE
     (IFB BEq (AId (Id 0))
              (APlus
                 (AMinus (APlus (APlus (AId (Id 1)) (ANum 1)) (ANum 2))
                    (AMult (AId (Id 1)) (ANum 6)))
                 (ANum 3))
      THEN Id 0 ::= AMult (AId (Id 0)) (ANum 1);; Id 1 ::= ANum 0
      ELSE SKIP FI, [])
*)

(*
Compute parse "
  SKIP;;
  z:=x*y*(x*x);;
  WHILE x==x DO
    IF z <= z*z && not x == 2 THEN
      x := z;;
      y := z
    ELSE
      SKIP
    END;;
    SKIP
  END;;
  x:=z  ".
====>
  SomeE
     (SKIP;;
      Id 0 ::= AMult (AMult (AId (Id 1)) (AId (Id 2)))
                     (AMult (AId (Id 1)) (AId (Id 1)));;
      WHILE BEq (AId (Id 1)) (AId (Id 1)) DO
        IFB BAnd (BLe (AId (Id 0)) (AMult (AId (Id 0)) (AId (Id 0))))
                  (BNot (BEq (AId (Id 1)) (ANum 2)))
           THEN Id 1 ::= AId (Id 0);; Id 2 ::= AId (Id 0)
           ELSE SKIP FI;;
        SKIP
      END;;
      Id 1 ::= AId (Id 0),
     [])
*)

(*
Compute parse "
  SKIP;;
  z:=x*y*(x*x);;
  WHILE x==x DO
    IF z <= z*z && not x == 2 THEN
      x := z;;
      y := z
    ELSE
      SKIP
    END;;
    SKIP
  END;;
  x:=z  ".
=====>
  SomeE
     (SKIP;;
      Id 0 ::= AMult (AMult (AId (Id 1)) (AId (Id 2)))
            (AMult (AId (Id 1)) (AId (Id 1)));;
      WHILE BEq (AId (Id 1)) (AId (Id 1)) DO
        IFB BAnd (BLe (AId (Id 0)) (AMult (AId (Id 0)) (AId (Id 0))))
                 (BNot (BEq (AId (Id 1)) (ANum 2)))
          THEN Id 1 ::= AId (Id 0);;
               Id 2 ::= AId (Id 0)
          ELSE SKIP
        FI;;
        SKIP
      END;;
      Id 1 ::= AId (Id 0),
     []).
*)

(* /DROP *)

(** $Date: 2017-04-26 17:33:43 -0400 (Wed, 26 Apr 2017) $ *)


(** * Induction: Proof by Induction *)

(** The next line imports all of our definitions from the
    previous chapter. *)

Require Export Basics.

(** For it to work, you need to use [coqc] to compile [Basics.v]
    into [Basics.vo].  (This is like making a .class file from a .java
    file, or a .o file from a .c file.)

    Here are two ways to compile your code:

     - CoqIDE:

         Open [Basics.v].
         In the "Compile" menu, click on "Compile Buffer".

     - Command line:

         Run [coqc Basics.v]

    *)

(* ###################################################################### *)
(** * Naming Cases *)

(** The fact that there is no explicit command for moving from
    one branch of a case analysis to the next can make proof scripts
    rather hard to read.  In larger proofs, with nested case analyses,
    it can even become hard to stay oriented when you're sitting with
    Coq and stepping through the proof.  (Imagine trying to remember
    that the first five subgoals belong to the inner case analysis and
    the remaining seven cases are what remains of the outer one...)
    Disciplined use of indentation and comments can help, but a better
    way is to use the [Case] tactic. *)

(* [Case] is not built into Coq: we need to define it ourselves.
    There is no need to understand how it works -- you can just skip
    over the definition to the example that follows.  It uses some
    facilities of Coq that we have not discussed -- the string
    library (just for the concrete syntax of quoted strings) and the
    [Ltac] command, which allows us to declare custom tactics.  Kudos
    to Aaron Bohannon for this nice hack! *)

Require String. Open Scope string_scope.

Ltac move_to_top x :=
  match reverse goal with
  | H : _ |- _ => try move x after H
  end.

Tactic Notation "assert_eq" ident(x) constr(v) :=
  let H := fresh in
  assert (x = v) as H by reflexivity;
  clear H.

Tactic Notation "Case_aux" ident(x) constr(name) :=
  first [
    set (x := name); move_to_top x
  | assert_eq x name; move_to_top x
  | fail 1 "because we are working on a different case" ].

Tactic Notation "Case" constr(name) := Case_aux Case name.
Tactic Notation "SCase" constr(name) := Case_aux SCase name.
Tactic Notation "SSCase" constr(name) := Case_aux SSCase name.
Tactic Notation "SSSCase" constr(name) := Case_aux SSSCase name.
Tactic Notation "SSSSCase" constr(name) := Case_aux SSSSCase name.
Tactic Notation "SSSSSCase" constr(name) := Case_aux SSSSSCase name.
Tactic Notation "SSSSSSCase" constr(name) := Case_aux SSSSSSCase name.
Tactic Notation "SSSSSSSCase" constr(name) := Case_aux SSSSSSSCase name.
(** Here's an example of how [Case] is used.  Step through the
   following proof and observe how the context changes. *)

Theorem andb_true_elim1 : forall b c : bool,
  andb b c = true -> b = true.
Proof.
  intros b c H.
  destruct b.
  Case "b = true".  (* <----- here *)
    reflexivity.
  Case "b = false".  (* <---- and here *)
    rewrite <- H.
    reflexivity.
Qed.

(** [Case] does something very straightforward: It simply adds a
    string that we choose (tagged with the identifier "Case") to the
    context for the current goal.  When subgoals are generated, this
    string is carried over into their contexts.  When the last of
    these subgoals is finally proved and the next top-level goal
    becomes active, this string will no longer appear in the context
    and we will be able to see that the case where we introduced it is
    complete.  Also, as a sanity check, if we try to execute a new
    [Case] tactic while the string left by the previous one is still
    in the context, we get a nice clear error message.

    For nested case analyses (e.g., when we want to use a [destruct]
    to solve a goal that has itself been generated by a [destruct]),
    there is an [SCase] ("subcase") tactic. *)

(** **** Exercise: 2 stars (andb_true_elim2) *)
(** Prove [andb_true_elim2], marking cases (and subcases) when
    you use [destruct]. *)

Theorem andb_true_elim2 : forall b c : bool,
  andb b c = true -> c = true.
Proof.
  intros b c H.
  destruct c.
  Case "c = true".
  reflexivity.
  Case "c = false".
  rewrite <- H.
  destruct b.
  SCase "b = false".
  reflexivity.
  reflexivity.
  Qed.

(** There are no hard and fast rules for how proofs should be
    formatted in Coq -- in particular, where lines should be broken
    and how sections of the proof should be indented to indicate their
    nested structure.  However, if the places where multiple subgoals
    are generated are marked with explicit [Case] tactics placed at
    the beginning of lines, then the proof will be readable almost no
    matter what choices are made about other aspects of layout.

    This is a good place to mention one other piece of (possibly
    obvious) advice about line lengths.  Beginning Coq users sometimes
    tend to the extremes, either writing each tactic on its own line
    or entire proofs on one line.  Good style lies somewhere in the
    middle.  In particular, one reasonable convention is to limit
    yourself to 80-character lines.  Lines longer than this are hard
    to read and can be inconvenient to display and print.  Many
    editors have features that help enforce this. *)

(* ###################################################################### *)
(** * Proof by Induction *)

(** We proved in the last chapter that [0] is a neutral element
    for [+] on the left using a simple argument.  The fact that it is
    also a neutral element on the _right_... *)

Theorem plus_0_r_firsttry : forall n:nat,
  n + 0 = n.

(** ... cannot be proved in the same simple way.  Just applying
  [reflexivity] doesn't work: the [n] in [n + 0] is an arbitrary
  unknown number, so the [match] in the definition of [+] can't be
  simplified.  *)

Proof.
  intros n.
  simpl. (* Does nothing! *)
Abort.

(** And reasoning by cases using [destruct n] doesn't get us much
   further: the branch of the case analysis where we assume [n = 0]
   goes through, but in the branch where [n = S n'] for some [n'] we
   get stuck in exactly the same way.  We could use [destruct n'] to
   get one step further, but since [n] can be arbitrarily large, if we
   try to keep on like this we'll never be done. *)

Theorem plus_0_r_secondtry : forall n:nat,
  n + 0 = n.
Proof.
  intros n. destruct n as [| n'].
  Case "n = 0".
    reflexivity. (* so far so good... *)
  Case "n = S n'".
    simpl.       (* ...but here we are stuck again *)
Abort.

(** To prove such facts -- indeed, to prove most interesting
    facts about numbers, lists, and other inductively defined sets --
    we need a more powerful reasoning principle: _induction_.

    Recall (from high school) the principle of induction over natural
    numbers: If [P(n)] is some proposition involving a natural number
    [n] and we want to show that P holds for _all_ numbers [n], we can
    reason like this:
         - show that [P(O)] holds;
         - show that, for any [n'], if [P(n')] holds, then so does
           [P(S n')];
         - conclude that [P(n)] holds for all [n].

    In Coq, the steps are the same but the order is backwards: we
    begin with the goal of proving [P(n)] for all [n] and break it
    down (by applying the [induction] tactic) into two separate
    subgoals: first showing [P(O)] and then showing [P(n') -> P(S
    n')].  Here's how this works for the theorem we are trying to
    prove at the moment: *)

Theorem plus_0_r : forall n:nat, n + 0 = n.
Proof.
  intros n. induction n as [| n'].
  Case "n = 0".     reflexivity.
  Case "n = S n'".  simpl. rewrite -> IHn'. reflexivity.  Qed.

(** Like [destruct], the [induction] tactic takes an [as...]
    clause that specifies the names of the variables to be introduced
    in the subgoals.  In the first branch, [n] is replaced by [0] and
    the goal becomes [0 + 0 = 0], which follows by simplification.  In
    the second, [n] is replaced by [S n'] and the assumption [n' + 0 =
    n'] is added to the context (with the name [IHn'], i.e., the
    Induction Hypothesis for [n']).  The goal in this case becomes [(S
    n') + 0 = S n'], which simplifies to [S (n' + 0) = S n'], which in
    turn follows from the induction hypothesis. *)

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

(** **** Exercise: 2 stars (basic_induction) *)

(** Prove the following lemmas using induction. You might need
    previously proven results. *)

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

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

Theorem plus_comm : forall n m : nat,
  n + m = m + n.
Proof.
  intros n m.
  induction n as [|n'].
  Case "n = 0".
  simpl. rewrite -> plus_0_r. reflexivity.
  Case "n = S n'".
  simpl. rewrite -> IHn'. rewrite -> plus_n_Sm.
  reflexivity. Qed.

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

(** **** Exercise: 2 stars (double_plus) *)

(** Consider the following function, which doubles its argument: *)

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

(** Use induction to prove this simple fact about [double]: *)

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

(** **** Exercise: 1 star (destruct_induction) *)
(** Briefly explain the difference between the tactics
    [destruct] and [induction].

(* destruct performs case analysis, where as induction also provides us with
   an induction hypothesis that we can use for rewriting.*)

*)
(** [] *)

(* ###################################################################### *)
(** * Proofs Within Proofs *)

(** In Coq, as in informal mathematics, large proofs are very
    often broken into a sequence of theorems, with later proofs
    referring to earlier theorems.  Occasionally, however, a proof
    will need some miscellaneous fact that is too trivial (and of too
    little general interest) to bother giving it its own top-level
    name.  In such cases, it is convenient to be able to simply state
    and prove the needed "sub-theorem" right at the point where it is
    used.  The [assert] tactic allows us to do this.  For example, our
    earlier proof of the [mult_0_plus] theorem referred to a previous
    theorem named [plus_O_n].  We can also use [assert] to state and
    prove [plus_O_n] in-line: *)

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

(** The [assert] tactic introduces two sub-goals.  The first is
    the assertion itself; by prefixing it with [H:] we name the
    assertion [H].  (Note that we could also name the assertion with
    [as] just as we did above with [destruct] and [induction], i.e.,
    [assert (0 + n = n) as H].  Also note that we mark the proof of
    this assertion with a [Case], both for readability and so that,
    when using Coq interactively, we can see when we're finished
    proving the assertion by observing when the ["Proof of assertion"]
    string disappears from the context.)  The second goal is the same
    as the one at the point where we invoke [assert], except that, in
    the context, we have the assumption [H] that [0 + n = n].  That
    is, [assert] generates one subgoal where we must prove the
    asserted fact and a second subgoal where we can use the asserted
    fact to make progress on whatever we were trying to prove in the
    first place. *)

(** Actually, [assert] will turn out to be handy in many sorts of
    situations.  For example, suppose we want to prove that [(n + m)
    + (p + q) = (m + n) + (p + q)]. The only difference between the
    two sides of the [=] is that the arguments [m] and [n] to the
    first inner [+] are swapped, so it seems we should be able to
    use the commutativity of addition ([plus_comm]) to rewrite one
    into the other.  However, the [rewrite] tactic is a little stupid
    about _where_ it applies the rewrite.  There are three uses of
    [+] here, and it turns out that doing [rewrite -> plus_comm]
    will affect only the _outer_ one. *)

Theorem plus_rearrange_firsttry : forall n m p q : nat,
  (n + m) + (p + q) = (m + n) + (p + q).
Proof.
  intros n m p q.
  (* We just need to swap (n + m) for (m + n)...
     it seems like plus_comm should do the trick! *)
  rewrite -> plus_comm.
  (* Doesn't work...Coq rewrote the wrong plus! *)
Abort.

(** To get [plus_comm] to apply at the point where we want it, we can
    introduce a local lemma stating that [n + m = m + n] (for
    the particular [m] and [n] that we are talking about here), prove
    this lemma using [plus_comm], and then use this lemma to do the
    desired rewrite. *)

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).
    Case "Proof of assertion".
    rewrite -> plus_comm. reflexivity.
  rewrite -> H. reflexivity.  Qed.

(** **** Exercise: 4 stars (mult_comm) *)
(** Use [assert] to help prove this theorem.  You shouldn't need to
    use induction. *)

Theorem plus_swap : forall n m p : nat,
  n + (m + p) = m + (n + p).
Proof.
  intros n m p.
  assert(H : m + (n + p) = (m + n) + p).
    Case "Assertion".
    rewrite -> plus_assoc. reflexivity.
  rewrite -> H. rewrite -> plus_assoc.
  assert(H2 : n + m = m + n). rewrite -> plus_comm. reflexivity.
  rewrite -> H2. reflexivity. Qed.

(** Now prove commutativity of multiplication.  (You will probably
    need to define and prove a separate subsidiary theorem to be used
    in the proof of this one.)  You may find that [plus_swap] comes in
    handy. *)

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

Lemma mult_comm_helper : forall m n : nat, m * S n = m + m * n.
Proof.
  intros m n.
  induction m as [| m'].
  Case "m = 0". reflexivity.
  Case "m = S m'".
  simpl. rewrite -> IHm'.
  rewrite -> plus_swap. reflexivity.
  Qed.

Theorem mult_comm : forall m n : nat,
 m * n = n * m.
Proof.
  intros m n.
  induction m as [ | m'].
  Case "m = 0". simpl. rewrite -> multZero. reflexivity.
  Case "m = S m'". simpl.
  rewrite -> mult_comm_helper. rewrite -> IHm'.
  reflexivity.
  Qed.

(** **** Exercise: 2 stars, optional (evenb_n__oddb_Sn) *)
(** Prove the following simple fact: *)
(*TODO: discuss this in class*)
Theorem evenb_n_oddb_Sn : forall n : nat,
  evenb n = negb (evenb (S n)).
Proof.
  intros n.
  induction n as [|n'].
  Case "n = 0". reflexivity.
  Case "n = S n'".
  assert(H:evenb(S(S(n'))) = evenb n'). reflexivity.
  rewrite -> H.  rewrite -> IHn'.
  assert(H2: forall x, negb(negb(x)) = x).
  intros x. destruct x as []. reflexivity. reflexivity.
  rewrite -> H2. reflexivity.
  Qed.

(* ###################################################################### *)
(** * More Exercises *)

(** **** Exercise: 3 stars, optional (more_exercises) *)
(** Take a piece of paper.  For each of the following theorems, first
    _think_ about whether (a) it can be proved using only
    simplification and rewriting, (b) it also requires case
    analysis ([destruct]), or (c) it also requires induction.  Write
    down your prediction.  Then fill in the proof.  (There is no need
    to turn in your piece of paper; this is just to encourage you to
    reflect before hacking!) *)

Theorem ble_nat_refl : forall n:nat,
  true = ble_nat n n.
Proof.
  intros n.
  induction n as [|n']. 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 andb_false_r : forall b : bool,
  andb b false = false.
Proof.
  intros b.
  destruct b as [|b']. reflexivity.
  reflexivity. Qed.

Theorem plus_ble_compat_l : forall n m p : nat,
  ble_nat n m = true -> ble_nat (p + n) (p + m) = true.
Proof.
  intros n m p H.
  induction p as [|p'].
  Case "p = 0". simpl. rewrite -> H. reflexivity.
  Case "p = S p'".
  simpl. rewrite -> IHp'. reflexivity.
  Qed.

Theorem S_nbeq_0 : forall n:nat,
  beq_nat (S n) 0 = false.
Proof.
  intros n.
  simpl. reflexivity. Qed.

Theorem mult_1_l : forall n:nat, 1 * n = n.
Proof.
  intros n. simpl. rewrite -> plus_0_r.
  reflexivity. Qed.

Theorem all3_spec : forall b c : bool,
    orb
      (andb b c)
      (orb (negb b)
               (negb c))
  = true.
Proof.
  intros b c.
  destruct b as [|b'].
    destruct c as [|c'].
    simpl. reflexivity.
    simpl. reflexivity.
    simpl. reflexivity.
  Qed.

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'].
  simpl. reflexivity.
  simpl. rewrite -> IHn'. rewrite -> plus_assoc.
  reflexivity.
  Qed.

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

(** **** Exercise: 2 stars, optional (beq_nat_refl) *)
(** Prove the following theorem.  Putting [true] on the left-hand side
of the equality may seem odd, but this is how the theorem is stated in
the standard library, so we follow suit.  Since rewriting
works equally well in either direction, we will have no
problem using the theorem no matter which way we state it. *)

Theorem beq_nat_refl : forall n : nat,
  true = beq_nat n n.
Proof.
  intros n.
  induction n as [|n']. reflexivity.
  simpl. rewrite -> IHn'. reflexivity.
  Qed.

(** **** Exercise: 2 stars, optional (plus_swap') *)
(** The [replace] tactic allows you to specify a particular subterm to
   rewrite and what you want it rewritten to.  More precisely,
   [replace (t) with (u)] replaces (all copies of) expression [t] in
   the goal by expression [u], and generates [t = u] as an additional
   subgoal. This is often useful when a plain [rewrite] acts on the wrong
   part of the goal.

   Use the [replace] tactic to do a proof of [plus_swap'], just like
   [plus_swap] but without needing [assert (n + m = m + n)].
*)

Theorem plus_swap' : forall n m p : nat,
  n + (m + p) = m + (n + p).
Proof.
  intros n m p.
  replace (m + (n + p)) with ((m + n) + p).
  rewrite -> plus_assoc.
  replace (n+m) with (m+n). reflexivity.
  rewrite -> plus_comm. reflexivity.
  rewrite -> plus_assoc. reflexivity.
  Qed.

(** **** Exercise: 3 stars (binary_commute) *)
(** Recall the [increment] and [binary-to-unary] functions that you
    wrote for the [binary] exercise in the [Basics] chapter.  Prove
    that these functions commute -- that is, incrementing a binary
    number and then converting it to unary yields the same result as
    first converting it to unary and then incrementing.

    (Before you start working on this exercise, please copy the
    definitions from your solution to the [binary] exercise here so
    that this file can be graded on its own.  If you find yourself
    wanting to change your original definitions to make the property
    easier to prove, feel free to do so.) *)

Inductive bin : Type :=
  | BinO : bin
  | Odd : bin -> bin
  | Even : bin -> bin.
(** [] *)

Fixpoint inc (n : bin) : bin :=
  match n with
      |BinO => Odd BinO
      |Even n => Odd n
      |Odd n => Even(inc n)
  end.

Fixpoint binToUnary(n : bin) : nat :=
  match n with
      |BinO => 0
      |Even n => 2 * (binToUnary n)
      |Odd n => 1 + 2 * binToUnary n
  end.
Lemma succXPlusOne : forall x : nat, S x = x + 1.
Proof.
  intros x. rewrite -> plus_comm. simpl.
  reflexivity.
  Qed.

(*TODO: discuss this in class*)
Theorem BinToUnaryCorrect : forall n : bin, binToUnary(inc n) = binToUnary(n) + 1.
Proof.
  intros n.
  induction n as [|n' | n'].
  Case "n = 0".
  simpl. reflexivity.
  Case "n = Even n'".
  simpl. rewrite -> plus_n_Sm. rewrite -> plus_0_r. rewrite -> plus_0_r.
  rewrite -> IHn'. rewrite -> plus_swap. rewrite -> plus_assoc. rewrite -> plus_assoc.
  assert(H: forall x, x + 1 + 1 = x + 2).
  intros x. rewrite -> plus_comm. rewrite -> plus_swap. simpl. reflexivity.
  rewrite -> H. reflexivity.
  simpl. rewrite -> plus_n_Sm. rewrite -> plus_0_r.
  rewrite -> succXPlusOne. rewrite -> plus_assoc. reflexivity.
  Qed.

(** **** Exercise: 5 stars, advanced (binary_inverse) *)
(** This exercise is a continuation of the previous exercise about
    binary numbers.  You will need your definitions and theorems from
    the previous exercise to complete this one.

    (a) First, write a function to convert natural numbers to binary
        numbers.  Then prove that starting with any natural number,
        converting to binary, then converting back yields the same
        natural number you started with.

    (b) You might naturally think that we should also prove the
        opposite direction: that starting with a binary number,
        converting to a natural, and then back to binary yields the
        same number we started with.  However, it is not true!
        Explain what the problem is.

    (c) Define a function [normalize] from binary numbers to binary
        numbers such that for any binary number b, converting to a
        natural and then back to binary yields [(normalize b)].  Prove
        it.

    Again, feel free to change your earlier definitions if this helps
    here.
*)

Fixpoint natToBin(n : nat) : bin :=
match n with
    |O => BinO
    |S n' => inc(natToBin n')
end.

Theorem natToBinCorrect : forall n : nat, binToUnary(natToBin n) = n.
Proof.
  intros n.
  induction n as [|n'].
  Case "n = 0". reflexivity.
  Case "n = S n'". simpl. rewrite -> BinToUnaryCorrect. rewrite -> IHn'. rewrite -> plus_comm.
  reflexivity.
  Qed.

Fixpoint normalize (b : bin) : bin :=
match b with
    |BinO => BinO
    |Even(b') => match normalize b' with
                     |BinO => BinO
                     |n => Even(Even n)
                 end
    |Odd(b') => Odd(normalize b')
end.

Theorem L : forall n, natToBin(n + n) = normalize(Even (natToBin n)).
Proof.
  intros. induction n as [|n'].
  simpl. reflexivity.
  simpl.  destruct (normalize(inc(natToBin n'))).

Theorem binToNatCorrect : forall b : bin, natToBin(binToUnary b) = normalize b.
Proof.
  intros b.
  induction b as [|n|n].
  reflexivity.
  Case "b = Odd n". simpl. rewrite -> plus_0_r.
  rewrite -> L. simpl. rewrite -> IHn. reflexivity.
  Case "b = Odd n". simpl. rewrite -> plus_0_r.
  rewrite -> L. rewrite -> IHn. reflexivity.
  Qed.

(*
Theorem NPlusNEven : forall n, natToBin(n + n) = Even (natToBin n).
Proof.
  intros. induction n as [|n'].
  Admitted.

Theorem binToNatCorrect : forall b : bin, natToBin(binToUnary b) = b.
Proof.
  intros b.
  induction b as [|n|n].
  reflexivity.
  Case "b = Odd n". simpl. rewrite -> plus_0_r.
  rewrite -> NPlusNEven. simpl. rewrite -> IHn. reflexivity.
  Case "b = Odd n". simpl. rewrite -> plus_0_r.
  rewrite -> NPlusNEven. rewrite -> IHn. reflexivity.
  Qed.*)

(* ###################################################################### *)
(** * Advanced Material *)

(** ** Formal vs. Informal Proof *)

(** "Informal proofs are algorithms; formal proofs are code." *)

(** The question of what, exactly, constitutes a "proof" of a
    mathematical claim has challenged philosophers for millenia.  A
    rough and ready definition, though, could be this: a proof of a
    mathematical proposition [P] is a written (or spoken) text that
    instills in the reader or hearer the certainty that [P] is true.
    That is, a proof is an act of communication.

    Now, acts of communication may involve different sorts of readers.
    On one hand, the "reader" can be a program like Coq, in which case
    the "belief" that is instilled is a simple mechanical check that
    [P] can be derived from a certain set of formal logical rules, and
    the proof is a recipe that guides the program in performing this
    check.  Such recipes are _formal_ proofs.

    Alternatively, the reader can be a human being, in which case the
    proof will be written in English or some other natural language,
    thus necessarily _informal_.  Here, the criteria for success are
    less clearly specified.  A "good" proof is one that makes the
    reader believe [P].  But the same proof may be read by many
    different readers, some of whom may be convinced by a particular
    way of phrasing the argument, while others may not be.  One reader
    may be particularly pedantic, inexperienced, or just plain
    thick-headed; the only way to convince them will be to make the
    argument in painstaking detail.  But another reader, more familiar
    in the area, may find all this detail so overwhelming that they
    lose the overall thread.  All they want is to be told the main
    ideas, because it is easier to fill in the details for themselves.
    Ultimately, there is no universal standard, because there is no
    single way of writing an informal proof that is guaranteed to
    convince every conceivable reader.  In practice, however,
    mathematicians have developed a rich set of conventions and idioms
    for writing about complex mathematical objects that, within a
    certain community, make communication fairly reliable.  The
    conventions of this stylized form of communication give a fairly
    clear standard for judging proofs good or bad.

    Because we are using Coq in this course, we will be working
    heavily with formal proofs.  But this doesn't mean we can ignore
    the informal ones!  Formal proofs are useful in many ways, but
    they are _not_ very efficient ways of communicating ideas between
    human beings. *)

(** For example, here is a proof that addition is associative: *)

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

(** Coq is perfectly happy with this as a proof.  For a human,
    however, it is difficult to make much sense of it.  If you're used
    to Coq you can probably step through the tactics one after the
    other in your mind and imagine the state of the context and goal
    stack at each point, but if the proof were even a little bit more
    complicated this would be next to impossible.  Instead, a
    mathematician might write it something like this: *)
(** - _Theorem_: For any [n], [m] and [p],
      n + (m + p) = (n + m) + p.
    _Proof_: By induction on [n].

    - First, suppose [n = 0].  We must show
        0 + (m + p) = (0 + m) + p.
      This follows directly from the definition of [+].

    - Next, suppose [n = S n'], where
        n' + (m + p) = (n' + m) + p.
      We must show
        (S n') + (m + p) = ((S n') + m) + p.
      By the definition of [+], this follows from
        S (n' + (m + p)) = S ((n' + m) + p),
      which is immediate from the induction hypothesis. [] *)

(** The overall form of the proof is basically similar.  This is
    no accident: Coq has been designed so that its [induction] tactic
    generates the same sub-goals, in the same order, as the bullet
    points that a mathematician would write.  But there are
    significant differences of detail: the formal proof is much more
    explicit in some ways (e.g., the use of [reflexivity]) but much
    less explicit in others (in particular, the "proof state" at any
    given point in the Coq proof is completely implicit, whereas the
    informal proof reminds the reader several times where things
    stand). *)

(** Here is a formal proof that shows the structure more
    clearly: *)

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

(** **** Exercise: 2 stars, advanced (plus_comm_informal) *)
(** Translate your solution for [plus_comm] into an informal proof. *)

(** Theorem: Addition is commutative.

    Proof: Proof by induction on n:
    Case (n = 0): We have "0 + m = m + 0", which simplifies to "m = m"
    Case (n = n' + 1): We have "(n' + 1) + m = m + (n' + 1)"
    By the definition of plus, we have "S(n' + m) = m + S n'"
    By the induction hypothesis, we have "S(m + n') = m + S n'"
    By Theorem plus_n_Sm, we have "m + S n' = m + S n'"

[]
*)

(** **** Exercise: 2 stars, optional (beq_nat_refl_informal) *)
(** Write an informal proof of the following theorem, using the
    informal proof of [plus_assoc] as a model.  Don't just
    paraphrase the Coq tactics into English!

    Theorem: [true = beq_nat n n] for any [n].

    Proof: (* FILL IN HERE *)
[]
 *)

(* $Date: 2013-07-17 16:19:11 -0400 (Wed, 17 Jul 2013) $ *)


(*|
########################################################
How to import the library ``Coq.Arith.PeanoNat`` in Coq?
########################################################

:Link: https://stackoverflow.com/q/36621752
|*)

(*|
Question
********

I need to use the part of the standard library called
``Coq.Arith.PeanoNat``
(https://coq.inria.fr/library/Coq.Arith.PeanoNat.html).

I've tried either importing the entire Arith library or just this
module, but I can't use it either way.

Every other library I've tried works just fine. When I do ``Require
Import Bool.`` I compile and I can use it correctly. Upon ``Print
Bool.`` I can take a look at all the functions inside in the next
format:

.. code-block::

    Module
    Bool
    := Struct
    Definition...
    .
    .
    .
    End

When I do either ``Require Import Arith.PeanoNat.`` or ``Require
Import Arith.`` I get this as immediate output:

.. code-block::

    [Loading ML file z_syntax_plugin.cmxs ... done]
    [Loading ML file quote_plugin.cmxs ... done]
    [Loading ML file newring_plugin.cmxs ... done]
    <W> Grammar extension: in [tactic:simple_tactic], some rule has been masked
    <W> Grammar extension: in [tactic:simple_tactic], some rule has been masked
    <W> Grammar extension: in [tactic:simple_tactic], some rule has been masked
    <W> Grammar extension: in [tactic:simple_tactic], some rule has been masked
    <W> Grammar extension: in [tactic:simple_tactic], some rule has been masked

When I ask Coq ``Print Arith.PeanoNat`` it outputs: ``Module Arith :=
Struct End``, it seems to be empty. When I try to use anything from
the library, for example ``le_le`` under boolean comparisons, I get
the standard ``Error: leb_le not a defined object.`` I have updated
Coq and the libraries, and I have no idea of what might be going on
here. I'd appreciate your input in fixing this library problem.
|*)

(*|
Answer
******

If I am not mistaken, ``Require`` is the keyword to load a file.
``Import`` has to do with managing name spaces. Often they are used
together, as in ``Require Import PeanoNat.``, but they are really
doing two different things.

When coq files (``DirName/FileName.vo``) are loaded with ``Require``,
it is as if the contents of ``FileName.vo`` is wrapped in ``Module
DirName.FileName ... End.`` Everyting defined in the file is then
accessed with ``DirName.FileName.Name``.

The file can itself have modules ``M`` inside of it, and to get to
``M``'s contents, one has to type
``DirName.FileName.ModuleName.Name1`` etc.

``Import`` is used to get all the definitions up to the top level. By
doing ``Import DirName.FileName.ModuleName`` the module ``Name1`` is
now imported to the top level, and can be referenced without the long
path.

In your example above, the file ``Arith/PeanoNat.vo`` defines the
module ``Nat``. Actually, that is all it defines. So if you do
``Require Import Arith.PeanoNat`` you get ``PeanoNat.Nat`` at the top
level. And then ``Import PeanoNat.Nat`` will bring ``Nat`` to the top
level. Note that you can't do ``Require Import PeanoNat.Nat`` because
it is no ``.vo`` file.

Coq can sometimes find a ``.vo`` file without you having to specify
the whole path, so you can also do ``Require Import PeanoNat.`` and
coq will find the file. If you wonder where it found it, do ``Locate
PeanoNat``.
|*)

Require Import PeanoNat.
Locate PeanoNat. (* .unfold *)

(*|
Another ``Nat`` is also available from another place than
``PeanoNat``.
|*)

Reset Initial. (* .none *)
Require Import Nat.
Locate Nat. (* .unfold *)

(*|
So, you don't ``Import`` a library, you ``Require`` it. You use
``Import`` to not have to use the full path name. I hope this helps
you debug what is happening.
|*)


(** **** Exercise: 3 stars, standard (binary)

 Après la représentation unaire des nombres naturels, nous proposons
 une représentation Binaire plus efficace en traitant un nombre Binaire
 comme une séquence de constructeurs [zero] et [un] (représentant 0 et 1),
 terminée par un [zeroFinal] ou un [unFinal]. En comparaison, dans la
 représentation unaire, un nombre est une séquence de [S] terminée par un [O].

        décimal             binaire                         unaire
           0                   0                              O
           1                   1                            S O
           2                (0 1)                        S (S O)
           3                (1 1)                     S (S (S O))
           4              0 (0 1)                  S (S (S (S O)))
           5              1 (0 1)               S (S (S (S (S O))))
           6              0 (1 1)            S (S (S (S (S (S O)))))
           7              1 (1 1)         S (S (S (S (S (S (S O))))))
           8           0 (0 (0 1))     S (S (S (S (S (S (S (S O)))))))

  Notez que le bit d'ordre inférieur est à gauche et le bit d'ordre supérieur
  est à droite -- à l'opposé de la façon dont les nombres binaires
  sont habituellement écrits. Ce choix facilite leur manipulation.

  Enfin, il peut exister plusieurs représentations binaires d'un entier naturel :
  il suffit d'ajouter des zéros à droite.
**)

(* Préambule *)
(* Quelques lemmes et définitions utiles, certaines donnant lieu à des tactiques standards.
 * Ces tactiques standards traitent de l'absurdité et de l'égalité. Elle sont à connaître :
 * - exfalso,
 * - f_equal
 * - discriminate.
 * On s'aperçoit que toutes ces tactiques peuvent s'exprimer en utilisant la tactique primitive
 * case, et quelques lemmes pratiques (appliqués avec apply ou refine).
 *)

(* Arguments implicites.
 * Il est possible de déclarer des paramètres entre accolades au lieu de parenthèses.
 * Ces paramètres donnent des arguments implicites : Coq les devine par lui-même.
 * Si on veut utiliser tous les arguments d'une fonction f, écrire l'appel ainsi :
 * - (@f args).
 *)

(* Lors de définitions par cas, il arrive que certains cas soient absurdes.
   On utilise alors la fonction casImpossible. *)
Definition casImpossible{T : Type}(H : False) : T.
  case H. (* voir le principe récursif False_rect. *)
Defined.

Print False_ind.
Print False_rect.

Print casImpossible.

(* alternative utilisant exfalso et False_rect. *)
Definition casImpossible'{T : Type}(H : False) : T.
    exfalso.
    exact H.
Defined.

Print casImpossible'.

(* Cette notation permet de masquer la preuve de l'absurdité (du Faux). *)
Notation "'Impossible'" := (casImpossible _) : type_scope.

(* Très souvent, l'absurdité vient d'une égalité impossible
 * entre deux termes de structures différentes. *)

Ltac egaliteImpossible eg := (apply casImpossible; discriminate eg).

(* discriminate est une tactique élaborée. Elle utilise la préservation
 * de l'égalité par les fonctions pour déduire le Faux, à partir d'une égalité impossible.
 * La préservation de l'égalité est exploitée par la tactique f_equal.
 *)

Lemma preservationFonctionnelleEgalite :
  forall {A B : Type}{F : A -> B},
  forall x y, x = y -> F x = F y.
Proof.
  intros A B F x y eg.
  case eg.
  reflexivity.
Qed.

(* Plutôt que "case eg", on peut utiliser "rewrite eg".
 *  rewrite est une tactique plus élaborée fondée sur l'égalité et sa décomposition via case.
 *)
Lemma preservationFonctionnelleEgalite' :
  forall {A B : Type}{F : A -> B},
  forall x y, x = y -> F x = F y.
Proof.
  intros A B F x y eg.
  (* rewrite eg. (* équivalent à case (eq_sym eg)
                    (où eq_sym est le lemme de symmétrie / égalité *)
   *)
  rewrite <- eg. (* équivalent à case eg *)
  reflexivity.
Qed.

(* Tactique f_equal := apply preservationFonctionnelleEgalite *)

Ltac egaliteFctn := apply preservationFonctionnelleEgalite.

(* Vers la discrimination :
 * si x = y, (P x) et non (P y), alors on a une contradiction.
 * On utilise la préservation de l'égalité par un prédicat (une fonction vers Prop).
 *)

Lemma discrimination :
  forall {A : Type},
  forall x y,
    x = y -> (exists (P : A -> Prop), (P x) /\ (P y -> False)) -> False.
Proof.
  intros A x y eg.
  case eg.
  intro H.
  case H as [P [Px abs]].
  apply (abs Px).
Qed.

(* Tactique pour discriminer une égalité fausse :
 * - appliquer discrimination
 * - définir (P n) par : si n vaut x alors True sinon False.
 * Le test relativement à x se fait par filtrage, sans utiliser l'égalité.
 * eg : x = y
 * discriminant :=
 * (fun n => match n with (filtrage étendu)
           | x => True (x à remplacer par la valeur)
           | _ => False
           end)
 *)
Ltac discriminer eg discriminant :=
 apply (discrimination _ _ eg);
 simple refine (ex_intro _ _ _);
 [ exact discriminant
 | simpl; tauto].

Example disc_5_6 : 5 = 6 -> False.
intro eg.
discriminer eg (fun n => match n with
                         | 5 => True
                         | _ => False
                         end).
Qed.

Print disc_5_6. (* Noter que le filtrage est plus élémentaire que dans l'écriture au-dessus.
                 * Il décrit tous les sous-termes de 5.
                 *)

(* discriminate produit automatiquement le discriminant. *)

Example disc_5_6' : 5 = 6 -> False.
intro eg.
discriminate eg.
Qed.

Print disc_5_6'. (* discriminate a effectivement produit automatiquement le discriminant. *)

(* Fin du préambule *)

(* Définition permettant d'obtenir une correspondance bi-univoque *)
Inductive SorteBinaire : Type
  := T1 | N.

(* N ::= 0 | T1 (N = forme normale)
   T1 ::= 1 | 0.T1 | 1 T1 (T1 = se termine par un 1)
 *)
Inductive Binaire : SorteBinaire -> Type :=
  | zeroFinal : Binaire N
  | unFinal : Binaire T1
  | double : Binaire T1 -> Binaire T1
  | successeurDouble : Binaire T1 -> Binaire T1
  | formeNormale : Binaire T1 -> Binaire N.

(** nat comme Binaire forment des algèbres initiales.
  * - nat : signature Nat := (0 : nat), (S : nat -> nat)
  * - Binaire : signature Bin avec deux sortes N et T1
  * - cinq opérations := (OF : Binaire N), (1F : Binaire T1),
  *    (double : Binaire T1 -> Binaire T1), (successeurDouble: Binaire T1 -> Binaire T1),
  *    (fn : Binaire T1 -> Binaire N)
  *
  * Propriété importante des algèbres initiales :
  - il existe un unique morphisme d'une algèbre initiale vers une algèbre sur la même signature.
  *
  * Une algèbre est donnée par des ensembles (un par sorte) et des fonctions sur ces ensembles
  * (une par opération de la sorte, en respectant le type).
  *
  * L'algèbre initiale est formée des termes, soit les arbres formés à partir des opérations,
  * en respectant le typage.
  *
  * Signature Bin
  * On interprète N par nat et T1 par nat* (nat - 0). Comme nat* est isomorphe à nat,
  * on simplifie : on interprète T1 par nat.
  * (nat/N, nat/T1) est une algèbre sur Bin.
  * Signature Nat
  * Binaire N est une algèbre sur Nat, Binaire T1 est une algèbre sur Nat.
  *
  * La propriété d'initialité permet de relier nat et Binaire.
  *  - si (nat/N, nat/T1) est une algèbre sur Bin,
  *    alors il existe un unique morphisme BN := (BN N, BN T1)
  *    sur Bin de Binaire vers (nat/N, nat/T1).
  *  - si (Binaire s) est une algèbre sur Nat,
  *    alors il existe un unique morphisme (NB s) sur Nat de nat vers (Binaire s).
  *
  * Pour montrer qu'il s'agit d'isomorphismes, il suffit de montrer que
  * - chaque composante (BN s) est aussi un morphisme sur Nat de (Binaire s) vers nat/s,
  * - (NB N, NB T1) est aussi un morphisme sur Bin de (nat/N, nat/T1) vers Bin.
  * NB o BN est alors un morphisme sur Bin de Binaire vers Binaire :
  * par unicité, il est égal à l'identité.
  * De même (BN s) o (NB s) est un morphisme sur Nat de nat vers nat :
  * par unicité, il est égal à l'identité.
*)

Local Notation "'BO'" := zeroFinal : type_scope.
Local Notation "'I'" := (unFinal) : type_scope.
Local Notation "'O,' x" := (double x) (at level 30, right associativity) : type_scope.
Local Notation "'I,' x" := (successeurDouble x) (at level 30, right associativity) : type_scope.
Local Notation "'B' x" := (formeNormale x) (at level 30, right associativity) : type_scope.

Check (B O,I,O,I).
Check (O,I,O,I).
Check (BO).

(* On cherche à définir les opérations de la signature Bin dans (nat/N, nat/T1)
 * et celles de la signature Nat dans (Binaire s) (s : sorte).
 * Rappel
 * Comme il y a deux sortes, on associe deux ensembles, côté nat :
 * - sorte N : nat
 * - sorte T1 : nat pour représenter nat* (nat - 0) (0 pour représenter 1, 1 pour représenter 2, etc.)
 * Attention : bien penser au décalage dans nat/T1.
 *)

(* Cette fonction correspond à la notation nat/s, utilisée en commentaire. *)
Definition natBinaire(e : SorteBinaire) : Type := nat.

(* natBinaire comme algèbre sur B *)

Definition zeroFinalNat : natBinaire N := 0.

Definition unFinalNat : natBinaire T1 := 0. (* Rappel : décalage
                                             * car représentation de T1 par nat au lieu de nat* *)

(* Fonction qui à n associe (n + 1) * 2 - 1.
 *   (à cause du décalage)
 * Pour simplifier les calculs, il est préférable d'utiliser seulement
 * la fonction S (successeur).
 *)
Definition doubleNat : natBinaire T1 -> natBinaire T1. (* +1 -> * 2 -> -1 *)
  intro n.
  induction n as [ | n'].
  - exact 1.
  - exact (S (S IHn')).
Defined.

(* Fonction qui à n associe (n + 1) * 2.
 *   (à cause du décalage)
 * Pour simplifier les calculs, il est préférable d'utiliser seulement
 * la fonction S (successeur).
 *)
Definition successeurDoubleNat(n : natBinaire T1) : natBinaire T1. (* -> +1 -> *2  *)
  exact (S (doubleNat n)).
Defined.

Definition formeNormaleNat(n : natBinaire T1) : natBinaire N := S n.  (* Rappel : décalage *)

(* (Binaire s) comme algèbre sur Nat *)

(* Interprétation de zéro dans (Binaire N) et (Binaire T1).
 * Prise en compte du décalge.
 *)
Definition zeroBinaire(s : SorteBinaire) : Binaire s.
  case s.
  - exact unFinal.
  - exact zeroFinal.
Defined.

(* interprétation de successeur dans (Binaire N) et (Binaire T1).
 * prise en compte du décalge.
 *)
Fixpoint successeurBinaire {e : SorteBinaire}(b : Binaire e) : Binaire e.
  case b as [ | | sb | sb | bn ].
  - exact (formeNormale (unFinal)).
  - exact (double unFinal).
  - exact (successeurDouble sb).
  - exact (double (successeurBinaire T1 sb)).
  - exact (formeNormale (successeurBinaire T1 bn)).
Defined.
(* Ou avec les notations :
  case b as [ | | sb | sb | bn].
  - exact (B I).
  - exact (O,I).
  - exact (I, sb).
  - exact (O, (successeurBin _ sb)).
  - exact (B (successeurBin _ bn)).
 *)

(** Conversion de [natBinaire] vers [Binaire] *)
Fixpoint valeurNatEnBinaire(s : SorteBinaire)(n : natBinaire s) : Binaire s.
  case n as [ | n'].
  - exact (zeroBinaire s).
  - exact (successeurBinaire (valeurNatEnBinaire _ n')).
Defined.

(* La conversion est un morphisme d'algèbre sur Nat.
 * Par définition - simple vérification.
 *)
Lemma morphismeNat_valeurNatEnBinaire :
  forall s,
  valeurNatEnBinaire s 0 = zeroBinaire s
  /\
  forall n,
    valeurNatEnBinaire s (S n) = successeurBinaire (valeurNatEnBinaire s n).
Proof.
  split; reflexivity.
Qed.

(* La conversion valeurNatEnBinaire est aussi un morphisme d'algèbre sur Bin.
 * Cinq lemmes, un par opération de la signature.
 *)
Lemma morphismeZeroFinal_valeurNatEnBinaire :
  valeurNatEnBinaire _ zeroFinalNat  = zeroFinal.
Proof.
  reflexivity.
Qed.

Lemma morphismeUnFinal_valeurNatEnBinaire :
  valeurNatEnBinaire _ unFinalNat  = unFinal.
Proof.
  reflexivity.
Qed.

Lemma morphismeDouble_valeurNatEnBinaire :
  forall n : natBinaire T1,
    valeurNatEnBinaire _ (doubleNat n)  = double (valeurNatEnBinaire _ n).
Proof.
  induction n.
  - simpl. reflexivity.
  - simpl. rewrite IHn. simpl. reflexivity.
Qed.

Lemma morphismeSuccesseurDouble_valeurNatEnBinaire :
  forall n : natBinaire T1,
    valeurNatEnBinaire _ (successeurDoubleNat n)  = successeurDouble (valeurNatEnBinaire _ n).
Proof.
  intro n. simpl. rewrite morphismeDouble_valeurNatEnBinaire.
  reflexivity.
Qed.

Lemma morphismeFormeNormale_valeurNatEnBinaire :
  forall n : natBinaire T1,
    valeurNatEnBinaire _ (formeNormaleNat n)  = formeNormale (valeurNatEnBinaire _ n).
Proof.
  induction n.
  - simpl. reflexivity.
  - simpl. simpl in IHn. rewrite IHn.
    simpl. reflexivity.
Qed.

(** Conversion de [Binaire] vers [natBinaire]
 *)

Fixpoint valeurBinaireEnNat{s : SorteBinaire}(b : Binaire s) : natBinaire s.
  case b as [ | | b' | b' | b'].
  - exact zeroFinalNat.
  - exact unFinalNat.
  - exact (doubleNat (valeurBinaireEnNat _ b')).
  - exact (successeurDoubleNat (valeurBinaireEnNat _ b')).
  - exact (formeNormaleNat (valeurBinaireEnNat _ b')).
Defined.

Compute valeurBinaireEnNat (B O,I,O,I).
(* Le paramètre s entre accolades est implicite.
   Il est déterminé automatiquement à partir du type de b. *)

(* La conversion est un morphisme d'algèbre sur Bin.
 * Par définition - simple vérification
 *)
Lemma morphismeBin_valeurBinaireEnNat :
  valeurBinaireEnNat zeroFinal  = zeroFinalNat
  /\
  valeurBinaireEnNat unFinal  = unFinalNat
  /\
  (forall b : Binaire T1,
    valeurBinaireEnNat (double b) = doubleNat (valeurBinaireEnNat b))
  /\
  (forall b : Binaire T1,
    valeurBinaireEnNat (successeurDouble b) = successeurDoubleNat (valeurBinaireEnNat b))
  /\
  forall b : Binaire T1,
    valeurBinaireEnNat (formeNormale b) = formeNormaleNat (valeurBinaireEnNat b).
Proof.
  repeat split; reflexivity.
Qed.

(* Chaque composante de la conversion est aussi un morphisme d'algèbre sur Nat.
 * Deux lemmes, un par opération.
 *)
Lemma morphismeZero_valeurBinaireEnNat :
  forall s,
      valeurBinaireEnNat (zeroBinaire s)  = 0.
Proof.
  intro s. case s; reflexivity.
Qed.

Lemma morphismeSuccesseur_valeurBinaireEnNat :
  forall s, forall b : Binaire s,
      valeurBinaireEnNat (successeurBinaire b)  = S (valeurBinaireEnNat b).
Proof.
  induction b as [ | | b' | b' | b'].
  - reflexivity.
  - reflexivity.
  - simpl. reflexivity.
  - simpl. rewrite IHb'. reflexivity.
  - simpl. rewrite IHb'. reflexivity.
Qed.

(* Les isomorphismes *)

(** (valeurBinaireEnNat s) o (valeurNatEnBinaire s) : natBinaire s -> natBinaire s
 * est un morphisme d'algèbre sur N.
 * Par initialité, c'est l'identité.
 * Démonstration directe ci-dessous.
 *)
Proposition isomorphisme_natBinNat :
  forall s, forall n : natBinaire s, valeurBinaireEnNat (valeurNatEnBinaire s n) = n.
Proof.
  induction n.
  - simpl. rewrite morphismeZero_valeurBinaireEnNat. reflexivity.
  - simpl. rewrite morphismeSuccesseur_valeurBinaireEnNat. rewrite IHn. reflexivity.
Qed.

(** valeurNatEnBinaire o valeurBinaireEnNat : Binaire  -> Binaire
 * est un morphisme d'algèbre sur B.
 * Par initialité, c'est l'identité.
 * Démonstration directe ci-dessous.
 *)
Proposition isomorphisme_binNatBin :
  forall e, forall b : Binaire e,  (valeurNatEnBinaire e (valeurBinaireEnNat b)) = b.
Proof.
  induction b as [ | | b' | b' | b'].
  - simpl. reflexivity.
  - simpl. reflexivity.
  - simpl. rewrite morphismeDouble_valeurNatEnBinaire. rewrite IHb'. reflexivity.
  - simpl. rewrite morphismeDouble_valeurNatEnBinaire. rewrite IHb'. simpl. reflexivity.
  - simpl valeurBinaireEnNat. rewrite morphismeFormeNormale_valeurNatEnBinaire. rewrite IHb'. reflexivity.
Qed.

(* tests *)

Compute (valeurNatEnBinaire N 17).
Compute (valeurBinaireEnNat (B I,I,O,I)).
Compute (valeurBinaireEnNat (I,I,O,I)).
Compute (valeurNatEnBinaire N (valeurBinaireEnNat (B I,I,O,I))).

(* TODO - Quelques exemples à faire *)

(*
 * On montre que Binaire N est un ensemble quotient de SuiteBinaire (cf. le TP Binaire).
 * projection : SuiteBinaire -> Binaire N := forme normale
 * représentant : Binaire N -> SuiteBinaire := plongement
 *)

Inductive SuiteBinaire : Type :=
  | dernierZero : SuiteBinaire
  | dernierUn : SuiteBinaire
  | zero : forall n : SuiteBinaire, SuiteBinaire
  | un : forall n : SuiteBinaire, SuiteBinaire.

Definition representant : forall {s}, (Binaire s) -> SuiteBinaire.
  fix REC 2.
  intros s b.
  case b as [ | | sb | sb | bn].
  - exact dernierZero.
  - exact dernierUn.
  - exact (zero (REC _ sb)).
  - exact (un (REC _ sb)).
  - exact (REC _ bn).
Defined.

(* Pour faciliter l'inversion, on définit la version paramétrée de Bianire. *)
Inductive BinaireP(s : SorteBinaire) : Type :=
  | zeroFinalP : N = s -> BinaireP s
  | unFinalP : T1 = s -> BinaireP s
  | doubleP : T1 = s -> BinaireP T1 -> BinaireP s
  | successeurDoubleP : T1 = s -> BinaireP T1 -> BinaireP s
  | formeNormaleP : N = s -> BinaireP T1 -> BinaireP s.

(* On définit les morphismes entre les deux versions, indexée et paramétrée respectivement. *)
Definition binaireP :
  forall {s}, Binaire s -> BinaireP s.
  fix REC 2.
  intros s b.
  case b as [ | | sb | sb | bn].
  - exact (zeroFinalP N eq_refl).
  - exact (unFinalP T1 eq_refl).
  - exact (doubleP T1 eq_refl (REC _ sb)).
  - exact (successeurDoubleP T1 eq_refl (REC _ sb)).
  - exact (formeNormaleP N eq_refl (REC _ bn)).
Defined.

Print binaireP.

Definition binaireI :
  forall {s}, BinaireP s -> Binaire s.
  fix REC 2.
  intros s b.
  case b as [ eg | eg| eg sb | eg sb | eg bn]; case eg.
  - exact zeroFinal.
  - exact unFinal.
  - exact (double (REC _ sb)).
  - exact (successeurDouble (REC _ sb)).
  - exact (formeNormale (REC _ bn)).
Defined.

Print binaireI.

(* Ces morphismes sont des isomorphismes *)
Lemma isomorphisme_binaireIPI :
  forall s, forall b : Binaire s,
      binaireI (binaireP b) = b.
  (* TODO *)
  admit.
Admitted.

Lemma isomorphisme_binairePIP :
  forall s, forall b : BinaireP s,
      binaireP (binaireI b) = b.
  (* TODO *)
  admit.
Admitted.

(* La projection réalise le calcul de la fome normale, sans zéro inutile à droite.
 * Noter la conversion en BinaireP. Sans celle-ci, l'inversion échoue.
 *)
Definition projection : SuiteBinaire -> Binaire N.
  fix REC 1.
  intro b.
  case b as [ | | sb | sb].
  - exact BO.
  - exact (B I).
  - case (binaireP (REC sb)) as [ eg| eg | eg sx | eg sx | eg nx];
      try (egaliteImpossible eg).
    + exact BO.
    + pose (y := nx).
      case y as [ eg1| eg1 | eg1 sx1 | eg1 sx1 | eg1 nx1];
        try (egaliteImpossible eg1); exact (B O, (binaireI nx)).
  - case (binaireP (REC sb)) as [ eg| eg | eg sx | eg sx | eg nx];
      try (egaliteImpossible eg).
    + exact (B I).
    + pose (y := nx).
      case y as [ eg1| eg1 | eg1 sx1 | eg1 sx1 | eg1 nx1];
        try (egaliteImpossible eg1); exact (B I, (binaireI nx)).
Defined.

Print projection.

(* La fonction de normalisation est l'identité ou formeNormale, suivant la sorte. *)
Definition normalisation : forall {s}, Binaire s -> Binaire N.
  intro s.
  case s.
  - intro b.
    exact (formeNormale b).
  - intro b. exact b.
Defined.

Print normalisation.

(* Les deux propositions suivantes établissent la propriété fondamentale d'un ensemble quotient.
 * Le premier lemme utilise la version paramétrée pour permettre une inversion sans perte
 * d'informations.
 *)
Lemma quotient_BinaireP :
  forall e, forall b : BinaireP e,
    projection (representant (binaireI b)) = normalisation (binaireI b).
Proof.
  (* TODO *)
  admit.
Admitted.

Proposition quotient_Binaire :
  forall s, forall b : Binaire s,
    projection (representant b) = normalisation b.
  (* TODO *)
  admit.
Admitted.

Print quotient_Binaire.

(* On déduit la propriété souhaitée pour la sorte N. *)
Corollary quotient_BinaireN :
  forall b : Binaire N,
    projection (representant b) = b.
Proof.
  (* TODO *)
  admit.
Admitted.


(** * Preface *)

(* ################################################################# *)
(** * Welcome *)

(** This is the entry point in a series of electronic textbooks on
    various aspects of _Software Foundations_ -- the mathematical
    underpinnings of reliable software.  Topics in the series include
    basic concepts of logic, computer-assisted theorem proving, the
    Coq proof assistant, functional programming, operational
    semantics, logics for reasoning about programs, and static type
    systems.  The exposition is intended for a broad range of readers,
    from advanced undergraduates to PhD students and researchers.  No
    specific background in logic or programming languages is assumed,
    though a degree of mathematical maturity will be helpful.

    The principal novelty of the series is that it is one hundred
    percent formalized and machine-checked: each text is literally a
    script for Coq.  The books are intended to be read alongside (or
    inside) an interactive session with Coq.  All the details in the
    text are fully formalized in Coq, and most of the exercises are
    designed to be worked using Coq.

    The files in each book are organized into a sequence of core
    chapters, covering about one semester's worth of material and
    organized into a coherent linear narrative, plus a number of
    "offshoot" chapters covering additional topics.  All the core
    chapters are suitable for both upper-level undergraduate and
    graduate students.

    This book, _Logical Foundations_, lays groundwork for the others,
    introducing the reader to the basic ideas of functional
    programming, constructive logic, and the Coq proof assistant. *)

(* ################################################################# *)
(** * Overview *)

(** Building reliable software is really hard.  The scale and
    complexity of modern systems, the number of people involved, and
    the range of demands placed on them make it extremely difficult to
    build software that is even more-or-less correct, much less 100%%
    correct.  At the same time, the increasing degree to which
    information processing is woven into every aspect of society
    greatly amplifies the cost of bugs and insecurities.

    Computer scientists and software engineers have responded to these
    challenges by developing a whole host of techniques for improving
    software reliability, ranging from recommendations about managing
    software projects teams (e.g., extreme programming) to design
    philosophies for libraries (e.g., model-view-controller,
    publish-subscribe, etc.) and programming languages (e.g.,
    object-oriented programming, aspect-oriented programming,
    functional programming, ...) to mathematical techniques for
    specifying and reasoning about properties of software and tools
    for helping validate these properties.  The _Software Foundations_
    series is focused on this last set of techniques.

    The text is constructed around three conceptual threads:

    (1) basic tools from _logic_ for making and justifying precise
        claims about programs;

    (2) the use of _proof assistants_ to construct rigorous logical
        arguments;

    (3) _functional programming_, both as a method of programming that
        simplifies reasoning about programs and as a bridge between
        programming and logic.

    Some suggestions for further reading can be found in the
    [Postscript] chapter.  Bibliographic information for all
    cited works can be found in the file [Bib]. *)

(* ================================================================= *)
(** ** Logic *)

(** Logic is the field of study whose subject matter is _proofs_ --
    unassailable arguments for the truth of particular propositions.
    Volumes have been written about the central role of logic in
    computer science.  Manna and Waldinger called it "the calculus of
    computer science," while Halpern et al.'s paper _On the Unusual
    Effectiveness of Logic in Computer Science_ catalogs scores of
    ways in which logic offers critical tools and insights.  Indeed,
    they observe that, "As a matter of fact, logic has turned out to
    be significantly more effective in computer science than it has
    been in mathematics.  This is quite remarkable, especially since
    much of the impetus for the development of logic during the past
    one hundred years came from mathematics."

    In particular, the fundamental tools of _inductive proof_ are
    ubiquitous in all of computer science.  You have surely seen them
    before, perhaps in a course on discrete math or analysis of
    algorithms, but in this course we will examine them more deeply
    than you have probably done so far. *)

(* ================================================================= *)
(** ** Proof Assistants *)

(** The flow of ideas between logic and computer science has not been
    unidirectional: CS has also made important contributions to logic.
    One of these has been the development of software tools for
    helping construct proofs of logical propositions.  These tools
    fall into two broad categories:

       - _Automated theorem provers_ provide "push-button" operation:
         you give them a proposition and they return either _true_ or
         _false_ (or, sometimes, _don't know: ran out of time_).
         Although their capabilities are still limited to specific
         domains, they have matured tremendously in recent years and
         are used now in a multitude of settings.  Examples of such
         tools include SAT solvers, SMT solvers, and model checkers.

       - _Proof assistants_ are hybrid tools that automate the more
         routine aspects of building proofs while depending on human
         guidance for more difficult aspects.  Widely used proof
         assistants include Isabelle, Agda, Twelf, ACL2, PVS, and Coq,
         among many others.

    This course is based around Coq, a proof assistant that has been
    under development since 1983 and that in recent years has
    attracted a large community of users in both research and
    industry.  Coq provides a rich environment for interactive
    development of machine-checked formal reasoning.  The kernel of
    the Coq system is a simple proof-checker, which guarantees that
    only correct deduction steps are ever performed.  On top of this
    kernel, the Coq environment provides high-level facilities for
    proof development, including a large library of common definitions
    and lemmas, powerful tactics for constructing complex proofs
    semi-automatically, and a special-purpose programming language for
    defining new proof-automation tactics for specific situations.

    Coq has been a critical enabler for a huge variety of work across
    computer science and mathematics:

    - As a _platform for modeling programming languages_, it has
      become a standard tool for researchers who need to describe and
      reason about complex language definitions.  It has been used,
      for example, to check the security of the JavaCard platform,
      obtaining the highest level of common criteria certification,
      and for formal specifications of the x86 and LLVM instruction
      sets and programming languages such as C.

    - As an _environment for developing formally certified software
      and hardware_, Coq has been used, for example, to build
      CompCert, a fully-verified optimizing compiler for C, and
      CertiKos, a fully verified hypervisor, for proving the
      correctness of subtle algorithms involving floating point
      numbers, and as the basis for CertiCrypt, an environment for
      reasoning about the security of cryptographic algorithms.  It is
      also being used to build verified implementations of the
      open-source RISC-V processor.

    - As a _realistic environment for functional programming with
      dependent types_, it has inspired numerous innovations.  For
      example, the Ynot system embeds "relational Hoare reasoning" (an
      extension of the _Hoare Logic_ we will see later in this course)
      in Coq.

    - As a _proof assistant for higher-order logic_, it has been used
      to validate a number of important results in mathematics.  For
      example, its ability to include complex computations inside
      proofs made it possible to develop the first formally verified
      proof of the 4-color theorem.  This proof had previously been
      controversial among mathematicians because part of it included
      checking a large number of configurations using a program. In
      the Coq formalization, everything is checked, including the
      correctness of the computational part.  More recently, an even
      more massive effort led to a Coq formalization of the
      Feit-Thompson Theorem -- the first major step in the
      classification of finite simple groups.

   By the way, in case you're wondering about the name, here's what
   the official Coq web site at INRIA (the French national research
   lab where Coq has mostly been developed) says about it: "Some
   French computer scientists have a tradition of naming their
   software as animal species: Caml, Elan, Foc or Phox are examples of
   this tacit convention. In French, 'coq' means rooster, and it
   sounds like the initials of the Calculus of Constructions (CoC) on
   which it is based."  The rooster is also the national symbol of
   France, and C-o-q are the first three letters of the name of
   Thierry Coquand, one of Coq's early developers. *)

(* ================================================================= *)
(** ** Functional Programming *)

(** The term _functional programming_ refers both to a collection of
    programming idioms that can be used in almost any programming
    language and to a family of programming languages designed to
    emphasize these idioms, including Haskell, OCaml, Standard ML,
    F##, Scala, Scheme, Racket, Common Lisp, Clojure, Erlang, and Coq.

    Functional programming has been developed over many decades --
    indeed, its roots go back to Church's lambda-calculus, which was
    invented in the 1930s, well before the first computers (at least
    the first electronic ones)!  But since the early '90s it has
    enjoyed a surge of interest among industrial engineers and
    language designers, playing a key role in high-value systems at
    companies like Jane St. Capital, Microsoft, Facebook, and
    Ericsson.

    The most basic tenet of functional programming is that, as much as
    possible, computation should be _pure_, in the sense that the only
    effect of execution should be to produce a result: it should be
    free from _side effects_ such as I/O, assignments to mutable
    variables, redirecting pointers, etc.  For example, whereas an
    _imperative_ sorting function might take a list of numbers and
    rearrange its pointers to put the list in order, a pure sorting
    function would take the original list and return a _new_ list
    containing the same numbers in sorted order.

    A significant benefit of this style of programming is that it
    makes programs easier to understand and reason about.  If every
    operation on a data structure yields a new data structure, leaving
    the old one intact, then there is no need to worry about how that
    structure is being shared and whether a change by one part of the
    program might break an invariant that another part of the program
    relies on.  These considerations are particularly critical in
    concurrent systems, where every piece of mutable state that is
    shared between threads is a potential source of pernicious bugs.
    Indeed, a large part of the recent interest in functional
    programming in industry is due to its simpler behavior in the
    presence of concurrency.

    Another reason for the current excitement about functional
    programming is related to the first: functional programs are often
    much easier to parallelize than their imperative counterparts.  If
    running a computation has no effect other than producing a result,
    then it does not matter _where_ it is run.  Similarly, if a data
    structure is never modified destructively, then it can be copied
    freely, across cores or across the network.  Indeed, the
    "Map-Reduce" idiom, which lies at the heart of massively
    distributed query processors like Hadoop and is used by Google to
    index the entire web is a classic example of functional
    programming.

    For purposes of this course, functional programming has yet
    another significant attraction: it serves as a bridge between
    logic and computer science.  Indeed, Coq itself can be viewed as a
    combination of a small but extremely expressive functional
    programming language plus a set of tools for stating and proving
    logical assertions.  Moreover, when we come to look more closely,
    we find that these two sides of Coq are actually aspects of the
    very same underlying machinery -- i.e., _proofs are programs_.  *)

(* ================================================================= *)
(** ** Further Reading *)

(** This text is intended to be self contained, but readers looking
    for a deeper treatment of particular topics will find some
    suggestions for further reading in the [Postscript]
    chapter. *)

(* ################################################################# *)
(** * Practicalities *)

(* ================================================================= *)
(** ** Chapter Dependencies *)

(** A diagram of the dependencies between chapters and some suggested
    paths through the material can be found in the file [deps.html]. *)

(* ================================================================= *)
(** ** System Requirements *)

(** Coq runs on Windows, Linux, and macOS.  You will need:

    - A current installation of Coq, available from the Coq home page.
      These files have been tested with Coq 8.8.1.

    - An IDE for interacting with Coq.  Currently, there are two
      choices:

        - Proof General is an Emacs-based IDE.  It tends to be
          preferred by users who are already comfortable with Emacs.
          It requires a separate installation (google "Proof
          General").

          Adventurous users of Coq within Emacs may also want to check
          out extensions such as [company-coq] and [control-lock].

        - CoqIDE is a simpler stand-alone IDE.  It is distributed with
          Coq, so it should be available once you have Coq installed.
          It can also be compiled from scratch, but on some platforms
          this may involve installing additional packages for GUI
          libraries and such.

          Users who like CoqIDE should consider running it with the
          "asynchronous" and "error resilience" modes disabled:

  coqide -async-proofs off -async-proofs-command-error-resilience off Foo.v &
*)

(* ================================================================= *)
(** ** Exercises *)

(** Each chapter includes numerous exercises.  Each is marked with a
    "star rating," which can be interpreted as follows:

       - One star: easy exercises that underscore points in the text
         and that, for most readers, should take only a minute or two.
         Get in the habit of working these as you reach them.

       - Two stars: straightforward exercises (five or ten minutes).

       - Three stars: exercises requiring a bit of thought (ten
         minutes to half an hour).

       - Four and five stars: more difficult exercises (half an hour
         and up).

    Also, some exercises are marked "advanced," and some are marked
    "optional."  Doing just the non-optional, non-advanced exercises
    should provide good coverage of the core material.  Optional
    exercises provide a bit of extra practice with key concepts and
    introduce secondary themes that may be of interest to some
    readers.  Advanced exercises are for readers who want an extra
    challenge and a deeper cut at the material.

    _Please do not post solutions to the exercises in a public place_.
    Software Foundations is widely used both for self-study and for
    university courses.  Having solutions easily available makes it
    much less useful for courses, which typically have graded homework
    assignments.  We especially request that readers not post
    solutions to the exercises anyplace where they can be found by
    search engines. *)

(* ================================================================= *)
(** ** Downloading the Coq Files *)

(** A tar file containing the full sources for the "release version"
    of this book (as a collection of Coq scripts and HTML files) is
    available at http://softwarefoundations.cis.upenn.edu.

    If you are using the book as part of a class, your professor may
    give you access to a locally modified version of the files; you
    should use this one instead of the public release version, so that
    you get any local updates during the semester. *)

(* ################################################################# *)
(** * Resources *)

(* ================================================================= *)
(** ** Sample Exams *)

(** A large compendium of exams from many offerings of
    CIS500 ("Software Foundations") at the University of Pennsylvania
    can be found at
    https://www.seas.upenn.edu/~cis500/current/exams/index.html.
    There has been some drift of notations over the years, but most of
    the problems are still relevant to the current text. *)

(* ================================================================= *)
(** ** Lecture Videos *)

(** Lectures for two intensive summer courses based on _Logical
    Foundations_ (part of the DeepSpec summer school series) can be
    found at https://deepspec.org/event/dsss17 and
    https://deepspec.org/event/dsss18/.  The video quality in the
    2017 lectures is poor at the beginning but gets better in the
    later lectures. *)

(* ################################################################# *)
(** * Note for Instructors *)

(** If you plan to use these materials in your own course, you will
    undoubtedly find things you'd like to change, improve, or add.
    Your contributions are welcome!

    In order to keep the legalities simple and to have a single point
    of responsibility in case the need should ever arise to adjust the
    license terms, sublicense, etc., we ask all contributors (i.e.,
    everyone with access to the developers' repository) to assign
    copyright in their contributions to the appropriate "author of
    record," as follows:

      - I hereby assign copyright in my past and future contributions
        to the Software Foundations project to the Author of Record of
        each volume or component, to be licensed under the same terms
        as the rest of Software Foundations.  I understand that, at
        present, the Authors of Record are as follows: For Volumes 1
        and 2, known until 2016 as "Software Foundations" and from
        2016 as (respectively) "Logical Foundations" and "Programming
        Foundations," and for Volume 4, "QuickChick: Property-Based
        Testing in Coq," the Author of Record is Benjamin C. Pierce.
        For Volume 3, "Verified Functional Algorithms", the Author of
        Record is Andrew W. Appel. For components outside of
        designated volumes (e.g., typesetting and grading tools and
        other software infrastructure), the Author of Record is
        Benjamin Pierce.

    To get started, please send an email to Benjamin Pierce,
    describing yourself and how you plan to use the materials and
    including (1) the above copyright transfer text and (2) your
    github username.

    We'll set you up with access to the git repository and developers'
    mailing lists.  In the repository you'll find a file [INSTRUCTORS]
    with further instructions. *)

(* ################################################################# *)
(** * Translations *)

(** Thanks to the efforts of a team of volunteer translators,
    _Software Foundations_ can be enjoyed in Japanese at
    http://proofcafe.org/sf.  A Chinese translation is also underway;
    you can preview it at https://coq-zh.github.io/SF-zh/. *)

(* ################################################################# *)
(** * Thanks *)

(** Development of the _Software Foundations_ series has been
    supported, in part, by the National Science Foundation under the
    NSF Expeditions grant 1521523, _The Science of Deep
    Specification_. *)

(* Wed Jan 9 12:02:43 EST 2019 *)


(*|
####################################################
Difference between parameters and members of a class
####################################################

:Link: https://stackoverflow.com/q/70112873
|*)

(*|
Question
********

I am new to Coq and was wondering what is the difference between the
following things:
|*)

Class test (f g : nat -> nat) := {
    init : f 0 = 0 /\ g 0 = 0;
  }.

(*| and |*)

Reset Initial. (* .none *)
Class test := {
    f : nat -> nat;
    g : nat -> nat;
    init : f 0 = 0 /\ g 0 = 0;
  }.

(*|
Could anyone provide an explanation?
|*)

(*|
Answer (Ana Borges)
*******************

The difference between them is referred to as bundling.
|*)

Reset Initial. (* .none *)
Class test (f g : nat -> nat) := {
    init:   f 0 = 0 /\ g 0 = 0;
  }.

(*| is unbundled, and |*)

Reset Initial. (* .none *)
Class test := {
    f : nat -> nat;
    g : nat -> nat;
    init : f 0 = 0 /\ g 0 = 0;
  }.

(*|
is bundled.

The advantage of bundling is that you don't need to always provide
``f`` and ``g``. The advantage of unbundling is that you can have
different instances of the same class sharing the same ``f`` and
``g``. If you bundle them, Coq will not be easily convinced that
different instances share parameters.

You can read more about this in `Type Classes for Mathematics in Type
Theory
<https://www.researchgate.net/publication/48202776_Type_Classes_for_Mathematics_in_Type_Theory>`__.
|*)

(*|
Answer (Maëlan)
***************

To complement Ana's excellent answer, here is a practical difference:

- the unbundled version (call it ``utest``) allows you to write the
  logical statement ``utest f g`` about a specific pair of functions
  ``f`` and ``g``,
- whereas the bundled version (call it ``btest``) allows you to state
  that there exists a pair of functions which satisfies the
  properties; you can later refer to these functions by the projection
  names ``f`` and ``g``.

So, roughly speaking:

- ``btest`` is "equivalent" to ``∃ f g, utest f g``;
- ``utest f' g'`` is "equivalent" to ``btest`` ∧ "the ``f`` (resp.
  ``g``) in the aforementioned proof of btest is equal to ``f'``
  (resp. ``g'``)".

More formally, here are the equivalences for a minimal example (in
this code, the notation ``{ x : A | B }`` is a **dependent pair**
type, i.e. the type of ``(x, y)`` where ``x : A`` and ``y : B`` and
the type ``B`` depends on the value ``x``):
|*)

Reset Initial. (* .none *)
(* unbundled: *)
Class utest (x : nat) : Prop := {
    uprop : x = 0;
  }.

(* bundled: *)
Class btest : Type := {
    bx : nat;
    bprop : bx = 0;
  }.

(* [btest] is equivalent to: *)

Goal { x : nat | utest x } -> btest.
Proof.
  intros [x u]. econstructor. exact (@uprop x u).
Qed.

Goal btest -> { x : nat | utest x }.
Proof.
  intros b. exists (@bx b). constructor. exact (@bprop b).
Qed.

(* [utest x] is equivalent to: *)

Goal forall x, { b : btest | @bx b = x } -> utest x.
Proof.
  intros x [b <-]. constructor. exact (@bprop b).
Qed.

Goal forall x, utest x -> { b : btest | @bx b = x }.
Proof.
  intros x u. exists {| bx := x ; bprop := @uprop x u |}. reflexivity.
Qed.

(* NOTE: Here I've explicited all implicit arguments; in fact, you
   can let Coq infer them, and write just [bx], [bprop], [uprop]
   instead of [@bx b], [@bprop b], [@uprop x u]. *)

(*|
In this example, we can also observe a difference with respect to
computational relevance: ``utest`` can live in ``Prop``, because its
only member, ``uprop``, is a proposition. On the other hand, I cannot
really put ``btest`` in ``Prop``, because that would mean that *both*
``bx`` and ``bprop`` would live in ``Prop`` but ``bf`` is
computationally relevant. In other words, Coq gives you this warning:
|*)

Reset Initial. (* .none *)
Class btest : Prop := {
    bx : nat;
    bprop : bx = 0;
  }.
(* WARNING:
   bx cannot be defined because it is informative and btest is not.
   bprop cannot be defined because the projection bx was not defined.
*)