The first example of a logic that we express in type theory is constructive logic. This logic is very close in spirit to the constructive principles underlying type theory, so expressing constructive logic amounts to interpreting the type constructors of the Nuprl logic as logical connectives using the informal semantics of evidence that was employed in the discussion of propositions as types.
The definitions in
figure express the
correspondence between logical connectives and type
constructors.
We treat as
, so we do not need an explicit definition for the
usual logical ``or'' in terms of the type constructors.
We could also include notations all3,
some3, all4, etc., for higher
numbers of variables of the same type, but
in practice two or three suffice most of the time.
The rules for the logical operators defined
in this way are exactly the
rules for constructive logic; see for example [Dummet 77].
We will discuss this at length in chapter 4 when we study proofs and rules;
however, one can see the intentions behind these definitions in
terms of an informal semantics of evidence of the kind mentioned
in chapter 1.
Consider first the definition and; there is evidence for A & B
precisely
when there is a pair, , such that a is evidence for A and b is
evidence for B.
Thus treating A & B as A # B is semantically correct from this
viewpoint.
Consider next. According to the
constructive interpretation,
is true when we have evidence for A or for B and when we
can tell from the evidence which of A or B it supports.
This is precisely the information that is available in the type
.
An element of the disjoint union is either
or
,
where a is in
A and b is in B and inl and inr are the
canonical injections into the disjoint sum type.
Next consider .
According to Brouwer [Brouwer 23],
the founder of
Intuitionism , an
implication is true when there is a method of
transforming any evidence
for the antecedent, A, into evidence for the consequent, B.
If A and B are represented by types,
then the function space,
, consists of objects which are
in fact
evidence for
.
Thus our definition is semantically correct.
The definition of the biconditional,
, is correct given that the definition of
implication is correct.
The constructive meaning of negation is delicate.
To say not A is to say that there is no evidence for A or that A will
never be proved.
In a type--theoretic context one
way to know this is to see that there are no members in A.
One might be tempted to translate
not A as A = Void, but type equality means
more than simply having the same members.
To say A is empty, we can say A is equivalent to void, i.e., that
#
. However,
is always inhabited,
so the only new content is
, which we take as our definition
of not.
Figure: Constructive Logic Connectives Expressed as Types
Now consider some , which is read ``we can find an x of type A
such that B is true.'' Intuitively there is evidence for an assertion of
existence when we have a witness, a in A, and
evidence, b, that
B is true with a substituted for free variable x
in B. We write this substitution as
. The dependent sum type
# B consists of pairs
with exactly these properties, so the definition is correct.
A universal statement, all , means
constructively that given any
element a of A we can find evidence for
.
This means that there is a procedure mapping elements a of A into
.
This is precisely what the dependent function space
provides, so this definition is also correct.
Finally, there should be no evidence for false, so the empty type, Void, is the right definition for it.
These definitions can be applied to atomic propositional forms such as the
types x = y in int or x < y to produce statements such as
all x:int.some y:int. x<y, which we read as ``for all integers x we
can find some integer y such that x is less than y''. It is also possible
to make more general statements,
such as all A:U1.all x:A.x=x in A.
This statement says that equality on every type is reflexive and
involves quantifying over all types in ; without the
hierarchy of universes it would not be possible to make such a statement
predicatively.
The logical operators can be used to state general results about constructive
predicate logic.
Give the identification of
propositions and types,
which we can make more
conspicuous by the definition prop == U1, we can assert
theorems about constructive propositional logic. Figure gives a
list of theorems that were expressed and proved
in Nuprl
.
Figure: Some Theorems of Constructive Propositional Logic
Statements in the predicate calculus are usually analyzed, following Frege
[Frege 1879], as operators applied to
propositional functions, where the term
propositional function describes a function that maps objects to propositions.
Given a type A, the propositional functions (of one argument) on A
are of the
type .
With this reading some basic facts from the predicate calculus are shown in
figure
.
Figure: Some Predicate Calculus Theorems