(** * ProofObjects: The Curry-Howard Correspondence *)
(** "_Algorithms are the computational content of proofs_."  --Robert Harper *)
Set Warnings "-notation-overridden,-parsing".
Require Export IndProp.
(** We have seen that Coq has mechanisms both for _programming_, using inductive data types like [nat] or [list] and functions over these types, and for _proving_ properties of these programs, using inductive propositions (like [ev]), implication, universal quantification, and the like.  So far, we have mostly treated these mechanisms as if they were quite separate, and for many purposes this is a good way to think.  But we have also seen hints that Coq's programming and proving facilities are closely related. For example, the keyword [Inductive] is used to declare both data types and propositions, and [->] is used both to describe the type of functions on data and logical implication.  This is not just a syntactic accident!  In fact, programs and proofs in Coq are almost the same thing.  In this chapter we will study how this works.  We have already seen the fundamental idea: provability in Coq is represented by concrete _evidence_.  When we construct the proof of a basic proposition, we are actually building a tree of evidence, which can be thought of as a data structure.  If the proposition is an implication like [A -> B], then its proof will be an evidence _transformer_: a recipe for converting evidence for A into evidence for B.  So at a fundamental level, proofs are simply programs that manipulate evidence. *)
(** Question: If evidence is data, what are propositions themselves?  Answer: They are types!  Look again at the formal definition of the [ev] property.  *)
Print ev.
(* ==> Inductive ev : nat -> Prop := | ev_0 : ev 0 | ev_SS : forall n, ev n -> ev (S (S n)). *)
(** Suppose we introduce an alternative pronunciation of "[:]". Instead of "has type," we can say "is a proof of."  For example, the second line in the definition of [ev] declares that [ev_0 : ev 0].  Instead of "[ev_0] has type [ev 0]," we can say that "[ev_0] is a proof of [ev 0]." *)
(** This pun between types and propositions -- between [:] as "has type" and [:] as "is a proof of" or "is evidence for" -- is called the _Curry-Howard correspondence_.  It proposes a deep connection between the world of logic and the world of computation:  propositions  ~  types proofs        ~  data values  See [Wadler 2015] for a brief history and an up-to-date exposition.  Many useful insights follow from this connection.  To begin with, it gives us a natural interpretation of the type of the [ev_SS] constructor: *)
Check ev_SS.
(* ===> ev_SS : forall n, ev n -> ev (S (S n)) *)
(** This can be read "[ev_SS] is a constructor that takes two arguments -- a number [n] and evidence for the proposition [ev n] -- and yields evidence for the proposition [ev (S (S n))]." *)
(** Now let's look again at a previous proof involving [ev]. *)
(** We can now see that this feature is a trivial consequence of the status the Coq grants to proofs and propositions: Lemmas and hypotheses can be combined in expressions (i.e., proof objects) according to the same basic rules used for programs in the language. *)
(* ################################################################# *)
(** * Proof Scripts *)
(** The _proof objects_ we've been discussing lie at the core of how Coq operates.  When Coq is following a proof script, what is happening internally is that it is gradually constructing a proof object -- a term whose type is the proposition being proved.  The tactics between [Proof] and [Qed] tell it how to build up a term of the required type.  To see this process in action, let's use the [Show Proof] command to display the current state of the proof tree at various points in the following tactic proof. *)
(** At any given moment, Coq has constructed a term with a "hole" (indicated by [?Goal] here, and so on), and it knows what type of evidence is needed to fill this hole.  Each hole corresponds to a subgoal, and the proof is finished when there are no more subgoals.  At this point, the evidence we've built stored in the global context under the name given in the [Theorem] command. *)
(** Tactic proofs are useful and convenient, but they are not essential: in principle, we can always construct the required evidence by hand, as shown above. Then we can use [Definition] (rather than [Theorem]) to give a global name directly to a piece of evidence. *)
Definition ev_4''' : ev 4 :=
ev_SS 2 (ev_SS 0 ev_0).
(** All these different ways of building the proof lead to exactly the same evidence being saved in the global environment. *)
Print ev_4.
(* ===> ev_4    =   ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
Print ev_4'.
(* ===> ev_4'   =   ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
Print ev_4''.
(* ===> ev_4''  =   ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
Print ev_4'''.
(* ===> ev_4''' =   ev_SS 2 (ev_SS 0 ev_0) : ev 4 *)
(** **** Exercise: 1 star (eight_is_even)  *)
(** Give a tactic proof and a proof object showing that [ev 8]. *)

Theorem ev_8 : ev 8.