CIS 301: Logical Foundations of Programming Module: Natural Deduction Lecture: Curry-Howard Isomorphism Copyright 2013-2016, Dave Schmidt, John Hatcliff, Torben Amtoft, Robby. The syllabus and all lectures for this course are copyrighted materials and may not be used in other course settings outside of Kansas State University in their current form or modified form without the express written permission of one of the copyright holders. During this course, students are prohibited from selling notes to or being paid for taking notes by any person or commercial firm without the express written permission of one of the copyright holders.

CIS 301 --- Curry-Howard Isomorphism

Objectives n

n

n

Understand the intriguing correspondence between programs and natural deduction proofs for propositional logic Understand the types of program objects that provides evidence of the truth of propositions for different logical connectives Given a natural deduction proof, be able to sketch corresponding data types and program

CIS 301 --- Curry-Howard Isomorphism

Arguments / Proofs as Truth-Preserving Functions In our previous lectures, we have discussed an intuitive connection between arguments (proofs) and functions… Inputs

n

Premise1



Premise2

Premisen

An argument has… n n

Truth Preserving Inference Step

Truth Preserving Inference Step

Claim1

Claim2 Truth Preserving Inference Step

Conclusion

Outputs

CIS 301 --- Curry-Howard Isomorphism

n

n

premises as inputs conclusion as outputs

Let’s assume our premises are true… To get from the inputs to the output, we take small steps, and each step builds some new truth from some previous truths n

We can think of steps as analogous to commands in a procedure

Data Structures / Objects for Representing Truth If we accept this analogy, we must decide on the specific ways to represent “truth”, i.e., ways to represent the evidence that a particular proposition is true x2: p → q

x1: p ∧ q → r Premise1



Premise2

Truth Preserving Inference Step

Truth Preserving Inference Step

Claim1

Claim2 Truth Preserving Inference Step

Conclusion

x4: r CIS 301 --- Curry-Howard Isomorphism

x3: p

n

Premisen n

Our inputs and outputs represent different “types” of claims/truths Each input/output is a value “evidence” testifying a proposition of the corresponding type is true Value in x1 is evidence that p ∧ q → r is true

x1: p ∧ q → r

Data Structures / Objects for Representing Truth (Cont’d) If we accept this analogy, we must decide on the specific ways to represent “truth”, i.e., ways to represent the evidence that a particular proposition is true n

n

What would be appropriate evidence that p ∧ q is true? Recall: If p ∧ q is true… n n

n

n

n

…then p is true (∧e1 rule) …then q is true (∧e2 rule)

So evidence x: p ∧ q should be some sort of package from which we can also extract evidence x1: p and x2: q We’ll use Python for illustrations ... and Java, then Scala

CIS 301 --- Curry-Howard Isomorphism

Pair objects can provide evidence for propositions with the shape p ∧ q

(p, q)

From any pair object, we can extract evidence of p (i.e., we retrieve the first value of the pair) and we can extract evidence of q (i.e., we can retrieve the second value of the pair)

And-Introduction Rule P Q ∧i : ------P ∧ Q The andi function implements the introduction rule for And – it takes as arguments an evidence p and an evidence q and makes a composite piece of evidence for p ∧ q by storing them in a pair object.

CIS 301 --- Curry-Howard Isomorphism

def andi(p, q): return (p, q)

And-Elimination Rules The ande1 function can take any evidence of p ∧ q (i.e., a pair object) and return evidence for p

P ∧ Q ∧e1: ------P

def ande1(pq): return pq[0] The ande2 function can take any evidence of p ∧ q (i.e., a pair object) and return evidence for q

P ∧ Q ∧e2: ------Q CIS 301 --- Curry-Howard Isomorphism

def ande2(pq): return pq[1]

Proofs-as-Programs: ∧-Example sequent/formula

p ∧ q ⊢ q ∧ p

object type

{

def and_example(premise1): x1 = premise1 x2 = ande1(x1) x3 = ande2(x1) x4 = andi(x3, x2) return x4

1. 2. 3. 4. }

p ∧ q p q q ∧ p

premise ∧e1 1 ∧e2 1 ∧i 3 2 proof

program

1. The function parameter represents evidence that the premise is true 2 & 3. Elimination rules retrieve the individual pieces of evidence for p and q 4. The introduction rule constructs the pair (q, p), which is returned; the output is the evidence that the conclusion q ∧ p is true.

Unfortunately, Python lacks static types; we’ll use Java/Scala to clarify the relationship between sequent (formula) and type. CIS 301 --- Curry-Howard Isomorphism

