Proof Terms


What kind of an object is a proof? Following the propositions-as-types principle, Coq models proofs as terms. According to this principle, proofs are terms of a typed lambda calculus such that the unique type of a proof term is the proposition the proof term establishes, and proof checking amounts to type checking. In programming languages we have

program : type

while in proof systems we have

proof : proposition

In both cases we have a typing relations that relates terms (which may represent programs or proofs) with types (which may represent types of programs or propositions). The propositions-as-types principle is often called Curry Howard correspondence, a catchy phrase that neglects the contributions of researchers like de Bruijn and Martin-Löf.

Consider the following formulas:

forall X, X -> X

forall X Y, (X -> Y) -> (Y -> Z) -> X -> Z

If X and Y range over types (i.e., X Y: Type), then the formulas are polymorphic types that take polymorphic functions as values. The following terms do have theses types.

fun (X: Type) (x:X) => x

fun (X Y: Type) (f:X->Y) (g:Y->Z) (x:X) => g(f x)

Now consider the above formulas for the case where X and Y range over propositions (i.e., X Y: Prop). Then both formulas are propositions and the terms

fun (X: Prop) (x:X) => x

fun (X Y: Prop) (f:X->Y) (g:Y->Z) (x:X) => g(f x)

are proofs of these propositions (since they have the propositions as types). Let's check this out in Coq.

Lemma L1 : forall X: Prop, X -> X.
Proof.
exact (fun (X: Prop) (x:X) => x).
Qed.

Since Coq comes with type inference, we can omit the types in the proof term.

Goal forall X: Prop, X -> X.
exact (fun X x => x).

We can also construct the proof term with the following proof script.

Lemma L1' : forall X: Prop, X -> X.
Proof.
intros X x. apply x.
Qed.

Print L1'.

Note that the proof script describes the proof term in pre-linearized form. Exploiting the propositions-as-types design of Coq fully, we can also state and proof the lemma as follows.

Definition L1'' : forall X: Prop, X -> X := fun X x => x.

Print L1''.

So there is no real need to use commands like Lemma, Proof, and Qed. There is also no need to write proof scripts. Rather we can write definitions to state and prove lemmas. Note that the identifier of a lemma is bound to the proof of the lemma, not to the claim of the lemma. However, the claim of the lemma appears as the type of the identifier of the lemma.

Instead of exact one can also write apply. The apply tactic is much smarter than exact. The apply tactic takes a proof term as argument and tries to apply it to the current claim.

Finally, let's prove a more complicated claim both with a script and with a proof term.

Definition Contra := forall P Q : Prop, (~P -> ~Q) -> Q -> P.
Definition Peirce := forall P Q : Prop, ((P -> Q) -> P) -> P.

Lemma contra2peirce : Contra -> Peirce.
Proof.
intros C P Q. apply C.
intros f g. apply f. apply g.
intro p. apply False_ind. apply f. apply p.
Qed.

Lemma contra2peirce' : Contra -> Peirce.
Proof.
exact (fun C P Q => C P ((P->Q)->P) (fun f g => f (g (fun p => False_ind Q (f p))))).
Qed.

This example shows that the automation that comes with the apply tactic is helpful because it frees us from giving the propositional arguments of contra. The tactic tauto can prove any tautology of contructive propositional logic. Using it, we can shorten the proof script considerably.

Lemma contra2peirce'' : Contra -> Peirce.
Proof.
intros C P Q. apply C. tauto.
Qed.

It turns out that the proof term tauto finds is not as nice as the one we gave. See yourself.

Print contra2peirce''.


This page has been generated by coqdoc