Logic ----- Notation Natural deduction -- Gentzen 1935 A and B are propositions (logical formulae) Can make judgments, such as "A is true". Want to define a formal system for proving these judgments. Could define such a proof system for other judgments: - "A is true" - "A is false" - "M is a proof of A" - "e has type T" - "K knows A" (epistemic logic) How do you define the meaning of conjunction? (A & B) true It's true when I can prove it's true. This leands to an _introduction rule_: A true B true ---------------- A & B true The meaning of a connector is given by its introduction rule(s). Another example, OR: (A | B) true Introduction rules for |: A true ------------ A | B true B true ------------ A | B true These rules define the meaning of conjunction and disjunction operators. These rules describe what can be _proved_ in the system. Note that there could be statements that are true but cannot be proved (cf. Godel's first incompleteness theorem). There could also be statements that are false. These statements also cannot be proved. In many logics (those with enough expressive power) you _cannot_ prove that a statement is false. Now, how do we use the knowledge that A & B is true? Elimination rule(s): A & B true --------------- A true A & B true --------------- B true The elimination rule for OR is more complicated: [A true] [B true] ------ ------ ... ... ------- ------- C true C true A | B true ------------------------------- C true This says, - if we can PROVE "A | B true" and - if we can PROVE "C true" ASSUMING we can prove "A true" - if we can PROVE "C true" ASSUMING we can prove "B true" - THEN, we can PROVE "C true" This notation is unwieldly, so we can rewrite it as follows: A true |- C true B true |- C true A | B true -------------------------------------------------- C true "|-" is called a turnstyle. This form of judgment is called a _sequent_. The general form is: A1, ..., An |- B We add the following axiom to allow us to use an assumption. P |- P Now, let's define the meaning of implication: => Introduction rule: if we assume A true, we can derive B true [A true] -------- ... --------- B true ---------------- A => B true "A => B true" can be proved if we can prove "B true" assuming "A true" With the change of notation: A true |- B true ------------------- A => B true Elimination rule: A => B true A true ---------------------- B true This is modus ponens. Curry-Howard isomorphism ------------------------ This is a very cool theoretical result. Haskell Curry 1934, 1958 -- deduction systems correspond to combinatory logic William Howard 1969 -- Gentzen's natural deduction can be interpreted as typed lambda calculus As I said when we introduced inference rules, the notation derives from logic. Indeed each typing judgment is a logical statement. Here again is the introduction rule for AND: A true B true --------------- A ^ B true Consider the following rule for typing pairs: G |- e1 : T1 G |- e2 : T2 --------------------------- G |- (e1, e2) : (T1, T2) Observe, that the rules have the same structure. And the elimination rules: A ^ B true ---------- A true A ^ B true ---------- B true G |- e : (T1, T2) ------------------ G |- fst e : T1 G |- e : (T1, T2) ------------------ G |- snd e : T2 Observe again, that the rules have the same structure. Now, the rules for implication. A |- B --------- A => B A => B A ----------- B And functions abstraction and application: G, x : T1 |- e : T2 -------------------------- G |- \x : T1 . e : T1 -> T2 G |- e1 : T1 -> T2 G |- e2 : T1 ----------------------------------- G |- e1 e2 : T2 Again, the rules have the same structure. The essence of the C-H isomorphism is that the structure of the proof trees for logical judgments is the same as the structure of the proof trees for type-checking. A _type_ corresponds to a _proposition_. A _term_ (i.e., a program) corresponds to a _proof_. If a term type-checks with a given type, there is a proof of the corresponding proposition. The connection is as follows: types ~ propositions terms ~ proofs type-checking ~ proof-checking Specifically: product types ~ conjunction (AND) function types ~ implication (=>) sum types ~ disjunction (OR) [below] If I can write a term with a given type; that is, there is a typing derivation for that term -- a proof that the term has the given type. Then, I also have a proof of the corresponding proposition. Sum types --------- The analogy for disjunction is _sum types_. A value of type T1 + T2 is either a T1 or a T2. Sum types are _disjoint unions_ or _tagged unions_. The expression "in1 e" _injects_ a term "e" of type T1 into the type T1 + T2. The expression "in2 e" _injects_ a term "e" of type T2 into the type T1 + T2. Here are the typing rules. G |- e1 : T1 --------------------- G |- in1 e1 : T1 + T2 G |- e2 : T2 --------------------- G |- in2 e2 : T1 + T2 These have the same structure as the introduction rules for |. The elimination rule is a "case" expression: G |- e : T1+T2 G, x: T1 |- e1 : T G, x: T2 |- e2 : T ---------------- G |- case e of in1 x => e1 | in2 x => e2 : T Theorem provers --------------- This correspondence is the basis of automated theorem provers. The idea is that the prover will represent the proposition as a type. To prove the proposition, you write an expression with the correct type. You can do this directly, but the usually you do this in an interactive mode where you deal with logical propositions. There are many such provers. Coq is one. Isabelle. Twelf. Sometimes called "proof assistants" rather the theorem provers, because they're interactive. PA helps formalize what you're trying to prove (definitions, axioms, theorems). General language for stating propositions (based on lambda). PA helps with checking and creating proofs. Proof checking = type checking. proof = term proposition = type proof checking = type checking proof search = term search (program synthesis) program/algorithm = term specification = type program = proof Type checking is decidable. Proof search is _not_. Need a human. Here's an example of using Coq: $ coqtop Welcome to Coq 8.4pl2 (May 2013) Coq < Goal forall A B: Prop, A -> A \/ B. 1 subgoal ============================ forall A B : Prop, A -> A \/ B Unnamed_thm0 < intros. 1 subgoal A : Prop B : Prop H : A ============================ A \/ B Unnamed_thm0 < left. 1 subgoal A : Prop B : Prop H : A ============================ A Unnamed_thm0 < assumption. No more subgoals. Unnamed_thm0 < Qed. intros. left. assumption. Unnamed_thm0 is defined ------------------------------- To use a PA, the user interacts with the system by applying _tactics_ to build a term. The term is the _proof_ of the theorem. Some tactics (e.g., auto), synthesize terms or evaluate terms (simpl).