Data Structures / Objects to Represent Truth -- Java If we accept this analogy, we must decide on the specific ways to represent “truth”, i.e., ways to represent the evidence that a particular proposition is true n

n

What would be appropriate evidence that p ∧ q is true? Recall: If p ∧ q is true… n n

n

Pair objects can provide evidence for propositions with the type/shape P ∧ Q

…then p is true (∧e1 rule) …then q is true (∧e2 rule)

So evidence x: p ∧ q should be some sort of package from which we can also extract evidence x1: p and x2: q

new Tuple2<>(p, q) public class Tuple2 { private final T1 v1; private final T2 v2; public Tuple2(final T1 x, final T2 y) { this.v1 = x; this.v2 = y; } public T1 _1() { return this.v1; } public T2 _2() { return this.v2; } }

CIS 301 --- Curry-Howard Isomorphism

Data Structures / Objects to Represent Truth -- Scala If we accept this analogy, we must decide on the specific ways to represent “truth”, i.e., ways to represent the evidence that a particular proposition is true n

n

What would be appropriate evidence that p ∧ q is true? Recall: If p ∧ q is true… n n

n

…then p is true (∧e1 rule) …then q is true (∧e2 rule)

So evidence x: p ∧ q should be some sort of package from which we can also extract evidence x1: p and x2: q

CIS 301 --- Curry-Howard Isomorphism

Pair objects can provide evidence for propositions with the type/shape P ∧ Q

Tuple2(p, q)

type ^[P, Q] = Tuple2[P, Q] This is optional, but in Scala, we can introduce a type called ∧ as alias of the pair type. The pair type accepts two type parameters, i.e., the types of its operands (P and Q here represent any types/formulae).

Data Structures / Objects to Represent Truth -- Scala If we accept this analogy, we must decide on the specific ways to represent “truth”, i.e., ways to represent the evidence that a particular proposition is true n

n

What would be appropriate evidence that p ∧ q is true? Recall: If p ∧ q is true… n n

n

…then p is true (∧e1 rule) …then q is true (∧e2 rule)

So evidence x: p ∧ q should be some sort of package from which we can also extract evidence x1: p and x2: q

CIS 301 --- Curry-Howard Isomorphism

Pair objects can provide evidence for propositions with the type/shape P ∧ Q

(p, q)

type ^[P, Q] = (P, Q) This is optional, but in Scala, we can introduce a type called ∧ as alias of the pair type. The pair type accepts two type parameters, i.e., the types of its operands (P and Q here represent any types/formulae).

And-Rules P Q ∧i : ------P ∧ Q

def andi[P, Q] (p: P, q: Q): P ^ Q = (p, q) The function return type gives a clue of what objects it is returning (the object shape is the formula it is constructing).

P ∧ Q ∧e1: ------P

def ande1[P, Q] (pq: P ^ Q): P = pq._1 The function parameter type limits the kinds of objects it accepts (i.e., a pair object).

P ∧ Q ∧e2: ------Q CIS 301 --- Curry-Howard Isomorphism

def ande2[P, Q] (pq: P ^ Q): Q = pq._2

Proofs-as-Programs: ∧-Example in Scala sequent/formula

p ∧ q ⊢ q ∧ p { 1. 2. 3. 4.

p ∧ q p q q ∧ p

premise ∧e1 1 ∧e2 1 ∧i 3,2

} proof

object type

def and_example[p, q] (premise1: p ^ q): q ^ p = { val x1 = premise1 val x2 = ande1(x1) val x3 = ande2(x1) val x4 = andi(x3,x2) /* return */ x4 } program

In this Scala version, it is clear that: i) the sequent/formula corresponds to the function type ii) the proof corresponds to the program ... and the Scala compiler type checks the program that it manipulates the right kinds of object types (formulae)! CIS 301 --- Curry-Howard Isomorphism

Proofs-as-Programs: ∧-Example in Scala sequent/formula

p ∧ q ⊢ q ∧ p

object type

def and_example[p, q] (premise1: p ^ q): q ^ p = { { val x1: p ^ q = premise1 1. p ∧ q premise val x2: p = ande1(x1) 2. p ∧e1 1 val x3: q = ande2(x1) 3. q ∧e2 1 val x4: q ^ p = andi(x3,x2) 4. q ∧ p ∧i 3,2 /* return */ x4 } } When variables are explicitly typed, they program proof expose the formulae in the proof steps! In this Scala version, it is clear that: i) the sequent/formula corresponds to the function type ii) the proof corresponds to the program ... and the Scala compiler type checks the program that it manipulates the right kinds of object types (formulae)! CIS 301 --- Curry-Howard Isomorphism

