Skip to content

Quick Reference for Beginners

alex argunov edited this page Aug 29, 2019 · 2 revisions

What follows is an informal guide to a shortlist of Coq features, designed to give new users a starting point. Runs as a standalone Coq file, tested on versions 8.6 and 8.9.1. Originally written in July 2019.

Require Import Coq.ZArith.ZArith.
Require Import Coq.micromega.Lia.
Require Import Coq.Lists.List.

(*** Concept/Syntax Reference ***)

(***
This is a quick reference for some foundational Coq syntax and proof tactics. It
is by no means complete -- for a complete reference, see the Coq Reference
Manual (https://coq.inria.fr/distrib/current/refman/index.html).

This reference is organized as follows:

Declarations:
  Definition
  Fixpoint
  Lemma
  Theorem
  Inductive

Inspection:
  Search
  Check
  Print

Miscellaneous:
  nat
  match

Propositions:
  Prop
  forall
  exists
  and (/\)
  or (\/)
  implies (->)
  not (~)
  eq (=)
  not-eq (<>)

Proofs:
  intros
  apply
  rewrite
  reflexivity
  cbv
  cbn
  induction
  lia
  nia
  replace
***)

(*** Declarations ***)

(* Definition :
   A [Definition] declares a term, a type, a proposition, or a non-recursive
   function. It looks like:

     Definition <name> : <type> := <value>.

   It's possible to omit the <type> if Coq can infer it from the value, which
   looks like:

     Definition <name> := <value>.

   For functions, the arguments can go before the colon. That is, saying:

     Definition <name> : <type1> -> <type2> -> <type3> := fun <argname> <argname> => <body>

   ...is equivalent to:

     Definition <name> (<argname> : <type1>) : <type2> -> <type3> := fun <argname> => <body>
     Definition <name> (<argname> : <type1>) (<argname : <type2>) : <type3> := <body>
 *)
Module DefinitionExamples.
  (* defining numbers *)
  Definition x : nat := 5.
  Definition y : Z := 5.
  Definition z := 5. (* z is a [nat], because that's the default type of numbers *)

  (* defining types *)
  Definition two_integers : Type := Z * Z. (* represents a pair of integers *)

  (* defining functions *)
  Definition add2 : nat -> nat := fun x => x + 2.
  Definition make_pair : Z -> Z -> two_integers := fun a b => (a,b).

  (* The following are both equivalent to [add2] *)
  Definition add2' (x : nat) : nat := x + 2.
  Definition add2'' (x : nat) := x + 2. (* return type is inferred *)

  (* The following are all equivalent to [make_pair] *)
  Definition make_pair' (a : Z) : Z -> two_integers := fun b => (a,b).
  Definition make_pair'' (a : Z) (b : Z) : two_integers := (a,b).
  Definition make_pair''' (a b : Z) : two_integers := (a,b).

  (* defining propositions : see the entry on [Prop] *)
  Definition nat_pos : Prop := forall x : nat, 0 <= x.
  Definition nat_pos' (x : nat) : Prop := 0 <= x. (* equivalent to [nat_pos] *)

  (* This [Prop] is false; you wouldn't be able to prove it, but you can state it. *)
  Definition nat_neg : Prop := forall x : nat, x < 0.
End DefinitionExamples.

(* Fixpoint :
   [Fixpoint] defines a *recursive* function. Syntax is similar to [Definition]:

     Fixpoint <name> : <type> := fun <arguments...> => <body>.
     Fixpoint <name> (<argname> : <type>) (argname : <type>) ... : <type> := <body>.

   However, it is important to note that Coq does not allow the construction of
   functions that might not terminate. So, every time you write a [Fixpoint], you
   have to make it very clear to Coq that the function will eventually stop. The
   simplest way to do this is to have one of the arguments be a natural number
   that decreases every time you call the function. You can also use
   other inductive structures like lists as the "decreasing" arguments.

   These definitions reference [O] and [S], the two constructors of [nat]. See
   the entry on [nat] to understand what [O] and [S] mean in detail; the short
   version is that O is zero and S is "successor"; any nat is either equal to
   O, or equal to the successor of some other nat.
 *)
Module FixpointExamples.
  (* loop and decrement n until we reach 0 *)
  Fixpoint countdown (n : nat) : nat :=
    match n with
    | O => n
    | S x => countdown x (* "x" is the name I chose for n's predecessor; changing
                            the name won't break anything *)
    end.

  (* exponentiation *)
  Fixpoint power_of (b : nat) (e : nat) : nat :=
    match e with
    | O => 1 (* return 1 if e = 0 *)
    | S n => b * power_of b n (* if e = n + 1 for some n, return b * b^n with a
                                 recursive call *)
    end.

  (* You can also recurse on lists, using the list constructors [nil] (an empty
     list) and [cons] (which makes a list by adding one element to the head of an
     existing list). [Fixpoint] can use any inductive data structure, even one
     you've defined yourself, as the decreasing argument (see the entry on
     [Inductive]) *)
  Fixpoint sum (ls : list nat) : nat :=
    match ls with
    | nil => 0
    | cons x ls' => x + sum ls'
    end.

  (* Fixpoints don't have to be recursive, technically, but there's no reason
     not to use [Definition] in that case. *)
  Fixpoint identity (x : nat) : nat := x.
End FixpointExamples.

(* Lemma :
   [Lemma] is the most common type of proof declaration. The syntax looks like:

      Lemma <name> : <proof statement>.
      Proof.
        <proof body>
      Qed.

   You can omit writing [Proof] before your proof, but it's convention, and
   visually helps separate the proof from the proof statement when the statement
   is long and complicated.

   The proof statement usually has type [Prop] (it can also have [Set] or [Type],
   if you're trying to prove that a type is non-empty, but this is fairly rare in
   practical use afaik).

   The proof body consists of "proof-mode" statements that construct a reasoning
   for why your proof statement is true. If you finish constructing that
   reasoning, you can end your proof with [Qed], which defines your lemma and
   makes it available to future proofs just like any fact from the standard library.

   If you don't finish your proof but want to exit your lemma, you can't use
   [Qed]. Instead, you have two options: [Admitted] and [Abort]. Choosing [Abort]
   means that the lemma will not be defined, and won't be visible to or usable by
   other proofs. Conversely, [Admitted] will let other proofs see and use your
   lemma, even though you haven't yet proven it. Naturally, this means it's
   important to remember if you're depending on an admitted lemma, because it
   means your top-level proof might not be correct. To see the admitted proofs
   a lemma or theorem depends on, type [Print Assumptions <lemma/theorem name>].
 *)
Module LemmaExamples.
  (* [True] has the type [Prop], so it technically counts as a proof statement *)
  Lemma simple : True.
  Proof.
    trivial. (* in this case, we just tell Coq "this proof is easy" *)
  Qed.

  Lemma nat_nonneg : forall a : nat, 0 <= a.
  Proof.
    (* see the [intros] and [lia] entries to understand what these do; for our
       purposes here, what's important is that they prove the goal so we can end
       with [Qed]. *)
    intros. lia.
  Qed.

  (* same statement as [nat_nonneg], just with the [forall] argument pulled
     before the colon *)
  Lemma nat_nonneg' (a : nat) : 0 <= a.
  Proof.
    intros. lia.
  Qed.

  Lemma nat_nonneg_aborted : forall a : nat, 0 <= a.
  Proof.
    intros.
  (* Qed. *) (* uncomment to see that [Qed] before finishing the proof fails *)
  Abort.
  (* Uncomment to see that Coq doesn't know about the lemma we [Abort]ed *)
  (* Check nat_nonneg_aborted. *)

  Lemma nat_nonneg_admitted : forall a : nat, 0 <= a.
  Proof.
    intros.
  (* Qed. *) (* uncomment to see that [Qed] before finishing the proof fails *)
  Admitted.

  Check nat_nonneg_admitted. (* admitted lemma is visible *)

  Lemma use_admitted : 0 <= 5.
  Proof.
    apply nat_nonneg_admitted. (* lemma is usable even though it's unproven *)
  Qed. (* we can still end *this* proof with [Qed] *)

  (* However, when we [Print Assumptions], we can see the admitted lemma *)
  Print Assumptions use_admitted.
End LemmaExamples.

(* Theorem :
   [Theorem] is exactly the same as [Lemma] to Coq. Its only purpose is to signal
   to humans that a particular proof is more important than the ones marked
   [Lemma].

   Other synonyms include [Remark], [Fact], [Corollary], and [Proposition]. In my
   own work, I use almost exclusively [Lemma] and only occasionally [Theorem] to
   mark particularly important top-level proofs. Ultimately, though, this comes
   down to individual style. *)
Module TheoremExamples.
  (* see Lemma examples *)
End TheoremExamples.

(* Inductive :
   Proofs by induction are an extremely powerful tool in mathematical proofs;
   [Inductive] is Coq's built-in machinery for inductive reasoning. Its syntax
   looks like:

   Inductive <name> [<arguments>] : <type> :=
   | <constructor>
   | <constructor>
   | <constructor>
   ...
   | <constructor>
   .

   The first example of an inductive is the [nat] type of natural
   numbers. If you [Print nat], you'll see the definition of the type,
   which looks like this:

   Inductive nat : Set :=
   | O : nat
   | S : nat -> nat
   .

   This means that you can make a natural number in two ways. The first way is
   to make zero (with the constructor [O]). The second way is to add one to an
   existing natural number, creating that number's "successor", using the [S]
   constructor. Because [S] requires a [nat] to create a [nat], its type is
   [nat -> nat]. Natural numbers are defined as everything that can be created
   by some combination of these two constructors. And whenever you have a natural
   number in context, you can use a [match] to split into the two cases -- either
   you have zero, or you have the successor of another number.

   An [Inductive] defines a [Set], [Prop], or [Type]. That means you can have
   inductive datatypes using [Type] (like [nat] or [list] from the standard
   library), and also inductive proof statements. For instance, if you're proving
   something about a state machine, you might want a proof statement that says
   "this state is reachable". Using an [Inductive], you can define "reachable" by
   saying "it's either equal to the initial state (base case) or it's one state
   transition away from another reachable state".
 *)
Module InductiveExamples.

  (* inductive type of binary trees; this says essentially that a binary tree can
     either be a leaf, or can be constructed from two existing binary trees (the
     left and right children. *)
  Inductive tree : Type :=
  | Leaf : tree
  | Parent : tree -> tree -> tree
  .

  (* Now, we can use the constructors of [tree] *)
  Check Parent.

  (* This tree looks like:
          x
         / \
        x   x
       / \
      x   x
   *)
  Definition small_tree : tree :=
    Parent (Parent Leaf Leaf) Leaf.

  (* we can also split into cases when we write functions about trees *)
  Definition is_leaf (t : tree) : bool :=
    match t with
    | Leaf => true
    | Parent x y => false
    end.

  (* ...and we can use a [tree] as the decreasing argument of a [Fixpoint] *)
  Fixpoint depth (t : tree) : nat :=
    match t with
    | Leaf => 0
    | Parent l r => S (max (depth l) (depth r))
    end.

  (* Most importantly, we can use [induction] in proofs -- see the entry on
     [induction] for more examples. This proof states that for all trees t,
     either t has a depth greater than zero or t is a leaf. *)
  Lemma depth_positive :
    forall t : tree, 0 < depth t \/ is_leaf t = true.
  Proof.
    induction t.
    (* now we have two cases : one in which t is a leaf, and one in which t is
       a parent; we'll use curly braces to separate the proof of each case. *)
    { (* subgoal 1 : t is a leaf *)
      cbv [depth is_leaf]. (* inline the definitions of [depth] and [is_leaf];
                              the [match] statements are automatically simplified
                              away *)
      right. (* the left side of the "or" is clearly false, so we confine
                ourselves to proving the right-hand side *)
      reflexivity. (* [reflexivity] can easily prove that [true = true] *)
    }
    { (* subgoal 2 : t is a parent *)
      (* notice that two inductive hypotheses have appeared, stating that, for
         both child trees, our proof statement holds *)
      cbn [depth is_leaf]. (* inline again -- use [cbn] instead of [cbv] to avoid
                              inlining the recursive calls in [depth] *)
      left. (* now, the right hand side of the "or" is clearly false, so we
               confine ourselves to the left *)
      lia. (* the successor of a nat is always < 0; we don't even have to use the
              inductive hypotheses. *)
    }
  Qed.

  (* [Inductive]s, like [Fixpoints], are typically recursive but don't have to
     be. You can also use them like enums, if you want to simply define a type
     that has a fixed set of constructors. *)
  Inductive color_enum : Type :=
  | RED : color_enum
  | GREEN : color_enum
  | BLUE : color_enum
  .

  (* ..then, just like before, you can easily split into cases *)
  Definition is_blue (x : color_enum) : bool :=
    match x with
    | BLUE => true
    | RED => false
    | GREEN => false
    end.


  (* You *can* construct inductive types with no base cases, but it will be
     impossible to construct anything of that type, so it's not very useful. *)
  Inductive silly_thing : Type :=
  | SillyConstructor : silly_thing -> silly_thing
  .

  (* [Inductive]s can also define [Prop]s, not just datatypes. This [Inductive]
     states that a number is even if and only if either it's zero, or it's two
     plus an even number. *)
  Inductive is_even : nat -> Prop :=
  | zero_is_even : is_even 0
  | plus_two_is_even : forall n : nat, is_even n -> is_even (n + 2)
  .
End InductiveExamples.

(*** Inspection ***)

(* Search :
   One of the most useful tactics for discovering lemmas or functions that have
   already been defined is [Search]. The syntax is simple:

           Search <expression>.

   When you process the statement, Coq will print out every function, definition,
   lemma, or anything else in which the expression you entered is part of its
   type signature/proof statement. That is, writing [Search Nat.mul] will show
   you every lemma that says anything at all about the multiplication of natural
   numbers in its proof statement. [Search nat] will give you every function
   that operates on or returns natural numbers, every natural number that has
   been defined already, and every lemma that says anything about [nat]s.

   What constitutes an "expression" for [Search] is very flexible, as you
   will see in the examples.
 *)
Module SearchExamples.

  (* simple statements : you can search about functions or about already-defined
     terms like 2, or even expressions like (1+1). *)
  Search Nat.mul.
  Search Nat.log2.
  Search 2.
  Search (1 + 1).

  (* You can also [Search] for things containing multiple expressions *)
  Search Nat.mul Nat.sub.
  Search Nat.mul Nat.sub 0.

  (* We can also [Search] types, like [nat] and [list], to get every function or
     definition with that type as a subset of its type signature, and every lemma
     that has the type in its proof statement. *)
  Search nat.
  Search list.
  Search (list nat). (* look for lemmas/functions about lists of natural numbers *)
  Search (nat -> nat -> bool). (* look for functions that take in two natural
                                  numbers and return a boolean *)


  (* Extremely usefully, [Search] allows you to leave "blanks" in expressions
     using underscores. *)
  Search (_ * 1). (* find anything times 1 *)
  Search (Nat.log2 _ = 0). (* find any lemma that says something about a [nat]
                              whose [log2] is 0 *)

  (* You can also use [?] to define variables, which lets you repeat them within
     the expression to narrow down your search. *)
  Search (?x * 1). (* same as [Search (_ + 1)], since x not repeated *)
  Search (?x * ?x).
  Search (?x * _ <= ?x * _).

  (* you can attach scope delimiters to [Search] expressions, which means that in
     this [Search] the [1]  and [*] are interpreted as the *integer* 1 and the
     function [Z.mul] (integer multiplication), instead of the *natural number* 1
     and the function [Nat.mul] (natural number multiplication). *)
  Search (_ * 1)%Z.

  (* You can also search for things you define yourself. *)
  Definition x : nat := 5.
  Search x. (* returns nothing because there are no lemmas about [x]; [x]
                    will not show up in its own [Search] because its *type*,
                    [nat], says nothing about [x]. *)
  Search nat. (* However, [x] does show up when we [Search nat] *)
  Lemma x_pos : 0 < x.
  Proof.
    cbv [x]. lia.
  Qed.
  Search x. (* now, we can see the lemma we just defined *)
End SearchExamples.

(* Check :
   [Check] is a useful tool for looking at the types of lemmas, functions, etc.
   The syntax is very similar to [Search] :

           Check <expression>.

   Coq will then print the name and type of the expression. This is most useful
   for proofs, whose "types" are their proof statements.
 *)
Module CheckExamples.

  (* look at the types of functions or pre-defined terms like [2] *)
  Check Nat.mul.
  Check 2.

  Check nat. (* the [nat] type is technically a [Set] (the difference between
                [Set] and [Type] is rarely relevant; feel free to think of them
                as synonyms) *)
  Check list. (* the [list] type requires you to specify what type the list
                 elements are, so [list] has type [Type -> Type] *)
  Check Type. (* [Type] has type [Type], in case you were curious *)

  (* [Check] is most often used to look at proof statements, like so *)
  Check Nat.log2_nonneg.
  Check Nat.mul_le_mono_l.

  (* you can even feed the proofs arguments to see what the proof statement
     looks like partially filled in *)
  Check (Nat.mul_le_mono_l 1 2 3).
  Check (Nat.mul_le_mono_l 1 2).
  Check (Nat.mul_le_mono_l _ _ 3).

  (* [Check] works on things you define yourself *)
  Definition x : nat := 5.
  Check x.

  (* [Check], like [Search], accepts scope delimiters. *)
  Check 2%Z.
End CheckExamples.

(* Print :
   While [Search] and [Check] show only the *types* of the things you search for,
   [Print] shows you the actual values. The syntax is very similar to [Search]
   and [Check]:

       Print <expression>.

   However, [Print] is more restrained in the kinds of expressions it accepts. In
   particular, [Print] only accepts what's referred to in the Coq manual as
   "qualid"s or "qualifier IDs" -- that means the *names* of functions, lemmas,
   definitions, types, etc. Unlike [Search], you can't [Print] a partially-filled
   expression like [(_ + 1)]; unlike [Check], you can't [Print] lemmas with
   arguments filled in like [(Nat.mul_le_mono_l 1)]. You can only use names, by
   themselves -- like [Print Nat.add] or [Print Nat.mul_le_mono_l].
 *)
Module PrintExamples.

  (* [Print]ing functions shows you the function definitions *)
  Print Nat.mul.

  (* You can also see the definitions of inductive types, which can be useful *)
  Print nat.
  Print list.

  (* [Print]ing an inductive constructor shows you the whole [Inductive] *)
  Print O.
  Print cons.

  (* printing lemmas is not usually useful, as you will see the raw form of the
     proof and it might be very large *)
  Print Nat.log2_nonneg.
End PrintExamples.

(*** Miscellaneous ***)

(* nat :
   One of the most frequently used and most basic types in Coq, [nat] is the type
   of natural numbers (0 and above).

   The definition of [nat] (as shown by [Print nat]) is:

   Inductive nat : Set :=
   | O : nat
   | S : nat -> nat
   .

   See the entry on [Inductive] for more detail about what this means exactly.
   But the gist is that you can construct a [nat] one of two ways: 1) by using
   the "O" constructor, which takes no arguments and represents zero, and 2) by
   using the "S" constructor, which takes another [nat] as an argument and
   represents the "successor" of the input (input + 1). In this format, 3 is
   represented by [S (S (S O))], 1 is represented by [S O], and so on.

   The Coq standard library contains many proofs about [nat], which can be found
   using [Search]. It further contains definitions of arithmetic operations like
   addition (Nat.add or +), multiplication (Nat.mul or * ), square root
   (Nat.sqrt), maximum/minimum (Nat.max/Nat.min), and even bitwise operations
   (Nat.lor, Nat.land, Nat.lxor, Nat.lnot). There are also definitions for
   comparison operations like < (Nat.lt), <= (Nat.le), > (Nat.gt), and
   >= (Nat.ge).
 *)
Module NatExamples.

  (* Define a term with type [nat] *)
  Definition x : nat := 5.

  (* we can split natural numbers into their two cases -- zero or successor *)
  Definition is_nonzero (n : nat) : bool :=
    match n with
    | O => false
    | S m => true
    end.

  (* an example lemma about natural numbers using comparison operators; states
     that if a [nat] is greater than zero and you add another [nat] to it, the
     result will also be greater than zero. *)
  Lemma sum_positive :
    forall n m : nat, 0 < n -> 0 < n + m.
  Proof.
    intros.
    lia. (* [lia] is the "linear arithmetic" tactic, and solves this one easily *)
  Qed.

  (* It's important to keep in mind that [nat] is very inefficient when composing
     large numbers. For anything where you're computing large numbers directly,
     use Z or N, which are based on binary formats and scale much better. *)
  Definition n : nat := 1000.
  (* Uncomment to see what your system does -- mine stack overflows *)
  (* Eval compute in (n * n). *)
  Definition z : Z := 1000.
  Eval compute in (z * z)%Z. (* just fine! *)
  Eval compute in (z * z * z * z * z * z)%Z. (* still fine *)

  (* Uncomment to see that at some point [Z] does get slow, but still no stack
     overflow *)
  (* Eval compute in (z ^ 500)%Z. *)

  (* Most other entries in this reference have natural numbers in their examples,
     too, so if you'd like more just look around! *)
End NatExamples.

(* match :
   When you have an inductive datatype, you can split into cases based on its
   constructors using [match]. The syntax is:

            match <name> with
            | <constructor> => <expression>
            | <constructor> => <expression>
            ...
            | <constructor> => <expression>
            end.

   This isn't unlike a [switch] or [case] statement in other programming
   languages. Cases can be listed in any order.

   You must put some expression for all cases. If you want a "default" behavior
   that applies to many different cases, you can use an underscore to match "any
   case not listed above". Therefore, for a [nat] called x, writing:

            match x with
            | O => true
            | S _ => false
            end

   ...is completely equivalent to both of the following:

            match x with
            | O => true
            | _ => false
            end

            match x with
            | S _ => false
            | _ => true
            end

  Note: there's also a [match] you can use in proof-mode with similar syntax,
  but it's not exactly the same thing.
 *)
Module MatchExamples.

  (* basic match -- two cases of nat constructors *)
  Definition minus1 (n : nat) : nat :=
    match n with
    | O => 0 (* 0 - 1 = 0 with natural numbers, since they can't go negative *)
    | S m => m
    end.

  (* If a constructor takes an argument, you can name the argument whatever you
     want. The following is completely equivalent to [minus1]. *)
  Definition minus1' (n : nat) : nat :=
    match n with
    | O => 0
    | S what_a_long_name123 => what_a_long_name123
    end.

  (* If you're ignoring the argument(s) a constructor takes, you can put _ *)
  Definition is_nonzero (n : nat) : bool :=
    match n with
    | O => false
    | S _ => true
    end.

  (* you can match multiple things at once *)
  Definition both_nonzero (n m : nat) : bool :=
    match n, m with
    | O, O => false
    | O, S _ => false
    | S _, O => false
    | S _, S _ => true
    end.

  (* equivalent to both_nonzero; using an underscore to signify "any case not
     listed above" *)
  Definition both_nonzero' (n m : nat) : bool :=
    match n, m with
    | S _, S _ => true
    | _, _ => false
    end.

  (* You can also match expressions *)
  Definition sum_nonzero (n m : nat) : bool :=
    match n + m with
    | O => false
    | S _ => true
    end.

  (* You can put matches in lemma statements, if you really want to, but it's
     a little hard to read. This lemma says "if x and y are both zero, their sum
     is zero; otherwise, their sum is greater than zero". *)
  Lemma sum_zero_or_positive :
    forall x y : nat,
      match x, y with
      | O, O => 0 = x + y
      | _, _ => 0 < x + y
      end.
  Proof.
    destruct x, y; lia.
  Qed.

End MatchExamples.

(*** Propositions ***)

(* Prop :
   The type of proof statements in Coq is called [Prop]. You can use it like any
   other type, from making definitions with that type to writing functions that
   take [Prop] as input. But it's more analogous to the type [Type] than it is
   to a type like [nat].

   Some extra notes for the curious:

   When you define something with type [Prop], the proof statement you have
   written can function a lot like a type. There can be many different ways to
   prove the same statement, and you can think of these as many different members
   of the type, much like there are many ways to construct a natural number, but
   they all have the same type. You might even write a false [Prop], for which
   there exist no proofs; this would be equivalent to a type with no members.

   In this framework, writing a proof in Coq is essentially like writing a
   function. This is called the Curry-Howard correspondence and is really cool if
   you want to read further about it.
 *)
Module PropExamples.

  (* The two most basic [Prop]s are [True] and [False] *)
  Check True.
  Check False.
  Print True. (* [True] has one constructor with no arguments; it can always be
                 constructed without input *)
  Print False. (* [False] is an inductive with no constructors; it can never be
                  constructed *)

  (* simple example: equality and comparison operations output [Prop] *)
  Definition one_lt_2 : Prop := 1 < 2.
  Definition one_eq_2 : Prop := 1 = 2. (* [Prop]s can be false! *)

  (* You can take arguments when defining a [Prop] *)
  Definition x_lt_2 : nat -> Prop := fun x => x < 2.

  (* You can construct new [Prop]s from ones you've already defined *)
  Definition x_le_2 : nat -> Prop := fun x => x_lt_2 x \/ x = 2.

  (* A good example of using [Prop] is [In], a function that takes in an element
     and a list and outputs a [Prop] saying the element is in the list. You can
     see it with [Print In], but I'll also write it out here. *)
  Fixpoint In' (A : Type) (a : A) (ls : list A) :=
    match ls with
    | nil => False
    | cons b ls' => b = a \/ In' A a ls' (* a is equal to the first element, or
                                            is in the remainder of the list *)
    end.
  (* We can see the full [Prop] provided by [In'] by plugging in a list *)
  Eval compute in (fun x => In' nat x (cons 3 (cons 2 nil))).

  (* We can also prove a statement in terms of [In'] *)
  Lemma two_in_list : In' nat 2 (cons 3 (cons 2 nil)).
  Proof.
    cbv [In'].
    auto.
  Qed.

  (* See the following entries for examples of the syntax used to construct
     [Prop]s *)
End PropExamples.

(* forall :
   The [forall] quantifier is exactly the same as a [forall] in mathematics, and
   is used the same way when writing [Prop]s. The syntax looks like:

      forall (<name> : <type>), <statement in terms of name>
 *)
Module ForallExamples.

  (* To showcase the various different ways of writing arguments to [forall],
     here are several definitions that are all completely equivalent. *)
  Definition nat_lt : Prop :=
    forall (x : nat) (y : nat), x < y.
  Definition nat_lt' : Prop :=
    forall (x : nat), forall (y : nat), x < y.
  Definition nat_lt'' : Prop :=
    forall (x y : nat), x < y.
  Definition nat_lt''' : Prop :=
    forall x y, x < y. (* Coq knows that < is short for [Nat.lt], so x and y
                          must be [nat]s *)
  Definition nat_lt'''' : Prop :=
    forall x, forall y, x < y.
  Definition nat_lt''''' : Prop :=
    forall (x : nat) y, x < y.

  (* You can also use [forall] for things with type [Prop], but it's usually
     more readable to use [implies] *)
  Definition lt_transitive : Prop :=
    forall a b c (Hab : a < b) (Hbc : b < c),
      a < c.
  (* more readable version of [lt_transitive] *)
  Definition lt_transitive' : Prop :=
    forall a b c,
      a < b ->
      b < c ->
      a < c.

End ForallExamples.

(* exists :
   The [exists] quantifier works basically the same way as [forall], with the
   same syntax and the meaning you would expect from a mathematical [exists].

   Note: in proof mode, there is also a tactic called [exists], but it is a
   different thing than the one used in defining [Prop]s.
 *)
Module ExistsExamples.

  Lemma exists_pos : exists x : nat, 0 < x.
  Proof.
    exists 1. (* here's that [exists] tactic; it takes a goal with an [exists]
                 on the outside and plugs in a specific member of the requested
                 type *)
    lia.
  Qed.
End ExistsExamples.

(* and (/\):
   The [and] function takes two [Prop]s and creates another [Prop], representing
   the conjunction of the two.

   [and] is represented by the notation "/\".

   It is defined as an inductive [Prop], with the single constructor [conj]. As
   [Print and] will show:

          Inductive and (A B : Prop) : Prop :=
          | conj : A -> B -> A /\ B
          .
 *)
Module AndExamples.

  (* states that a [nat] is in the range [low...high) *)
  Definition in_range (low high : nat) : nat -> Prop :=
    fun x => x < high /\ low <= x.

  (* equivalent to [in_range], just not using the [/\] notation *)
  Definition in_range' (low high : nat) : nat -> Prop :=
    fun x => and (x < high) (low <= x).
  Print in_range'. (* printing shows you the notation again *)

  (* proof using [and]s; states that we can expand the range and know that it
     still holds everything that was in the original range *)
  Lemma loosen_range :
    forall low high new_low new_high,
      high <= new_high ->
      new_low <= low ->
      forall x,
        in_range low high x ->
        in_range new_low new_high x.
  Proof.
    cbv [in_range]. (* inline the definition of [in_range] *)
    intros.
    destruct H1. (* use [destruct] to separate an [and] in a hypothesis *)
    split. (* use [split] to separate an [and] in a goal *)
    { lia. }
    { lia. }
  Qed.

End AndExamples.

(* or (\/):
   The [or] function is very analogous to [and], and is represented by the
   notation "\/".

   [or] is defined as an inductive [Prop] with two constructors: [or_introl] and
   [or_intror]. These say that you can construct an [or] with a proof of either
   the left side or the right side, respectively, which makes good sense. The
   definition is:

       Inductive or (A B : Prop) : Prop :=
       | or_introl : A -> A \/ B
       | or_intror : B -> A \/ B
       .
 *)
Module OrExamples.

  (* states that a [nat] is *outside* the range [low...high) *)
  Definition out_of_range (low high : nat) : nat -> Prop :=
    fun x => high <= x \/ x < low.

  (* equivalent to [out_of_range], just without using the [\/] notation *)
  Definition out_of_range' (low high : nat) : nat -> Prop :=
    fun x => or (high <= x) (x < low).
  Print out_of_range'. (* printing shows you the notation again *)

  (* proof using [or]s; states that we can narrow the range and know that
     everything that was outside the range is still outside it *)
  Lemma tighten_range :
    forall low high new_low new_high,
      new_high <= high ->
      low <= new_low ->
      forall x,
        out_of_range low high x ->
        out_of_range new_low new_high x.
  Proof.
    cbv [out_of_range]. (* inline the definition of [out_of_range] *)
    intros.
    destruct H1. (* use [destruct] to separate an [or] in a hypothesis; this
                    will give you two subgoals *)
    { left. (* use [left] to prove an [or] by proving the left side *)
      lia. }
    { right. (* use [right] to prove an [or] by proving the right side *)
      lia. }
  Qed.
End OrExamples.

(* implies (->) :
   The [implies] function is represented by an arrow [->] and states that a
   particular [Prop] implies another. It's used very frequently to add
   preconditions to lemma statements.
 *)
Module ImpliesExamples.

  (* simple example: if n < m, then n <= m *)
  Definition lt_le_incl : Prop :=
    forall n m : nat, n < m -> n <= m.

  (* chain multiple [implies] for multiple preconditions *)
  Definition lt_transitive : Prop :=
    forall a b c, a < b -> b < c -> a < c.

  (* These statements are completely equivalent to each other and to
     [lt_transitive]. *)
  Definition lt_transitive' : Prop :=
    forall a b c,
      a < b ->
      b < c ->
      a < c.
  Definition lt_transitive'' : Prop :=
    forall a b c,
      a < b
      -> b < c
      -> a < c.
  Definition lt_transitive''' : Prop :=
    forall a b c,
      a < b -> b < c ->
      a < c.

  (* Using [and] works, but is annoying in proofs because then you have to
     [destruct] hypotheses with [and] and [split] goals with [and], all over the
     place. Chaining [implies] is recommended instead. *)
  Definition lt_transitive'''' : Prop :=
    forall a b c,
      (a < b /\ b < c) -> (* not recommended *)
      a < c.
End ImpliesExamples.

(* not (~):
   The [not] function, represented by [~], actually has a very simple definition.
   [Print not] will show you:

          fun A : Prop => A -> False

   Because we have the unconstructable [Prop], [False], saying a [Prop] is not
   true is equivalent to saying that if it was true, then it would imply [False].
 *)
Module NotExamples.

  (* simple example of a [Prop] using [not] *)
  Definition not_lt (a b : nat) : Prop :=
    ~ (a < b).

  (* using [not] in preconditions *)
  Definition not_lt_ge : Prop :=
    forall a b,
      ~ (a < b) ->
      a >= b.

  (* proving a goal with [not] *)
  Lemma ge_not_lt :
    forall a b,
      a >= b ->
      ~ (a < b).
  Proof.
    intros.
    (* If you read the definition of [not], you'll see that what our goal really
       says now is (a < b) -> False. [intros] won't pick it up, but if you use
       the variant [intro] Coq will know you mean business and actually show you
       the structure. *)
    intro. (* now our goal says [False]! We have to prove that the hypotheses
              contradict. *)
    lia. (* luckily, [lia] is pretty smart. *)
  Qed.
End NotExamples.

(* eq (=):
   The default equality relation in Coq is [eq], represented by [=]. It is
   defined as an inductive [Prop] with one constructor, [eq_refl]:

        Inductive eq {A : Type} (x : A) : A -> Prop :=
        | eq_refl : eq x x
        .

   (Note that A, the type of x, is "implicit"; Coq will infer what A is from x,
   so you can use [eq] or [eq_refl] without writing the type.)

   This definition says that for any type A, and any element x of that type, x
   is equal to itself. So, to prove equality, you must have exactly the same
   thing on either side of the [=] sign.

   Extra notes for the curious:

   This notion of equality produces some problems for the equivalence of
   functions; even if two functions always produce the same output for every
   possible input, if they are constructed differently they will not be equal
   in this definition of [eq]. Assuming they can be swapped freely for each
   other is called functional extensionality, and exists only as an axiom that I
   do not recommend using. Instead, specifically prove in each place you need it
   that swapping out a function argument for an equivalent function produces the
   same result. It's annoying, but it's logically consistent. For an example of
   this kind of proof, look at [map_ext] from the list library, which says that
   you can swap out the functional argument of [map] for an equivalent function
   without changing the result. (It's convention to give this kind of lemma a
   name ending in "_ext" for "extensionality".)

   The default equality used in Coq is Leibniz equality, in theoretical-math
   terms. It's possible to create your own notions of equivalence in Coq, but
   that is beyond the scope of this reference; if that's what you're looking to
   do you should examine [RelationClasses.Equivalence]. To use [rewrite] with
   custom equivalence relations, look at [Proper] and [setoid_rewrite] as well.
 *)
Module EqExamples.
  (* simple [Prop] using [eq] *)
  Definition simple_eq : Prop := 1 = 2.

  (* equivalent to [simple_eq], just not using the [=] notation *)
  Definition simple_eq' : Prop := eq 1 2.
  Print simple_eq'. (* notation shows up again when printed *)

  (* [Prop] with equality on lists of [nat]s *)
  Definition cons_hd_tl_nat : Prop :=
    forall ls : list nat,
      ls <> nil ->
      cons (hd 0 ls) (tl ls) = ls.

  (* [Prop] with equality on lists with unspecified element types *)
  Definition cons_hd_tl : Prop :=
    forall (A : Type) (ls : list A) (a : A),
      ls <> nil ->
      cons (hd a ls) (tl ls) = ls.
End EqExamples.

(* not-eq (<>) :
   When you write something in Coq of the form [~ (x = y)], this gets shortened
   into the notation [<>], meaning "not equal".

   Since most of this is covered by the [eq] and [not] entries, this entry is
   rather short; look at [eq] and [not] for further understanding.
 *)
Module NotEqExamples.

  (* using <> to state a simple [Prop] *)
  Definition one_neq_2 : Prop := 1 <> 2.

  (* using <> to state a precondition *)
  Definition nonzero_pos : Prop :=
    forall n : nat,
      n <> 0 ->
      0 < n.
End NotEqExamples.

(*** Proof mode ***)

(* intros :
   The [intros] tactic is frequently run at the beginning of proofs and separates
   the proof state into the things you already know (above the ===== line) and
   the things you're trying to prove (below the ==== line).

   It works both on [forall] arguments and on the first arguments to [implies];
   that is, if your goal says something like:

     forall x y, x < y -> x <= y

   ...then the things you "know", which [intros] will move above the line, are:
     - x and y exist and are natural numbers
     - x < y

   Sometimes, particularly when using the [induction] tactic, it's important to
   leave [forall]s intact, so resist the temptation to run [intros] automatically
   on inductive proofs. See the entry on [induction] for details. *)
Module IntrosExamples.
  (* [intros] pulls [forall] arguments into the "known" section *)
  Lemma simple_intros : forall a : nat, 0 <= a.
  Proof.
    (*
       ============================
       forall a : nat, 0 <= a *)
    intros.
    (* a : nat
       ============================
       0 <= a *)
  Abort.

  (* if you put the argument before the colon, it's already "introduced" *)
  Lemma intros_unneeded (a : nat) : 0 <= a.
  Proof.
    (* a : nat
       ============================
       0 <= a *)
    intros. (* no-op *)
  Abort.

  (* [intros] also pulls preconditions into the "known" section *)
  Lemma intros_precondition : forall a : nat, a <> 0 -> 0 < a.
  Proof.
    (*
       ============================
       forall a : nat, a <> 0 -> 0 <= a *)
    intros.
    (* a : nat
       H : a <> 0
       ============================
       0 <= a *)
  Abort.

  (* [intros] works if you don't have a [forall] as well *)
  Lemma intros_precondition' : 1 <> 0 -> 0 < 1.
  Proof.
    (*
       ============================
       1 <> 0 -> 0 < 1 *)
    intros.
    (* H : 1 <> 0
       ============================
       0 < 1 *)
  Abort.

  (* [intros] can optionally rename your arguments/preconditions *)
  Lemma intros_names : forall a : nat, a <> 0 -> 0 < a.
  Proof.
    (*
       ============================
       forall a : nat, a <> 0 -> 0 <= a *)
    intros x y.
    (* x : nat
       y : x <> 0
       ============================
       0 <= x *)
  Abort.

  (* Leaving a [?] when providing names tells [intros] to name that argument
     however it wants *)
  Lemma intros_names : forall a : nat, a <> 0 -> 0 < a.
  Proof.
    (*
       ============================
       forall a : nat, a <> 0 -> 0 <= a *)
    intros x ?.
    (* x : nat
       H : x <> 0
       ============================
       0 <= x *)
  Abort.
End IntrosExamples.

(* apply :
   The [apply] tactic is the simplest way to use a lemma or known hypothesis in
   proof-mode. The basic syntax is:

         apply <lemma name>.

   If the lemma or hypothesis exactly matches the goal, then this step completes
   the proof. If the lemma has preconditions, you'll be left with having to prove
   them.
 *)
Module ApplyExamples.

  (* use [apply] to prove a goal using a hypothesis *)
  Lemma simple_apply_hypothesis :
    forall n : nat,
      0 < n ->
      0 < n.
  Proof.
    intros.
    (* n : nat
       H : 0 < n
       ============================
       0 < n *)
    apply H.
  Qed.

  (* use [apply] to prove a goal using a hypothesis with preconditions *)
  Lemma apply_hypothesis_precondition :
    (forall m, m <> 0 -> 0 < m) ->
    0 < 5.
  Proof.
    intros.
    (* H : forall m : nat, m <> 0 -> 0 < m
       ============================
       0 < 5 *)
    apply H.
    (* H : forall m : nat, m <> 0 -> 0 < m
       ============================
       5 <> 0 *)
    lia.
  Qed.

  (* use an existing lemma about the distributive property of [mul] to prove
     a simple arithmetic statement *)
  Lemma mul_distributive :
    forall n m : nat,
      n * (m + n) = n * m + n * n.
  Proof.
    intros.
    (* n, m : nat
       ============================
       n * (m + n) = n * m + n * n *)
    apply Nat.mul_add_distr_l.
  Qed.

  (* You can pass arguments to lemmas in [apply]. Look at the entries for [Check]
     and [Search] to find out about inspecting lemmas to see which arguments are
     which. *)
  Lemma gt_5_implies_gt_3 :
    forall a : nat,
      5 < a ->
      3 < a.
  Proof.
    intros.
    (* a : nat
       H : 5 < a
       ============================
       3 < a *)

    (* just plain [apply Nat.lt_trans] will fail, because the goal only mentions
       [3] and [a] ("n" and "p" respectively in the lemma statement); Coq doesn't
       know what to plug in for the variable "m" in the lemma statement (it
       should be 5). *)
    Check Nat.lt_trans. (* look at the lemma statement *)
    Fail apply Nat.lt_trans. (* error message: "Unable to find an instance for
                                the variable m." *)

    (* however, if we pass in all the arguments explicitly, it works fine *)
    apply (Nat.lt_trans 3 5 a).

    (* other options that would work the exact same way:
             apply (Nat.lt_trans _ 5 _).
             apply Nat.lt_trans with (m := 5).
    *)


    (* a : nat
       H : 5 < a
       ============================
       3 < 5

    subgoal 2 (ID 14) is:
    5 < a *)
    { (* subgoal 1 : 3 < 5 *)
      lia. }
    { (* subgoal 2 : 5 < a *)
      apply H. }
  Qed.
End ApplyExamples.

(* rewrite :
   The [rewrite] tactic is another essential one in Coq, and the other main way
   of using already-proven lemmas or hypotheses in proofs. The basic syntax is:

       rewrite <lemma name>.

   [rewrite] works with proof statements of the form [a = b] and expressions that
   mention something about [a]; if you know [a = b], you can restate your goal or
   hypothesis in terms of [b]. If the lemma or hypothesis you [rewrite] with has
   preconditions, these will appear as new subgoals.
 *)
Module RewriteExamples.

  (* use lemmas from the standard library to change the goal *)
  Lemma simple_rewrite :
    forall n,
      n + 0 = 0 + n.
  Proof.
    intros.
    (* n : nat
       ============================
       n + 0 = 0 + n *)
    rewrite Nat.add_0_r.
    (* n : nat
       ============================
       n = 0 + n *)
    rewrite Nat.add_0_l.
    (* n : nat
       ============================
       n = n *)
    reflexivity.
  Qed.

  (* use known hypotheses to change the goal *)
  Lemma rewrite_with_hypothesis :
    forall n m p,
      n + m = 1 + p ->
      (n + m) ^ 4 = (1 + p) ^ 4.
  Proof.
    intros.
    (* n, m, p : nat
       H : n + m = 1 + p
       ============================
       (n + m) ^ 4 = (1 + p) ^ 4 *)
    rewrite H.
    (* n, m, p : nat
       H : n + m = 1 + p
       ============================
       (1 + p) ^ 4 = (1 + p) ^ 4 *)
    reflexivity.
  Qed.

  (* with [<-], you can rewrite "backwards" *)
  Lemma rewrite_with_hypothesis' :
    forall n m p,
      n + m = 1 + p ->
      (n + m) ^ 4 = (1 + p) ^ 4.
  Proof.
    intros.
    (* n, m, p : nat
       H : n + m = 1 + p
       ============================
       (n + m) ^ 4 = (1 + p) ^ 4 *)
    rewrite <-H.
    (* n, m, p : nat
       H : n + m = 1 + p
       ============================
       (n + m) ^ 4 = (n + m) ^ 4 *)
    reflexivity.
  Qed.

  (* you can also [rewrite] in a hypothesis *)
  Lemma rewrite_in_hypothesis :
    forall n m,
      n + 0 = m ->
      n = m.
  Proof.
    intros.
    (* n, m : nat
       H : n + 0 = m
       ============================
       n = m *)
    rewrite Nat.add_0_r in H.
    (* n, m : nat
       H : n = m
       ============================
       n = m *)
    apply H.
  Qed.

  (* If you [rewrite] with a lemma that has preconditions, they will show up as
     new subgoals. *)
  Lemma rewrite_with_preconditions :
    forall n,
      n * 3 = 0 ->
      n * 5 = 0.
  Proof.
    intros.
    (* n : nat
       H : n * 3 = 0
       ============================
       n * 5 = 0 *)
    rewrite (Nat.mul_eq_0_l n 3).
    (* n : nat
       H : n * 3 = 0
       ============================
       0 * 5 = 0

       subgoal 2 (ID 37) is:
       n * 3 = 0
       subgoal 3 (ID 38) is:
       3 <> 0 *)
    { lia. }
    { lia. }
    { lia. }
  Qed.

  (* Writing [rewrite <lemma> by <tactic>] lets you rewrite if and only if all
     the preconditions can be solved by <tactic>. *)
  Lemma rewrite_by :
    forall n,
      n * 3 = 0 ->
      n * 5 = 0.
  Proof.
    intros.
    (* n : nat
       H : n * 3 = 0
       ============================
       n * 5 = 0 *)
    rewrite (Nat.mul_eq_0_l n 3) by lia.
    (* n : nat
       H : n * 3 = 0
       ============================
       0 * 5 = 0 *)
    (* No new subgoals this time *)
    lia.
  Qed.

  (* Like [apply], you can pass arguments to [rewrite]; this is useful if you
     have multiple places that could be transformed by the same lemma and want
     to specify which one you mean. *)
  Lemma rewrite_with_arguments :
    forall n m p,
      p + m = n ->
      n + n = m + p + n.
  Proof.
    intros.
    (* n, m, p : nat
       H : p + m = n
       ============================
       n + n = m + p + n *)

    (* Now, we want to [rewrite] with [Nat.add_comm] to switch the order of [p]
       and [m] so we can use H. But when we try, Coq will attempt to change the
       order of the first [Nat.add] it sees -- [n + n]. That fails, because it
       doesn't change the goal at all. *)
    Fail rewrite Nat.add_comm. (* error : "Tactic generated a subgoal identical
                                  to the original goal" *)

    (* if we specify the arguments to [Nat.add_comm], it works *)
    rewrite (Nat.add_comm m p).
    (* n, m, p : nat
       H : p + m = n
       ============================
       n + n = p + m + n *)
    rewrite H.
    reflexivity.
  Qed.
End RewriteExamples.

(* reflexivity :
   The [reflexivity] tactic is simple but powerful. Basically, you tell Coq "I'm
   pretty sure both things on the side of this [eq] are the same" and Coq then
   simplifies them until either they can't be simplified further or they're equal.
   [reflexivity] takes no arguments.

   [reflexivity] also works on other relations that are known to Coq to be
   reflexive, like [<=].

   Performance note : If [reflexivity] is very slow, Coq is probably simplifying
   something it shouldn't be simplifying, and you should try transforming your
   goal some more to get rid of any subterms that are huge when simplified, such
   as a non-opaque proof or a term with a ton of [let]s in it.
 *)
Module ReflexivityExamples.

  (* if the two sides of the [eq] are precisely equal, call [reflexivity]! *)
  Lemma basic_reflexivity :
    5 = 5.
  Proof.
    reflexivity.
  Qed.
  (* also works on other reflexive relations like [<=] *)
  Lemma reflexivity_le :
    5 <= 5.
  Proof.
    reflexivity.
  Qed.

  (* [reflexivity] works even if it has to inline definitions for the two sides
     to be equal *)
  Definition x : nat := 5.
  Lemma reflexivity_inlines :
    x = 5.
  Proof.
    reflexivity.
  Qed.
  (* in this case, [reflexivity] inlines [Nat.add] *)
  Lemma reflexivity_inlines' :
    3 + 2 = 5.
  Proof.
    reflexivity.
  Qed.

  (* However, [reflexivity] knows nothing about math, and won't understand
     anything in terms of variables unless the variables are in exactly the same
     places on either side of the [eq]. *)
  Lemma reflexivity_bad_at_math :
    forall n m : nat,
      n + m = m + n.
  Proof.
    Fail reflexivity. (* error : "Unable to unify 'm + n' with 'n + m'." *)
  Abort.

  (* Sometimes, if you're lucky, your expression simplifies in exactly the way
     you want it to. In this case, [Nat.add] branches on the first argument
     first, and simply returns the second argument. So [reflexivity] figures this
     one out, even though it's bad at math. *)
  Lemma reflexivity_lucky :
    forall n : nat,
      0 + n = n.
  Proof.
    reflexivity.
  Qed.
  (* However, it's not recommended to rely on this, because if the definition of
     [Nat.add] changed, your proof would break. Already, this doesn't work if you
     reverse the arguments, because [Nat.add] is trying to branch on the first
     argument. *)
  Lemma reflexivity_unlucky :
    forall n : nat,
      n + 0 = n.
  Proof.
    Fail reflexivity. (* error : "Unable to unify 'n' with 'n + 0'." *)
  Abort.
  (* You can see why [reflexivity] works for [0 + n] but not [n + 0] by running
     [Eval compute] on the expression to simplify it yourself. *)
  Eval compute in (fun n => 0 + n). (* simplifies to [fun n => n] *)
  Eval compute in (fun n => n + 0). (* simplifies to a recursive match expression *)
End ReflexivityExamples.

(* cbv :
   The [cbv] tactic inlines definitions in your goal or hypotheses. If you give
   it no arguments, it will inline everything. If you give it a list of term
   names, however, it will only inline the things you named. [cbv] will also
   inline [let]s and apply functions (so something like [(fun x y => x + y) 5]
   would become [(fun y => 5 + y)].

   Performance note : like [reflexivity], it's not a good idea to use [cbv] on
   very large terms, because it will be slow.
 *)
Module CbvExamples.

  (* With no arguments, [cbv] inlines everything *)
  Lemma simple_cbv :
    Nat.double 5 = 11 - 1.
  Proof.
    (*
       ============================
       Nat.double 5 = 11 - 1 *)
    cbv.
    (*
       ============================
       10 = 10 *)
    reflexivity.
  Qed.

  (* With arguments, [cbv] inlines only the functions specified *)
  Lemma cbv_arguments :
    Nat.double 5 = 11 - 1.
  Proof.
    (*
       ============================
       Nat.double 5 = 11 - 1 *)
    cbv [Nat.double]. (* now [Nat.double] gets inlined but [Nat.add] and
                         [Nat.sub] do not *)
    (*
       ============================
       5 + 5 = 11 - 1 *)
    reflexivity.
  Qed.

  (* You can pass multiple arguments *)
  Lemma cbv_multiple_arguments :
    Nat.double 5 = 11 - 1.
  Proof.
    (*
       ============================
       Nat.double 5 = 11 - 1 *)
    cbv [Nat.double Nat.sub].
    (*
       ============================
       5 + 5 = 10 *)
    reflexivity.
  Qed.

  (* You can also use a "-" sign to say "inline everything *except*
     these functions" *)
  Lemma cbv_exclude :
    Nat.double 5 = 11 - 1.
  Proof.
    (*
       ============================
       Nat.double 5 = 11 - 1 *)
    cbv - [Nat.add].
    (*
       ============================
       5 + 5 = 10 *)
    reflexivity.
  Qed.

  (* [cbv] works in hypotheses too *)
  Lemma cbv_in_hypothesis :
    forall n,
      Nat.double 5 = n ->
      n = 10.
  Proof.
    intros.
    (* n : nat
       H : Nat.double 5 = n
       ============================
       n = 10 *)
    cbv [Nat.double] in H.
    (* n : nat
       H : 5 + 5 = n
       ============================
       n = 10 *)
    lia.
  Qed.

  (* [cbv] can make your goal very messy if you have recursive calls to the
     same function or repeated uses of the function; it inlines whethet that
     makes the goal nicer or not. If [cbv] is giving you this kind of problem,
     try [cbn] instead. *)
  Lemma cbv_messy :
    forall n m,
      S n + m = n + S m.
  Proof.
    intros.
    (* n, m : nat
       ============================
       S n + m = n + S m *)
    cbv [Nat.add].
    (* n, m : nat
       ============================
       S ((fix add (n0 m0 : nat) {struct n0} : nat := match n0 with
                                                      | 0 => m0
                                                      | S p => S (add p m0)
                                                      end) n m) =
       (fix add (n0 m0 : nat) {struct n0} : nat := match n0 with
                                                   | 0 => m0
                                                   | S p => S (add p m0)
                                                   end) n (S m) *)
  Abort.
End CbvExamples.

(* cbn :
   The [cbn] tactic is similar to [cbv], except that it only inlines definitions
   if it thinks it can simplify the goal by doing so. This makes it very useful
   in cases where [cbv] inlines too aggressively.

   The syntax is exactly the same as [cbv]; it can either take no arguments or it
   can take some term names and not inline anything except things in the list.

   For inductive proofs about recursive functions, you almost always want to use
   [cbn] instead of [cbv], because using your inductive hypothesis is easiest if
   you don't inline the recursive calls.
 *)
Module CbnExamples.

  (* If everything becomes simpler when inlined, like if there are no variables,
     [cbn] has the exact same behavior as [cbv]. *)
  Lemma simple_cbn :
    Nat.double 5 = 11 - 1.
  Proof.
    (*
       ============================
       Nat.double 5 = 11 - 1 *)
    cbn.
    (*
       ============================
       10 = 10 *)
    reflexivity.
  Qed.

  (* Here's the same proof from the [cbv] entry that [cbv] made a mess of. [cbn]
     handles things much better; it only inlines the single round of [Nat.add]
     that can actually be simplified, and leaves the recursive calls and other
     occurences of [Nat.add] intact. *)
  Lemma cbn_not_messy :
    forall n m,
      S n + m = n + S m.
  Proof.
    intros.
    (* n, m : nat
       ============================
       S n + m = n + S m *)
    cbn [Nat.add].
    (* n, m : nat
       ============================
       S (n + m) = n + S m *)
    lia.
  Qed.
End CbnExamples.

(* induction :
   The [induction] tactic is Coq's built-in machinery for doing inductive proofs,
   along with [Inductive]. If you have some term [x] in context, and [x]'s type
   is an [Inductive], you can write [induction x] to set up an inductive proof.


   Some advice for inductive proofs:
     - If you're proving something about a [Fixpoint], the decreasing argument of
       the [Fixpoint] is probably the thing you want to do induction on.
     - If you're having trouble making use of your inductive hypothesis because
       it's too specific, you may need to make it "stronger" (less specific) by
       e.g. turning constants into variables in your lemma statement, or using
       more arguments in your recursive function.
     - Don't use [induction] multiple times in the same proof; if you feel the
       urge to do so, consider making multiple proofs.
     - Run [intros] *after* [induction] to sometimes avoid accidentally making
       your inductive hypothesis too weak.
 *)
Module InductionExamples.

  Lemma simple_nat_induction :
    forall n : nat,
      0 <= n.
  Proof.
    intros.
    (* n : nat
       ============================
       0 <= n *)
    induction n.
    (*
       ============================
       0 <= 0

       subgoal 2 (ID 9) is:
       0 <= S n *)

    (* Now we have two subgoals, corresponding to the two constructors in the
       [nat] inductive definition. In the first, [n] is 0, and in the second,
       [n] is the successor of another [nat]. From both definitions, our original
       [n] has disappeared; the [n] in the second case is actually the
       predecessor of the original. *)

    { (* subgoal 1 : 0 <= 0 *)
      reflexivity. }
    { (* subgoal 2 : 0 <= S n *)
      (* Note that in context here we now have an inductive hypothesis, stating
         that [0 <= n]. In this case, we don't need it, but often we will. *)
      lia. }
  Qed.

  (* You can use [induction] with any inductive datatype; here's a slightly more
     complex example using [list]. *)
  Lemma list_induction :
    forall (A : Type) (ls1 ls2 : list nat),
      length (ls1 ++ ls2) = length ls1 + length ls2.
  Proof.
    induction ls1; intros.
    { (* subgoal 1 : length (nil ++ ls2) = length nil + length ls2 *)
      rewrite app_nil_l.
      cbn [length].
      lia. }
    { (* subgoal 2 : length ((cons a ls1) ++ ls2)
                     = length (cons a ls1) + length ls2 *)
      rewrite <-app_comm_cons.
      cbn [length].
      rewrite IHls1. (* use of the inductive hypothesis! *)
      lia. }
  Qed.

  (* A common pitfall in inductive proofs in general (not just in Coq) is
     accidentally making your inductive hypothesis too weak. Most commonly, if
     your proof is about a recursive function and you need to be able to change
     an argument *other* than the one you're doing [induction] on, you'll need
     your inductive hypothesis to have a [forall] qualifier for the changing
     argument. This takes a little explanation, but is a really common way to get
     stuck and is worth being aware of.

     To make things more concrete, I'll demonstrate making a too-weak inductive
     hypothesis for a proof about the [seq] function, and how to fix it. *)

  (* Reproduction of the [seq] function from the standard list library; produces
     a list of [length] sequential natural numbers beginning with [start]. That
     is, [seq 3 4] will be the list [3;4;5;6]. *)
  Fixpoint seq (start len : nat) : list nat :=
    match len with
    | O => nil (* length 0; empty list *)
    | S len' =>
      (* increment start and decrease length *)
      cons start (seq (S start) len')
    end.

  (* Since the [seq] function decreases on [len], that's the argument we want to
     do [induction] on. But notice that [start] also changes between calls, and
     that's how we can run into problems. *)
  Lemma bad_inductive_hypothesis :
    forall start len,
      length (seq start len) = len.
  Proof.
    (*
      ============================
      forall start len : nat, length (seq start len) = len *)
    induction len.
    { (* subgoal 1 (len = 0) *)

      (* start : nat
         ============================
         length (seq start 0) = 0 *)
      cbn [seq length].

      (* start : nat
         ============================
         0 = 0 *)
      reflexivity. }
    { (* subgoal 2 (len = S len') *)

      (* start, len : nat
         IHlen : length (seq start len) = len
         ============================
         length (seq start (S len)) = S len *)

      (* Take a close look at the inductive hypothesis, and notice that it
         doesn't apply to just any [start]; it requires the specific argument
         we had to begin with, and that's going to be a problem. *)

      cbn [seq length].

      (* start, len : nat
         IHlen : length (seq start len) = len
         ============================
         S (length (seq (S start) len)) = S len *)

      (* Now our goal talks about starting with [S start], and our inductive
         hypothesis doesn't apply at all. We need the hypothesis to say
         [forall start]. *)
  Abort.

  (* The reason the previous proof failed is that [induction] automatically
     [intros] everything up to the variable you do induction on. In this case,
     we want to leave the [forall start] intact in our lemma statement. The
     easiest way to do this is simply to switch the order of the lemma
     arguments. *)
  Lemma good_inductive_hypothesis :
    forall len start,
      length (seq start len) = len.
  Proof.
    (*
      ============================
      forall len start : nat, length (seq start len) = len *)
    induction len.
    { (* subgoal 1 (len = 0) *)

      (*
         ============================
         forall start, length (seq start 0) = 0 *)
      intros.
      cbn [seq length].

      (*
         ============================
         0 = 0 *)
      reflexivity. }
    { (* subgoal 2 (len = S len') *)

      (* len : nat
         IHlen : forall start, length (seq start len) = len
         ============================
         forall start, length (seq start (S len)) = S len *)

      (* Our inductive hypothesis has a [forall] now! *)

      intros.
      cbn [seq length].

      (*  len : nat
          IHlen : forall start : nat, length (seq start len) = len
          start : nat
          ============================
          S (length (seq (S start) len)) = S len *)
      rewrite IHlen. (* ...and we can use it to prove the goal *)

      (*  len : nat
          IHlen : forall start : nat, length (seq start len) = len
          start : nat
          ============================
         S len = S len *)
      reflexivity. }
  Qed.
End InductionExamples.

(* lia :
   The [lia] tactic tries to solve your goal using linear arithmetic. It's
   pretty smart, and knows about minimum and maximum functions as well as the
   usual arithmetic operations. It takes no arguments.

   If your goal has [forall]s in it, always call [intros] before [lia].

   Coq does not include [lia] by default; you need to import it from the standard
   library with [Require Import Coq.micromega.Lia]. This import will give you
   [nia] as well.

   If it can't solve the goal, [lia] will fail and give you no clues about what
   preconditions it might be missing.

   Lots of the entries in this reference use [lia]; feel free to search for more
   examples.
 *)
Module LiaExamples.

  Lemma simple_lia :
    forall n m,
      n < m ->
      n <= m.
  Proof.
    intros.
    lia.
  Qed.

  Lemma more_complex :
    forall n m,
      5 < Nat.min n m ->
      3 < m.
  Proof.
    intros.
    lia.
  Qed.

  (* save yourself lots of work! *)
  Lemma annoying_algebra :
    forall n m,
      2 * n + m * (n + 3) = m * n + 3 * (m + n) - n.
  Proof.
    intros.
    lia.
  Qed.

  (* this goal is too much for lia *)
  Lemma lia_fails :
    forall a b,
      b <> 0 ->
      b * a + b * (b - 1) * a = b * b * a.
  Proof.
    intros.
    Fail lia. (* lia doesn't work! *)

    (* but, if we give it some help by letting it put all the [b] expressions in
       terms of [b-1], so it doesn't have to deal with the subtraction, it'll
       figure it out *)
    replace b with (S (b - 1)) by lia.
    replace (S (b - 1) - 1) with (b - 1) by lia.
    lia. (* now it works *)
  Qed.
End LiaExamples.

(* nia :
   The [nia] tactic is a stronger version of [lia]. It works on pretty much
   everything [lia] works on, and some things [lia] doesn't. It can be, however,
   much slower than [lia], so only use [nia] if [lia] doesn't work. No need to
   use a hammer to crack a nut.
 *)
Module NiaExamples.
  (* this is the goal from the [lia] entry that [lia] needed help to solve. [nia]
     requires no assistance. *)
  Lemma lia_fails :
    forall a b,
      b <> 0 ->
      b * a + b * (b - 1) * a = b * b * a.
  Proof.
    intros.
    nia.
  Qed.
End NiaExamples.

(* replace :
   The [replace] tactic lets you replace one expression in your goal or
   hypothesis with another expression, and leaves you a new subgoal to prove
   that the two are equal. The syntax is:

        replace <expression> with <expression>.

   If you want to do the [replace] in a hypothesis instead of a goal, use:

        replace <expression> with <expression> in <hypothesis>.

   ...and if you want to prove the new subgoal immediately:

        replace <expression> with <expression> by <tactic>.
        OR
        replace <expression> with <expression> in <hypothesis> by <tactic>.

  [replace] is most useful if you want to do a bunch of annoying algebra
  manipulations on a term that's buried inside an expression. By creating a new
  subgoal with only the algebra reasoning, you can prove the new goal with a
  tactic like [lia] and save yourself work.
 *)
Module ReplaceExamples.

  Lemma simple_replace :
    forall n ls,
      cons (S n - 1) ls = cons n ls.
  Proof.
    intros.
    (* n : nat
       ls : list nat
       ============================
       S n - 1 :: ls = n :: ls *)

    (* Logically, we know this is true because [S n - 1] equals [n]. [lia] could
       prove that, but it won't work to use [lia] here because the goal is in
       terms of lists. Instead, we create a new subgoal that [lia] can solve. *)
    replace (S n - 1) with n.

    (* n : nat
       ls : list nat
       ============================
       n :: ls = n :: ls

       subgoal 2 (ID 11) is:
       n = S n - 1 *)
    { reflexivity. }
    { lia. (* this is the subgoal left by [replace] *) }
  Qed.


  (* like [rewrite], you can use [by] to immediately prove the new subgoal. *)
  Lemma replace_by :
    forall n ls,
      cons (S n - 1) ls = cons n ls.
  Proof.
    intros.
    (* n : nat
       ls : list nat
       ============================
       S n - 1 :: ls = n :: ls *)

    replace (S n - 1) with n by lia.
    (* n : nat
       ls : list nat
       ============================
       n :: ls = n :: ls *)
    (* No new subgoal! *)
    reflexivity.
  Qed.

  Lemma replace_in_hypothesis :
    forall n m,
      n + n <= m ->
      2 * n <= m.
  Proof.
    intros.
    (* n, m : nat
       H : n + n <= m
       ============================
       2 * n <= m *)
    replace (n + n) with (2 * n) in H by lia.
    apply H.
  Qed.
End ReplaceExamples.
Clone this wiki locally