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