Assessment We have just uncovered a potential correspondence between proofs in Propositional Logic and programs n

n

n

n

Propositions correspond to certain Types/Classes in a programming language An object in the program corresponds to a piece of evidence the proposition corresponding to its type is true A proof of a sequent corresponds to a method/procedure that takes as inputs evidence of the premises and produces as outputs evidence of the conclusion Does this work for or and implies as well? n n

Yes! …but it works less well for negation

CIS 301 --- Curry-Howard Isomorphism

Curry-Howard Isomorphism The Curry-Howard Isomorphism represents a beautiful connection between logic and programming… n

n

Named after the logicians (Mr. Curry and Mr. Howard) who (in different settings) pointed out the correspondence between certain types of logics and programs Not all of Propositional Logic can be explained this way n

n

This only applies for Intuitionistic Logic

Intuitionistic Logic has the property that any time we have a proof of something, we have a way of building evidence for the claim that we proved Don’t be intimidated by proofs... They’re just programs!

CIS 301 --- Curry-Howard Isomorphism

Slogans Slogans associated with the Curry-Howard Isomorphism

Propositions

Types

Proofs

Functions/Programs

“evidence of truth”

Values/Objects

CIS 301 --- Curry-Howard Isomorphism

Evidence for Implies? The evidence representation for conjunction was pretty straightforward. How should we represent evidence for implication, P → Q ? n n

What would be appropriate evidence that P → Q is true? Intuitively, P → Q says… n n

n

n n

…if you give me evidence for P, …then I can give you evidence for Q

So we need an evidence transformer – something that can turn evidence of P into evidence of Q …that sounds like a function! Essentially, evidence of P → Q is a function that can turn evidence of P into evidence of Q n

note: the previous slides show that a sequent is also a function!

type ->[P, Q] = Function[P, Q] CIS 301 --- Curry-Howard Isomorphism

Evidence for Implies? The evidence representation for conjunction was pretty straightforward. How should we represent evidence for implication, P → Q ? n n

What would be appropriate evidence that P → Q is true? Intuitively, P → Q says… n n

n

n n

…if you give me evidence for P, …then I can give you evidence for Q

So we need an evidence transformer – something that can turn evidence of P into evidence of Q …that sounds like a function! Essentially, evidence of P → Q is a function that can turn evidence of P into evidence of Q n

note: the previous slides show that a sequent is also a function!

type ->[P, Q] = P => Q CIS 301 --- Curry-Howard Isomorphism

Implies-Introduction Rule { P assume ... Q } →i : -------------P → Q

A “sub-proof” that says, “Assuming P, I can prove Q” Signature of a subproof (function) that says “if you give me evidence for P, I can produce evidence of Q” The implyi function produces an implication of the form P → Q

def implyi[P, Q] (pDEDUCEq: P => Q): P -> Q = (p) => pDEDUCEq(p)

The produced implication is a lambda (function) that applies the “sub-proof” to construct Q from P CIS 301 --- Curry-Howard Isomorphism

Implies-Introduction Rule { P assume ... Q } →i : -------------P → Q

A “sub-proof” that says, “Assuming P, I can prove Q” Signature of a subproof (function) that says “if you give me evidence for P, I can produce evidence of Q” The implyi function produces an implication of the form P → Q

def implyi[P, Q] (pDEDUCEq: P => Q): P -> Q = pDEDUCEq type ->[P, Q] = P => Q Since -> is defined as =>, then we can return the function pDEDUCEq directly! CIS 301 --- Curry-Howard Isomorphism

Implies-Elimination Rule →e :

P → Q P -----------Q

→e takes two parameters: (1) an implication, and (2) the antecedent of the implication, and produces the implication consequent

def implye[P, Q] (pIMPLYq: P -> Q, p: P): Q = pIMPLYq(p)

The →e implementation simply apply/call the implication function P → Q to the antecedent P to produce the consequent Q

CIS 301 --- Curry-Howard Isomorphism

Proofs-as-Programs: Example1 p ∧ q → r, p → q, p



{ 1. 2. 3. 4. 5. 6.

p ∧ q → r p → q p q p ∧ q r

premise premise premise →e 2 3 ∧i 3 4 →e 1 5

}

CIS 301 --- Curry-Howard Isomorphism

r

