Formal Logic CPSC 509: Programming Language Principles Ronald Garcia∗ 13 September 2016 (Time Stamp: 11:03, Friday 14th October, 2016) 1 What is Logic? Logic is the process of systematically deducing new knowledge from assumed knowledge. That’s a mouthful, so let’s consider this in a slightly more...well hunger-inducing way:1 A prominent logician was trying to explain logic to his young son, and he said, ”Well, you know when we’re out for dinner, and the waiter says, ’So, who had the chicken?’, and Mommy says yes, and the waiter says, ’And who had the beef?’, and Daddy says yes, ... and then the waiter says, ’And you must have ordered the fish!’, without asking? That’s logic.” In this example the key event is that last one, when the waiter somehow gets from the assumed knowledge that the father and mother ordered the other dishes to the fact that the son ordered the fish. To do so, the waiter internally appealed to some other bits of assumed knowledge (e.g., that parents do not hoard all of the food) and in several steps of lightning-quick reasoning arrived at the answer to the question that need not be asked (“who had the fish?”). The steps of reasoning that the waiter took internally are called deductions and in the end the result is that assumptions about the beef and chicken eaters, combined with codes of civility together entail knowledge about the fish eater. In short, we use steps of deduction to establish entailment relationships between facts. 2 The Proof-theoretic Approach to Formal Logic This set of notes develops a particular system of formal logic, which allows us to precisely apply formal deduction steps to establish entailment relations in our system. In this context, formal refers to the fact that we are using precise symbols (or forms) to build an extremely systematic reasoning system that amounts to pure calculation. Before there were computers that could mechanize our symbolic reasoning, people did develop calculational methods but had to run them by hand (think long-division, for example). Here we do the same for logical reasoning: in practice we can implement this system on a computer, but since our goal is to internalize logical reasoning, we work on paper instead. If you’ve studied logic in a previous computer science course, you probably learned specifically about connectives like “and”, “or”, “not”, and “implies”, and how to use truth tables to determine whether a logical statement (often called a formula or proposition) is true or not. This approach to logic, called the model-theoretic approach is particularly well suited to reasoning about the behaviour of digital electronic circuits, which are built up from via and-gates, not-gates, and others. When extended to account for “objects in the universe” like numbers, tables, and trees, it also leads to powerful reasoning tools for quite abstract endeavors. ∗ c Ronald Garcia. Not to be copied, used, or revised without explicit written permission from the copyright owner. by William Lovas from a scenario due to Johan van Benthem. 1 Adapted 1 Time Stamp: 11:03, Friday 14th October, 2016 Logic However, truth tables in particular, and model theory in general, are not well suited to understanding how we typically write and read typical mathematical proofs, which say things like “assume n is a number:” or “thus n is prime.” Nor is it so helpful for debugging your prose-based proofs. And it does not have as good of an affinity with programming languages, which are much higher-level than digital circuits. This set of notes introduces a different approach to logic, one that is more well suited to thinking about the structure of mathematical proofs and also more closely connected to modern principles in programming languages. The key difference is that instead of focusing on truth, we focus on formal proofs, which you can view as data structures built up step-by-step from primitive reasoning principles. What’s amazing is how these formal proofs codify in precise terms many of the kinds of informal reasoning that mathematicians use. This is by design. 2.1 Formal (Logic) Proofs versus Informal (Math) Proofs The plan of attack is to present a proof theory2 for precisely and systematically reasoning about logical propositions. By starting with such a precise style, we can develop a strong sense of “what counts as a proof.” These proofs are based on a very very (i.e. painfully) strict set of rules. The nice thing about these rules is that they force the structure of your proof to very closely follow the structure of the proposition you intend to prove. This is good guidance at first in that it leaves little room for creativity (almost all you can do is change the order in which you construct the proof). In that way we hope to clarify what counts as a legal proof move, so that you need not worry about whether the steps of reasoning you are taking are “rigorous” enough. In essence, we’re showing how you could build a “type checker”, just like for C or Java, which tells you whether your proof is legal. In fact we can go further and check whether your proof is right, that is, a proof of the thing you intended to prove. This material is in fact the underpinnings for many computerized proof-checkers and automated theorem-provers. Since this course isn’t focused primarily on logic, we won’t push things quite that far, but you may get some hints at how you could build such software, even as we focus primarily on paper-based proofs of programming language properties. Bear in mind that our ultimate goal here is to work toward understanding how these formal models of proofs correspond to the kinds of proofs that you see in math textbooks. Proofs in mathematics tend to be more free-form, and take huge steps at a time, tying everything together in prose. This is quite a contrast to what you will see in this section. The way to think about the relationship between these two traditions of proof is to think of textbook mathematical proofs as “pseudocode”, and formal logic proofs as “actual code.” In principle you can take a mathematical proof and fill in all the details until you get a machine-checkable formal proof, just as you can take pseudocode from an algorithms textbook and tern it into a running C implementation. So paper proofs are “algorithms”, and formal proofs are “programs.” For a less formal approach to the same ideas, with a twist, I recommend the book “How to Prove It”. 3 Growing A Proof System Our main goal in these notes is to give you a good intuition for how proofs work, as well as some guardrails to push you in the direction of the proof you want. With that in mind, we start with a system that is strict but sufficient. The rules that we start with are way too strict though...if we used them exclusively, our proofs would be painfully big to write. A computer, on the other hand would really appreciate this small system because it makes it easy to both prove theorems and refute them, i.e., demonstrate that a proposition doesn’t hold because there cannot possibly be a proof for it. Think of our first system as low-level proof assembly language. It needs to be good enough to write all proofs, but not necessarily as friendly as we want for day-to-day proving. Then, we want to build at least a slightly higher-level language that lets us write proofs more succinctly, knowing that we could “compile” them to “assembly language”. In short we want at least a “FORTRANlike” proof language.3 2 There 3 you are many different ones could call it PROOFTRAN! Page 2 Time Stamp: 11:03, Friday 14th October, 2016 Logic 3.1 Verifications (and Uses) Let’s lay out our logical system. We’ll use formal notation, but explain it partly informally for now since your intuitions (and prior C.S. knowledge) will likely send you in the right direction.4 We will begin with propositional logic, which allows us to reason about opaque atomic propositions. That is to say, the system can’t directly reason about objects like chocolate or cookies, but we can use atomic symbols to stand in for propositional statements like “cookies are the best.” Here are some examples of atomic propositions: C ≡ Chocolate is delicious A ≡ Apples are delicious G ≡ Apples are good for you S ≡ Chocolate is good for you What makes them propositions is that they are statements that either “hold” or “do not hold”. It doesn’t matter which is the case at this point, but we want to reason about what would hold if other things did hold. We use atomic propositions to build up more complicated propositions. These are built using a variety of connectives which allow us to build up propositions from smaller ones. Here is an example proposition built up from our atomic ones: (C ∧ A ∧ G) ⊃ S This proposition represents the (obviously correct ,) statement “If chocolate is delicious and apples are delicious and apples are good for you, then chocolate is good for you.” In logic, we try to reason by using assumed propositions to verify other propositions. We call these steps of reasoning entailment. So our goal is to build a formal system in which we can formally describe entailment relations. 3.1.1 Syntax We start with the syntax of constructive propositional logic. Here’s the BNF first: A ∈ ATOMIC P ROP, p ∈ P ROP, p ::= A | > | ⊥ | p ∧ p | p ∨ p | p ⊃ p We use A to stand for any atomic proposition (like C, G, and so on). The symbol > represents propositional truth and ⊥ represents falsity. The symbol ∧ represents conjunction (“and”), and ∨ represents disjunction (“or”). Finally ⊃ represents implication (“if...then”). We’ll see that our system of proof theory gives precise and explicit meaning to propositions 3.1.2 Deduction Rules Now that we have defined the set of propositional formulas, we can establish what counts as proofs of propositions. In actuality, what we will define is a relation called entailment, which establishes the following: given the knowledge of certain truths, what other truths can we deduce (i.e., what truths are entailed by other truths)? To define entailment, we define the structure of proofs by laying out a set of deduction rules. Our deduction rules have the form: J1 · · · Jn J where J represents a judgment: i.e., a statement about a proposition p. The judgments on top of the horizontal bar are called premises, and the single judgment on the bottom is called the conclusion. Roughly speaking the rule says that if the premises can be established, then the conclusion follows immediately. 4 Some of the below text is stolen straight from the notes on inductive definitions. Page 3 Time Stamp: 11:03, Friday 14th October, 2016 Logic In logic, there are many judgments about propositions, like p true which says that p is true (more on this later), p@t, which says that p is true exactly at time t (which arises in temporal logic, a logic of truth over time), and p poss which says that p is true in some possible world (which arises in modal logic, a logic of necessity and possibility). In our system, we develop a simple propositional logic based on rules that tell us how to use the assumption that some propositions hold (regardless of whether or not they actually do) as a means to verify that some other proposition holds. This is the essence of hypothetical reasoning. In line with the above informal reasoning, we define our logic, we introduce two judgments: p ↓ pronounced “use p”, and p ↑ pronounced “verify p”. J ∈ J UDGMENT J ::= p ↑ | p ↓ We use arrows of this form because our proofs will typically take the form: p1 ↓ · · · pn ↓ .. .. p↑ which represents a proof tree with uses at the top and a verification at the bottom. We write the entailment relation p1 ↓ · · · pn ↓ ` p ↑ to say that we have such a proof tree, that is, we can use p1 , . . . , pn to verify p, or p1 , . . . , pn entails p. Each rule is defined in terms of the top-most logical connective that appears in a proposition. Ultimately we will build proofs by building proof trees, which you can think of as structures built up from “lego-blocks”, so very systematic. These lego-block structures have strict rules about how to combine them and how you know you are done. You can think of this as a data structure that has strict and easy to check, rules for building up data. We’ll introduce each of the rules one-by one, then summarize all the rules at the end. Atomic Propositions As we will see, each propositional connective introduces rules about how to use propositions that have that connective and rules about how to verify a proposition with a connective. Since atomic propositions are totally opaque, there’s not much that you can do...they represent abstract facts. Our basic principle is this “You can only verify an atomic proposition if you already have license to use it”, alternatively “Using an atomic proposition amounts to verifying it.” A↓ (↓↑) A↑ Conjunction A conjunction p1 ∧ p2 expresses the idea that both p1 and p2 hold. Without knowing anything about the structure of p1 or p2 , we can specify what it takes to verify p1 ∧ p2 : p1 ↑ p2 ↑ (∧↑) p1 ∧ p2 ↑ Similarly, without knowing the structure of either underlying proposition, we know how to use an assumption that the conjunction is true. First, if we can use the conjunction, then we can safely use either individual conjunct. p1 ∧ p2 ↓ (∧↓1) p1 ↓ p1 ∧ p2 ↓ (∧↓2) p2 ↓ At first it may seem odd that we can’t squeeze out both propositions at the same time with one rule, but somehow we have to represent two separate propositions. In this system, we are allowed to use our assumptions zero or more times, so we can use conjunction twice to get both pieces. We’ll see an example of this later. Page 4 Time Stamp: 11:03, Friday 14th October, 2016 Logic Disjunction A disjunction p1 ∨ p2 expresses the idea that one of p1 and p2 must hold. Following this intuition, we get two rules for verifying disjunction. p1 ↑ (∨↑1) p1 ∨ p2 ↑ p2 ↑ (∨↑2) p1 ∨ p2 ↑ In short, in order to verify a disjunction, it suffices to verify either one of the disjuncts. Now to use a disjunction, we must be able to deduce some conclusion regardless of which disjunct holds. p1 ↓ .. .. p1 ∨ p2 ↓ p3 ↑ p3 ↑ x p2 ↓ .. .. p3 ↑ y (∨↓x,y ) This rule is different from the previous ones that we have seen because two of the premises are hypothetical judgments of the form: p1 ↓ .. .. p2 ↑ Each of these stands for a subtree that may have p1 ↓ free at the top, and must conclude in p2 . Previous rules simply noted that p2 is directly above, so only focuses on the conclusion: a hypothetical judgment talks about judgments that may be used throughout the subproof. Given such a subproof, the rule for disjunction essentially introduces the hypothesis. This corresponds to temporarily supposing the premise and using it to deduce a conclusion. If successful, then we close the hypotheses, and mark them with an identifier, e.g., x, y, etc. which matches an identifier listed in the rule. Identifiers helps us keep track of which rule locally introduced (and dispatched) a hypothesis that was used internally in the proof. To use p1 ∨ p2 , we must produce two hypothetical judgments: the first supposes that we can use p1 and from it deduces p3 ; the second independently does the same for p2 . Thus, even though we do not know which of p1 and p2 will be available for us to use, we are prepared to deduce p3 from either. This ought to become clearer later when we write some proofs. Truthhood The > proposition is one of two propositional constants. It represents contentless truthhood. As such it has a rule that says that you can always verify truthness, with no assumptions needed. >↑ (>↑) There is no rule to use truthhood. Why not? Well, essentially because there is no “information content” to squeeze out of truthhood. In principle, we could introduce a rule for truthhood that matches the rule for atomic propositions: you can use > to verify >. However, that rule is totally redundant because you can always verify > already, with no assumptions. So you might as well never bother using truth. In contrast, for atomic propositions, you need license to use it in order to verify it. Falsehood The ⊥ proposition is one of two propositional constants, i.e. 0-ary propositional connectives. This connective represents absurdity, or falsehood. In essence this is something that can never happen. While it may sound odd to codify falsehood, it is actually quite useful to be able to talk about things that are absurd, i.e. “that could never be true” and other negative statements. We’ll find that ⊥ is exactly what we need to do that. By design, there is no direct rule for verifying ⊥. This is because we intend that it be impossible to verify ⊥ unless we have previously assumed it. This is in line with the idea that logic is reasoning under hypotheses: we can assume anything, regardless of whether it holds or not, and armed with such assumptions, we still deduce their implications. This is akin to “if pigs could fly:” we can make a lot of deductions from such a hypothetical, but we may never be able to take advantage of them. Page 5 Time Stamp: 11:03, Friday 14th October, 2016 Logic Though we cannot directly verify ⊥, we can use it. The basic idea is that “if you have license to use ⊥ then you’ve gone off the rails, everything has broken loose, etc., so you can verify anything.” ⊥↓ (⊥↓) p↑ This rule is hard to grasp on its own, but it fits within the larger reasoning framework. We need it to reason about negation, i.e. claims that certain propositions are impossible. This is called the principle of explosion, or ex falso quodlibet, which is latin for “from absurdity, anything follows.” The basic idea is that since we know that ⊥ can never be verified, than any hypothetical deduction that leads to it can never be used, so you might as well deduce any fact. Another way to think about it is this: think of ⊥ as the 0-ary version of disjunction ∨. If p1 ∨ p2 is verified , then we would know that one or the other of the two is verified. As such, p1 ∨ p2 can be used to deduce p if we can deduce it from both p1 and p2 . In contrast, if ⊥ is verified, then nothing is verified. Then ⊥ can be used to verify p right away, without verifying any side deductions. Indeed, ⊥ acts like an identity operator for ∨: (p ∨ ⊥) ⊃ p and p ⊃ (p ∨ ⊥). When an implication holds in both directions, we call it a “bi-implication”, and it means that the two propositions are logically equivalent. We’ll prove these theorems shortly, and you will then see that the first implication depends critically on (⊥↓). Similarly, truth > acts as identity for conjunction: p ⊃ (p ∧ >) and vice-versa, and the first proposition depends critically on (>↑). Implication To verify an implication, we must establish the conclusion assuming that we can use the assumption. This directly embodies hypothetical reasoning. x p1 ↓ .. .. p2 ↑ (⊃↑x ) p1 ⊃ p2 ↑ This rule, like (∨↓) is premised with a hypothetical judgment. In essence, this rule says that an implication internalizes the hypothetical proof p1 ` p2 as a proposition that may be mixed with others. This is quite analogous to how some programming languages have first-class functions, which may be treated as data. To use an implication, we must first verify the premise. If we have done so, then we have license to use the conclusion. p1 ⊃ p2 ↓ p1 ↑ (⊃↓) p2 ↓ The rough idea is that is if we knew the implication p1 ⊃p2 , it would mean that we knew some methodology for transforming a verification of the premise p1 into a verification of the conclusion p2 . Thus we can safely use the knowledge of p2 so long as we can verify p1 . Indeed, you can think of an implication as a form of function on proofs. We’ll hear more about this later in the course. Page 6 Time Stamp: 11:03, Friday 14th October, 2016 Logic We now summarize all of the rules of the logic. A↓ (↓↑) A↑ >↑ p1 ↑ p2 ↑ (∧↑) p1 ∧ p2 ↑ p1 ↑ (∨↑1) p1 ∨ p2 ↑ ⊥↓ (⊥↓) p↑ (>↑) p1 ∧ p2 ↓ (∧↓1) p1 ↓ p2 ↑ (∨↑2) p1 ∨ p2 ↑ x p1 ↓ .. .. p2 ↑ (⊃↑x ) p1 ⊃ p2 ↑ p1 ∧ p2 ↓ (∧↓2) p2 ↓ p1 ↓ .. .. p1 ∨ p2 ↓ p3 ↑ p3 ↑ x p2 ↓ .. .. p3 ↑ y (∨↓x,y ) p1 ⊃ p2 ↓ p1 ↑ (⊃↓) p2 ↓ Negation: a derived notion If you learned logic before, then you may have been shown the negation logical operator ¬ p, which means “not p.” In our system of logic, we do not introduce a primitive ¬ operator, but rather we define it in terms of notions that we already have: ¬p ≡ p ⊃ ⊥ In short, “not b” is defined to mean “if b held, then absurdity would follow.” In our setting, this is the essence of statements of falsehood: p ⊃ ⊥ represents a claim that there is a means by which a verification of p could be transformed into a verification of ⊥, but we know that there is no way to verify ⊥, therefore there is no way to verify p. We will find that this interpretation of negation can usefully guide our reasoning about propositions that we claim cannot be proven, especially with regards to what other propositions in turn cannot be proven either. 3.2 Precedence Conventions We typically do not want to place parentheses around every single subformula of a proposition. To avoid doing so, we adopt a common set of precedence conventions that appear throughout the literature: 1. Not has the highest precedence: for example, ¬ A ∨ B means (¬ A) ∨ B. 2. implication has the lowest precedence: for example, A ∨ C ⊃ D means (A ∨ C) ⊃ D. 3. implication associates to the right: for example, A ⊃ B ⊃ C ⊃ D means A ⊃ (B ⊃ (C ⊃ D)). 3.3 Examples Example 1. A ⊃ (B ⊃ (A ∧ B)) Here is what the formula looks like with minimal parentheses: A ⊃ B ⊃ A ∧ B And here is the proof: y x A↓ B↓ (↓ ↑) (↓ ↑) A↑ B↑ (∧ ↑) A ∧ B↑ (⊃ ↑)y B ⊃ (A ∧ B) ↑ (⊃ ↑)x A ⊃ (B ⊃ (A ∧ B) ↑ Page 7 Time Stamp: 11:03, Friday 14th October, 2016 Logic Example 2. (A ∧ B) ⊃ (B ∧ A) Here is what the formula looks like with minimal parentheses: A ∧ B ⊃ B ∧ A And here is the proof: x x A ∧ B↓ A ∧ B↓ (∧ ↓ 1) (∧ ↓ 2) A↓ B↓ (↓ ↑) (↓ ↑) A↑ B↑ (B ∧ A) ↑ (⊃ ↑x ) (A ∧ B) ⊃ (B ∧ A) ↑ Example 3. (A ⊃ B ∧ C) ⊃ (A ⊃ B) ∧ (A ⊃ C) Here is the proof: y x x z A ⊃ B ∧ C↓ A↓ A ⊃ B ∧ C↓ A↓ (⊃↓) (⊃↓) B ∧ C↓ B ∧ C↓ (∧↓1) (∧↓2) B↓ C↓ (↓↑) (↓↑) B↑ C↑ (⊃↑y ) (⊃↑z ) A ⊃ B↑ A ⊃ C↑ (∧↑) (A ⊃ B) ∧ (A ⊃ C) ↑ (⊃↑x ) (A ⊃ B ∧ C) ⊃ (A ⊃ B) ∧ (A ⊃ C) ↑ Example 4. (A ⊃ B) ∧ (B ⊃ C) ⊃ (A ⊃ C) Here is the proof: x (A ⊃ B) ∧ (B ⊃ C) ↓ x y (∧↓2) (A ⊃ B) ∧ (B ⊃ C) ↓ A ⊃ B↓ A↓ (∧↓1) (⊃↓) B ⊃ C↓ B↓ (⊃↓) C↓ (↓↑) C↑ (⊃↑y ) A ⊃ C↑ (⊃↑x ) (A ⊃ B) ∧ (B ⊃ C) ⊃ (A ⊃ C) ↑ Example 5. A ∧ (A ⊃ ⊥) ⊃ C This theorem makes necessary use of ⊥ to deduce C. Here is the proof, presented in steps. Step 0: .. .. A ∧ (A ⊃ ⊥) ⊃ C ↑ Page 8 Time Stamp: 11:03, Friday 14th October, 2016 Logic Step 1: Step 2: Step 2: x A ∧ (A ⊃ ⊥) ↓ .. .. C↑ (⊃↑x ) A ∧ (A ⊃ ⊥) ⊃ C ↑ x A ∧ (A ⊃ ⊥) ↓ x (∧↓1) A↓ A ∧ (A ⊃ ⊥) ↓ .. .. C↑ (⊃↑x ) A ∧ (A ⊃ ⊥) ⊃ C ↑ x x A ∧ (A ⊃ ⊥) ↓ A ∧ (A ⊃ ⊥) ↓ x (∧↓1) (∧↓2) A↓ A ⊃ ⊥↓ A ∧ (A ⊃ ⊥) ↓ .. .. C↑ (⊃↑x ) A ∧ (A ⊃ ⊥) ⊃ C ↑ Step 3: x A ∧ (A ⊃ ⊥) ↓ (∧↓1) A↓ x .. A ∧ (A ⊃ ⊥) ↓ .. (∧↓2) A ⊃ ⊥↓ A↑ x (⊃↓) ⊥↓ A ∧ (A ⊃ ⊥) ↓ .. .. C↑ (⊃↑x ) A ∧ (A ⊃ ⊥) ⊃ C ↑ Step 4: x A ∧ (A ⊃ ⊥) ↓ (∧↓2) A ⊃ ⊥↓ ⊥↓ Step 5: x A ∧ (A ⊃ ⊥) ↓ (∧↓1) A↓ (↓↑) A↑ x (⊃↓) A ∧ (A ⊃ ⊥) ↓ .. .. C↑ (⊃↑x ) A ∧ (A ⊃ ⊥) ⊃ C ↑ x A ∧ (A ⊃ ⊥) ↓ x (∧↓1) A ∧ (A ⊃ ⊥) ↓ A↓ (∧↓2) (↓↑) A ⊃ ⊥↓ A↑ (⊃↓) ⊥↓ (⊥↓) C↑ (⊃↑x ) A ∧ (A ⊃ ⊥) ⊃ C ↑ Notice that if you replace ⊥ in the above theorem with C, the result is still provable, but using (↓↑) instead of (⊥↓). But replacing ⊥ with B would not be provable. Many formulae that involve ⊥ could also be proven with an arbitrary atomic proposition in its place. Only for some proofs is the full power of ⊥ necessary. This is an example of such a formula, since ⊥ cannot be replaced with any arbitrary constant. Page 9 Time Stamp: 11:03, Friday 14th October, 2016 Logic 3.4 Refutations One of the nice things about the proof system that we’ve presented is that we can exploit it to show not only that some propositions are theorems, but also to show that some propositions are most definitely NOT theorems. This is called refuting a theorem. We give an example here, which also exposes an interesting aspect of the logic that we have defined. Consider the formula A ∨ ¬ A, which we would read informally as “A is true or false.” In the approach to logic that you may have learned in prior classes, the classical approach, this formula is true. In this course, the formula doesn’t hold. What the...??? Well, before we get into detail about this, let’s show that this is so. Suppose you try to verify this formula. First we translate ¬ A into its primitive form, and prepare to verify it: .. .. A ∨ (A ⊃ ⊥) ↑ At this point, there are only two rules that could possibly apply. Let’s try (∨↑1): .. .. A↑ (∨↑1) A ∨ (A ⊃ ⊥) ↑ Now we know we are stuck! In principle, we could use (↓↑) to get A ↓ on top, but in practice, when proving a theorem we only want to use that rule to finish a proof: it’s better to work toward the middle then fill in the gap. In this case we have no uses to work down from, so we can throw in the towel now. Ok, so if that doesn’t work, let’s try (∨↑2): .. .. A ⊃ ⊥↑ (∨↑2) A ∨ (A ⊃ ⊥) ↑ We can then apply (⊃↑x ): x A↓ .. .. ⊥↑ (⊃↑x ) A ⊃ ⊥↑ (∨↑2) A ∨ (A ⊃ ⊥) ↑ And we’re stuck again! The problem is that we want to meet in the middle, either using (↓↑) or (⊥↓) to bridge a gap. We can do neither of those things here, and we are out of options. Thus we know that the theorem cannot be proven. Thus A ∨ ¬ A is not a theorem of our logic. This may seem a bit unusual, but the intuition is that in this logic, any proof of A ∨ B must include enough information to establish which of A or B is in fact true (or at least which one was used to justify the theorem, in case both are in fact true). This gets at the very heart of constructive logic. We cannot simply claim that everything is true or false...we must figure out which one it is exactly. The proposition A ∨ ¬ A is called the law of the excluded middle (LEM), because it explicitly rules out the possibility that something is neither true nor false but something in the middle. This proposition cannot be proven in our logic because it demands that you demonstrate which one in particular is true: without more information than A, that’s not possible. By restricting ourselves in this way, all of our proofs have constructive content. Given a disjunction, a proof must commit to one of the disjuncts. Page 10 Time Stamp: 11:03, Friday 14th October, 2016 Logic Even though the LEM is not provable, it is not false: ¬ ¬(A ∨ ¬ A) is a theorem. Here is the proof: y A↓ (↓↑) A↑ x (∨↑1) ¬(A ∨ ¬ A) ↓ A ∨ ¬A↑ (⊃↓) ⊥↑ (⊥↓) ⊥↑ (⊃↑y ) ¬A↑ x (∨↑2) ¬(A ∨ ¬ A) ↓ A ∨ ¬A↑ (⊃↓) ⊥↓ (⊥↓) ⊥↑ (⊃↑x ) ¬ ¬(A ∨ ¬ A) ↑ Let’s unpack this proposition: it says that if you had a proof of (A ∨ ¬ A) ⊃ ⊥, then you would be in trouble, because ((A ∨ ¬ A) ⊃ ⊥) ⊃ ⊥. Considering these two formula, the LEM and its double-negation, tells us essentially that we do not have a general method for proving which of a proof or its negation holds (i.e., LEM is not a theorem), but we could never prove that neither a formula nor its negation is possible (i.e., double-negation of LEM is a theorem). It’s worth noting, though, that replacing all of the (implicit) instances of ⊥ with C, getting ((A ∨ (A ⊃ C)) ⊃ C) ⊃ C, still yields a provable a theorem (what changes must you make to the proof?). In essence, ⊥ in particular is not needed to make sense of this theorem: any atomic proposition will do instead! On a related note, another proof that you cannot prove is “double-negation elimination” (DNE): we can prove that any verifiable proposition is not false (A ⊃ ¬ ¬ A holds), but knowledge that a proposition is not false does not tell us how to verify that proposition holds (¬ ¬ A ⊃ A does not hold). Both LEM and DNE can be proven in classical logic, which is focused more on establishing Platonic abstract truth rather than general constructive methodology. In essence, A ∨ ¬ A does not constructively hold because there does not exist a constructive method that for all possible A computes which one of the two is true. More To Come! A Classical Logic If you’ve learned about logic before, then in all likelihood, you were taught classical logic. This section extends our logical system to classical logic, just so that you have some understanding of the difference. In essence, classical logic supports more reasoning from falsehood than constructive logic. As such we introduce two new judgments: p false, which is used to assume that a proposition p is indeed false, and #, which expresses that a contradiction has been deduced. In addition to our new judgments, we add two new rules and modify two of our previous rules. The first new rule determines how to deduce a contradiction. p false p ↑ (contra) # The (contra) rule says that one can deduce a contradiction by verifying any proposition that has previously been assumed false. The second rule introduces our primary mechanism for classically verifying more propositions. k p false .. .. # (pbc)k p↑ Page 11 Time Stamp: 11:03, Friday 14th October, 2016 Logic This rule captures proof by contradiction: it is sufficient to verify a proposition by merely assuming it is false and deriving a contradiction. Finally we modify two of our previous rules: specifically the two rules for using disjunctions and false. In particular, each can now be used to deduce contradictions, i.e.: p1 ↓ .. .. p1 ∨ p2 ↓ # # x p2 ↓ .. .. # y (∨↓x,y ) ⊥↓ (⊥↓) # Adding these mechanisms to constructive logic is sufficient to get you classical logic. To demonstrate, here is a proof of the law of excluded middle. You can see here that the proof makes essential use of proof by contradiction. x A↓ (↓↑) A↑ (∨↑1) k A ∨ ¬ A false A ∨ ¬A↑ (contra) # h (pbc) ⊥↑ (⊃↑x ) ¬A↑ (∨↑2) k A ∨ ¬ A false A ∨ ¬A↑ (contra) # k (pbc) A ∨ ¬A↑ This proof is quite peculiar compared to some of our earlier proofs. First, notice the use of proof-byh contradiction that introduces an assumption ⊥ false which is never used. This allows us to introduce whatever proposition we desire (here ⊥). As such, we can see that A ∨ (A ⊃ C) is also verifiable classically. Notice as well that ultimately we verify this disjunction without producing a definitive verification of either disjunction. indeed there are two instances of disjunction verification, but each is fundamentally dependent on our assumption that A ∨ ¬ A is false. This reasoning is very similar to our “double-negation” reasoning, except that proof-by-contradiction transforms double-negations into affirmations. What makes Constructive Logic “Constructive” One of the key differences between constructive logic and classical logic is exactly the global nature of disjunctions, especially verifications of disjunctions. In fact, in constructive logic, it is a metatheorem (i.e. theorem about the system, as opposed to a theorem proven in the system) that: .. .. .. .. .. .. Theorem 1. If A ∨ B ↑ then either A ↑ or B ↑. What that means is that if you give me a proof that verifies a disjunction, then I can systematically deconstruct it and find inside a standalone proof of one of the two disjuncts. As we saw in the above example, this metatheorem doesn’t hold in classical logic: you can verify a disjunction without ever definitively verifying one of the disjuncts along the way. This may matter even more when we get to first-order logic: constructive proof of the existence of a mathematical object with certain properties must provide that very object. Classical existence proofs need not do so: they may simply prove that it’s not possible that such an object doesn’t exist. The key point in favour of classical logic is that in practice we often you don’t care about which disjunct holds (or which mathematical object has a property): in essence we often just want to know that something is ”not false”, without worrying about constructive evidence that it is verified. That’s where classical logic shines. Page 12
© Copyright 2026 Paperzz