15-312 Recitation #6: Curry-Howard
2002-10-02
Joshua Dunfield (joshuad@cs)
Carnegie Mellon University
- lambda
- Natural deduction
- Curry-Howard isomorphism
- `curry'
- Another natural deduction system...
- ...becomes another typing system: S and K
LAMBDA
In MinML, all functions are recursive, just as `fun' declares a
recursive function in SML. On the other hand, for our purposes
today it will be easier to separate the concepts of _function_
and _recursion_. The classic notation (going back to Church in
the 1930s) is
\lambda x.e alternatively rendered into ASCII as \x.e
In SML we would write this as fn x => e. Lambda gives a name only to
the argument, not to the function itself, so you can't write a recursive
function using \lambda.
The typing rule for \x.e is just the obvious simplification of
the rule for `fun'. ?:
G, x : tau1 |- e : tau2
----------------------------
G |- \x.e : tau1 -> tau2
NATURAL DEDUCTION
There are various standard systems for logic; we'll look at a
variant of "natural deduction" in which propositions (A, B, C) are
defined by the grammar
A ::= A => A | A /\ A | T | F | all x.A | x
Our judgment form is
G |- A Assuming the propositions in G, A is true
The rules are
--------------
G1, A, G2 |- A
G, A |- B G |- A => B G |- A
=> ----------- -------------------- (Modus ponens)
G |- A => B G |- B
G |- A G |- B G |- A /\ B G |- A /\ B
/\ --------------- ----------- -----------
G |- A /\ B G |- A G |- B
T,F ------
G |- T
G, x var |- A G |- all x.A
all ------------- ------------
G |- all x.A G |- {B/x} A
?: Do these look familiar? In particular, do the rules for =>
look familiar?
(Typing rules for ->, *, 1/int/bool, All)
What emerges is a _correspondence_ between propositions and
types, known as the Curry-Howard isomorphism:
Logic MinML
-------------- --------
=> ->
/\ *
\/ + (exercise)
T 1, ...
F 0
all All
~ _ -> 0
EXERCISE: From the rules for + (sum types) from lecture,
construct the rules for \/ in natural deduction.
A major difference between the systems remains: while the propositions
correspond to the types, nothing in the nat.d. system seems to
correspond to the terms. However, it is possible to modify the
nat.d. system to include explicit "proof terms". Then the nat.d.
system derives judgments asserting that a given proof term is a proof
of (or "a witness to") a given proposition. For instance, the
introduction rule for /\,
G |- A G |- B
---------------
G |- A /\ B
becomes
G |- M : A G |- N : B
-----------------------
G |- (M,N) : A /\ B
which can be explained as: Given a proof M of A, and a proof N of B,
the proof-pair (M,N) is a proof of A /\ B.
So in fact there is a second correspondence, between proofs and
programs.
EXAMPLE: curry
fun curry f = fn a => fn b => f(a, b)
curry = Fun a. Fun b. Fun c.\f.\a.\b. f(a,b)
Has type All a. All b. All c. (a * b -> c) -> (a -> (b -> c))
I.e.: we have a typing derivation
|- curry : All a. All b. All c. (a * b -> c) -> (a -> (b -> c))
Hence, the *corresponding proposition must be true* -- and provable
by a corresponding nat.d. derivation!
|- all a. all b. all c. (a /\ b => c) => (a => (b => c))
SUMMARY
Proposition <-> Type
Proof term <-> Program
Provability <-> Inhabitation (is there any value of the type?)
Just as |- F is not provable, |- e : 0 is not provable.
NOTE: We've seen examples of terms e such that |- e : 0, but they included
recursive functions, which we don't have here.
A SYSTEM EQUIVALENT TO NATURAL DEDUCTION
Consider just the (=>) fragment of the nat.d. system.
It is a theorem that the following system
---------------- K
|- A => (B => A)
-------------------------------------------- S
|- (A => (B => C)) => ((A => B) => (A => C))
|- A => B |- A
-------------------- MP
|- B
is complete with respect to it (anything derivable through the
old rules is derivable with S, K, MP).
This should ring some bells...
Now, what does this tell us about programs and types?
We can construct an analogous system with only prefabricated
"combinators" K and S (letting A, B, C stand for types):
-------------------- K
|- K : A => (B => A)
------------------------------------------------ S
|- S : (A => (B => C)) => ((A => B) => (A => C))
|- e : A => B |- e : A
------------------------ MP
|- e : B
Given a term K of type 'a -> 'b -> 'a and a term S of type
('a -> 'b -> 'c) -> ('a -> 'b) -> ('a -> 'c), _and no other
terms_, wherever we could derive a program of type tau in
the old typing system (with just rules for =>) we can derive
a program of type tau.
The terms can be written easily as lambdas:
K = \a.\b.a
S = \f.\g.\a.f a (g a)
Example: S K K has type 'a -> 'a.
- Unlambda: http://www.eleves.ens.fr:8080/home/madore/programs/unlambda/
- Program extraction: from a proof, get a program, but the program
may be very inefficient