def example1[p, q, r] (premise1: p ^ q -> r, premise2: p -> q, premise3: p): r = { val x1 = premise1 val x2 = premise2 val x3 = premise3 val x4 = implye(x2, x3) val x5 = andi (x3, x4) val x6 = implye(x1, x5) x6 }

Proofs-as-Programs: Example1 p ∧ q → r, p → q, p



{ 1. 2. 3. 4. 5. 6.

p ∧ q → r p → q p q p ∧ q r

premise premise premise →e 2 3 ∧i 3 4 →e 1 5

}

r

def example1[p, q, r] (premise1: p ^ q -> r, premise2: p -> q, premise3: p): r = { val x1: p ^ q -> r = premise1 val x2: p -> q = premise2 val x3: p = premise3 val x4: q = implye(x2, x3) val x5: p ^ q = andi (x3, x4) val x6: r = implye(x1, x5) x6 }

When variables are typed, they expose the formulae in the proof steps! CIS 301 --- Curry-Howard Isomorphism

Evidence for Or P ∨i1 : ------P ∨ Q Either[P, Q] Evidence for P ∨ Q

“P is True”: Evidence for P

Left[P, Q]

Q ∨i2 : ------P ∨ Q type V[P, Q] = Either[P, Q] Evidence for P ∨ Q has two cases: (1) a tag that says P is true (Left), and then evidence for P (2) a tag that says Q is true (Right), and then evidence for Q

“Q is True”: Evidence for Q

Right[P, Q] {

If our evidence is structured this way, we have enough info to choose the “right branch” in ∨e rule, and once we choose the correct branch, we have the “right info” to feed into it as an argument.

P assume { Q assume P ∨ Q ... R } ... R } ∨e : -----------------------------------R CIS 301 --- Curry-Howard Isomorphism

Or-Introduction Rules P ∨i1 : ------P ∨ Q

def ori1[P, Q] (p: P): P V Q = Left[P, Q](p)

Q ∨i2 : ------P ∨ Q

def ori2[P, Q] (q: Q): P V Q = Right[P, Q](q)

CIS 301 --- Curry-Howard Isomorphism

Or-Elimination Rule { P assume { Q assume P ∨ Q ... R } ... R } ∨e : -----------------------------------R

def ore[P, Q, R] (pORq: P V Q, pDEDUCEr: P => R, qDEDUCEr: Q => R): R = pORq match { case Left(p) => pDEDUCEr(p) case Right(q) => qDEDUCEr(q) } CIS 301 --- Curry-Howard Isomorphism

Proofs-as-Programs: ∨-Example q



{ 1. q 2. p ∨ q 3. (p ∨ q) ∨ r }

def or_example[p, q, r] (premise1: q): (p V q) V r = { val x1: q = premise1 premise val x2: p V q = ori2[p, q](x1) ∨i2 1 val x3: p V q V r = ori1[p V q, r](x2) ∨i1 2 x3 }

(p ∨ q) ∨ r

CIS 301 --- Curry-Howard Isomorphism

Proofs-as-Programs: Example2 p ∨ q → r, q



r

{ 1. 2. 3. 4.

p ∨ q → r q p ∨ q r

premise premise ∨i2 2 →e 1 3

}

CIS 301 --- Curry-Howard Isomorphism

def example2[p, q, (premise1: p V q premise2: q): r { val x1: p V q -> val x2: q val x3: p V q val x4: r x4 }

r] -> r, = r

= = = =

premise1 premise2 ori2(x2) implye(x1, x3)

Proofs-as-Programs: Example3 p, q ∧ p → r



q → r

{ 1. p 2. q ∧ p → r 3. { 4. q 5. q ∧ p 6. r } 7. q → r

premise premise assume ∧i 4 1 →e 2 5 →i 3

}

CIS 301 --- Curry-Howard Isomorphism

def example3[p, q, r] (premise1: p, premise2: q ^ p -> r): q -> r = { val x1: p = premise1 val x2: q ^ p -> r = premise2 val x3 = { (x4: q) => val x5: q ^ p = andi(x4, x1) val x6: r = implye(x2, x5) x6 } val x7: q -> r = implyi(x3) x7 }

Proofs-as-Programs: Example4 p → r, q → r ⊢ p ∨ q → r { 1. p → r 2. q → r 3. { 4. p ∨ q 5. { 6. p 7. r

premise premise assume assume →e 1 6

} 8. { 9. q 10. r } 11. r } 12. p ∨ q → r

assume →e 2 9 ∨e 4 5 8 →i 3

} CIS 301 --- Curry-Howard Isomorphism

def example4[p, q, r] (premise1: p -> r, premise2: q -> r): val x1: p -> r val x2: q -> r val x3 = { (x4: p V q) => val x5 = { (x6: p) => val x7: r x7 } val x8 = { (x9: q) => val x10: r x10 } val x11: r x11 } val x12: p V q -> r x12 }

p V q -> r { = premise1 = premise2

= implye(x1, x6)

= implye(x2, x9) = ore[p, q, r](x4, x5,x8) = implyi(x3)

Proofs-as-Programs: Example5 q



p → q ∧ p

{ 1. q 2. {

premise 3. p 4. q ∧ p

} 5. p → q ∧ p

assume ∧i 1 3 →i 2

}

CIS 301 --- Curry-Howard Isomorphism

def example5[p, q] (premise1: q): p -> (q { val x1: q = val x2 = { (x3: p) => val x4: q ^ p = x4 } val x5: p -> (q ^ p) = x5 }

^ p) = premise1 andi(x1,x3) implyi(x2)

Proofs-as-Programs: Example6 p → q → r ⊢ (p → q) → (p → r) { 1. p → q → r premise 2. { 3. p → q assume 4. { 5. p assume 6. q → r →e 1 5 7. q →e 3 5 8. r →e 6 7 } 9. p → r } 10. (p → q) → (p → r)

→i 4 →i 2

}

CIS 301 --- Curry-Howard Isomorphism

def example6[p, q, r] (premise1: p -> (q -> r)): (p -> q) -> (p -> r) { val x1: p -> (q -> r) = premise1 val x2 = { (x3: p -> q) => val x4 = { (x5: p) => val x6: q -> r = implye(x1, x5) val x7: q = implye(x3, x5) val x8: r = implye(x6, x7) x8 } val x9: p -> r = implyi(x4) x9 } val x10: (p -> q) -> (p -> r) = implyi(x2) x10 }

Curry-Howard Isomorphism n

Curry-Howard Isomorphism -- a relationship between mathematical proofs and computer programs n n

n

Propositions-as-Types Proofs-as-Programs

The relationship between proofs and programs is illustrated by the following judgments: n n

V: T V: T

V is a proof term for proposition T V is a program of type T (T can capture rich properties!)

These dual interpretations of the same judgment is the core of the Curry-Howard isomorphism n

For more information, see http://homepages.inf.ed.ac.uk/wadler/papers/pro positions-as-types/propositions-as-types.pdf

CIS 301 --- Curry-Howard Isomorphism

Acknowledgements n

The material in this lecture was developed by Zhi Zhang, Dr. John Hatcliff, and Dr. Robby

CIS 301 --- Curry-Howard Isomorphism

Propositions-as-Types n n n n

Conjunction = Product Type Disjunction = Sum Type Implication = Function Type …

CIS 301 --- Curry-Howard Isomorphism

Propositions-as-Types Conjunction = Product Type T1 ^ T2 -

T1 * T2

T1 and T2 are propositions v1 is a proof for T1 and v2 is a proof for T2 a proof of T1 ^ T2 is a pair of proofs (v1, v2)

CIS 301 --- Curry-Howard Isomorphism

-

T1 and T2 are types v1 is an expression with type T1 and v2 is an expression with type T2 the pair (v1, v2) is a program with type T1 * T2

Propositions-as-Types Disjunction = Sum Type T1 v T2 -

T1 + T2

T1 and T2 are propositions v1 is a proof for T1 and v2 is a proof for T2 either v1 or v2 can be a proof of T1 v T2

-

CIS 301 --- Curry-Howard Isomorphism

T1 and T2 are types T1 + T2 is the disjoint type sum of T1 and T2 v1 is an expression with type T1 and v2 is an expression with type T2 either v1 or v2 is an expression of type T1 + T2

Propositions-as-Types Implication = Function Type T1 -> T2 -

T1 -> T2

T1 and T2 are propositions T1 -> T2 means taking a proof of proposition T1 and producing a proof of proposition T2

CIS 301 --- Curry-Howard Isomorphism

-

T1 and T2 are types T1 -> T2 is a function type taking an expression of type T1 and producing an expression of type T2

NatDed-08-Curry-Howard-Isomorphism.pdf

Page 2 of 39. Objectives. n Understand the intriguing correspondence. between programs and natural deduction proofs. for propositional logic. n Understand the types of program objects that. provides evidence of the truth of propositions. for different logical connectives. n Given a natural deduction proof, be able to.

26MB Sizes 0 Downloads 123 Views

Recommend Documents

No documents