Program Proof
Program Proof
Contents
0 Introduction 10
0.1 Proving instead of testing . . . . . . . . . . . . . . . . . . . . . . 10
0.2 Typing as proving . . . . . . . . . . . . . . . . . . . . . . . . . . 11
0.3 Checking programs . . . . . . . . . . . . . . . . . . . . . . . . . . 13
0.4 Checking proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
0.5 Searching for proofs . . . . . . . . . . . . . . . . . . . . . . . . . 15
0.6 Foundations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
0.7 In this course . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
0.8 Other references on programs and proofs . . . . . . . . . . . . . . 17
0.9 About this document . . . . . . . . . . . . . . . . . . . . . . . . . 17
2 Propositional logic 41
2.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.1.1 From provability to proofs . . . . . . . . . . . . . . . . . . 41
2.1.2 Intuitionism . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.1.3 Formalizing proofs . . . . . . . . . . . . . . . . . . . . . . 43
2.1.4 Properties of the logical system . . . . . . . . . . . . . . . 44
2.2 Natural deduction . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.2.1 Formulas . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.2.2 Sequents . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.2.3 Inference rules . . . . . . . . . . . . . . . . . . . . . . . . 46
2.2.4 Intuitionistic natural deduction . . . . . . . . . . . . . . . 46
2.2.5 Proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.2.6 Fragments . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.2.7 Admissible rules . . . . . . . . . . . . . . . . . . . . . . . 49
2.2.8 Definable connectives . . . . . . . . . . . . . . . . . . . . 52
2.2.9 Equivalence . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.2.10 Structural rules . . . . . . . . . . . . . . . . . . . . . . . . 54
2.2.11 Substitution . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.3 Cut elimination . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.3.1 Cuts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
2.3.2 Proof substitution . . . . . . . . . . . . . . . . . . . . . . 57
2.3.3 Cut elimination . . . . . . . . . . . . . . . . . . . . . . . . 58
2.3.4 Consistency . . . . . . . . . . . . . . . . . . . . . . . . . . 61
2.3.5 Intuitionism . . . . . . . . . . . . . . . . . . . . . . . . . . 62
2.3.6 Commutative cuts . . . . . . . . . . . . . . . . . . . . . . 63
2.4 Proof search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2.4.1 Reversible rules . . . . . . . . . . . . . . . . . . . . . . . . 65
2.4.2 Proof search . . . . . . . . . . . . . . . . . . . . . . . . . . 66
2.5 Classical logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
2.5.1 Axioms for classical logic . . . . . . . . . . . . . . . . . . 70
2.5.2 The intuition behind classical logic . . . . . . . . . . . . . 72
2.5.3 A variant of natural deduction . . . . . . . . . . . . . . . 74
2.5.4 Cut-elimination in classical logic . . . . . . . . . . . . . . 76
2.5.5 De Morgan laws . . . . . . . . . . . . . . . . . . . . . . . 77
2.5.6 Boolean models . . . . . . . . . . . . . . . . . . . . . . . . 81
2.5.7 DPLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
2.5.8 Resolution . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
2.5.9 Double-negation translation . . . . . . . . . . . . . . . . . 91
2.5.10 Intermediate logics . . . . . . . . . . . . . . . . . . . . . . 93
2.6 Sequent calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
2.6.1 Sequents . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
2.6.2 Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
2.6.3 Intuitionistic rules . . . . . . . . . . . . . . . . . . . . . . 98
2.6.4 Cut elimination . . . . . . . . . . . . . . . . . . . . . . . . 98
2.6.5 Proof search . . . . . . . . . . . . . . . . . . . . . . . . . . 98
2.7 Hilbert calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
2.7.1 Proofs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
2.7.2 Other connectives . . . . . . . . . . . . . . . . . . . . . . 104
2.7.3 Relationship with natural deduction . . . . . . . . . . . . 105
2.8 Kripke semantics . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
CONTENTS 4
6 Agda 268
6.1 What is Agda? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268
6.1.1 Features of proof assistants . . . . . . . . . . . . . . . . . 268
6.1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . 272
6.2 Getting started with Agda . . . . . . . . . . . . . . . . . . . . . . 272
6.2.1 Getting help . . . . . . . . . . . . . . . . . . . . . . . . . 272
6.2.2 Shortcuts . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
6.2.3 The standard library . . . . . . . . . . . . . . . . . . . . . 274
6.2.4 Hello world . . . . . . . . . . . . . . . . . . . . . . . . . . 274
6.2.5 Our first proof . . . . . . . . . . . . . . . . . . . . . . . . 275
6.2.6 Our first proof, step by step . . . . . . . . . . . . . . . . . 276
6.2.7 Our first proof, again . . . . . . . . . . . . . . . . . . . . 278
6.3 Basic Agda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
6.3.1 The type of types . . . . . . . . . . . . . . . . . . . . . . . 280
6.3.2 Arrow types . . . . . . . . . . . . . . . . . . . . . . . . . . 280
6.3.3 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
6.3.4 Postulates . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
6.3.5 Records . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
6.3.6 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
6.4 Inductive types: data . . . . . . . . . . . . . . . . . . . . . . . . . 283
6.4.1 Natural numbers . . . . . . . . . . . . . . . . . . . . . . . 284
6.4.2 Pattern matching . . . . . . . . . . . . . . . . . . . . . . . 284
6.4.3 The induction principle . . . . . . . . . . . . . . . . . . . 286
6.4.4 Booleans . . . . . . . . . . . . . . . . . . . . . . . . . . . 288
6.4.5 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
6.4.6 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
6.4.7 Vectors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
6.4.8 Finite sets . . . . . . . . . . . . . . . . . . . . . . . . . . . 291
6.4.9 Integers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 292
6.5 Inductive types: logic . . . . . . . . . . . . . . . . . . . . . . . . 293
6.5.1 Implication . . . . . . . . . . . . . . . . . . . . . . . . . . 293
6.5.2 Product . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
6.5.3 Unit type . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
6.5.4 Empty type . . . . . . . . . . . . . . . . . . . . . . . . . . 295
6.5.5 Negation . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
6.5.6 Coproduct . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
6.5.7 Π-types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
6.5.8 Σ-types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
6.5.9 Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
6.6 Equality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
CONTENTS 7
A Appendix 473
A.1 Relations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
A.1.1 Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
A.1.2 Closure . . . . . . . . . . . . . . . . . . . . . . . . . . . . 473
A.1.3 Quotient . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
A.1.4 Congruence . . . . . . . . . . . . . . . . . . . . . . . . . . 474
A.2 Monoids . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
A.2.1 Definition . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
A.2.2 Free monoids . . . . . . . . . . . . . . . . . . . . . . . . . 474
A.3 Well-founded orders . . . . . . . . . . . . . . . . . . . . . . . . . 475
A.3.1 Partial orders . . . . . . . . . . . . . . . . . . . . . . . . . 475
A.3.2 Well-founded orders . . . . . . . . . . . . . . . . . . . . . 475
A.3.3 Lexicographic order . . . . . . . . . . . . . . . . . . . . . 476
A.3.4 Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477
A.3.5 Multisets . . . . . . . . . . . . . . . . . . . . . . . . . . . 478
A.4 Cantor’s diagonal argument . . . . . . . . . . . . . . . . . . . . . 479
A.4.1 A general Cantor argument . . . . . . . . . . . . . . . . . 479
A.4.2 Agda formalization . . . . . . . . . . . . . . . . . . . . . . 481
Chapter 0
Introduction
These are the extended notes for the course CSC_51051_EP (formerly INF551),
which I am teaching at École Polytechnique since 2019. The goal is to give a
first introduction to the Curry-Howard correspondence between programs and
proofs from a theoretical programmer’s perspective: we want to understand
the theory behind logic and programming languages, but also to write concrete
programs (in OCaml) and proofs (in Agda). Although most of the material is
self-contained, the reader is supposed to be already acquainted with logic and
programming.
On day three, he thinks maybe a pattern could emerge and discovers that
Z ∞
sin(t) sin(t/101) sin(t/201) π
dt =
0 t t/101 t/201 2
On day four, he gets quite confident and conjectures that, for every n ∈ N,
Z ∞ Y n
!
sin(t/(100i + 1)) π
dt =
0 i=0
t/(100i + 1) 2
He then spends the rest of the year heating his computer and the planet, suc-
cessfully proving the conjecture for increasing values of n. This approach seems
to be justified since the most complicated function involved in here is the sine,
which is quite regular (it is periodic), and all the constants are small (we get
factors such as 100), so that if something bad ought to happen it will happen
for a not-so-big value of n and testing should discover it. In fact, the conjecture
breaks starting at
n = 15 341 178 777 673 149 429 167 740 440 969 249 338 310 889
and none of the usual tests would have found this out. There is a nice explana-
tion for this which we will not give here, see [BB01, Bae18], but the moral is: if
you want to be sure of something, don’t test it, prove it.
On the computer science side, analogous examples abound where errors have
been found in programs which were heavily tested. The number of such exam-
ples have recently increased with the advent of parallel computing (for instance,
in order to exploit all the cores that you have on your laptop or even your
smartphone), where bugs might be triggered by some particular and very rare
scheduling of processes. Already in the 70s, Dijkstra was claiming that program
testing can be used to show the presence of bugs, but never to show their ab-
sence! [Dij70], and the idea of formally verifying programs can even be traced
back 20 years before that by, as usual, Turing [Tur49]. If we want to have soft-
ware we can really trust (and not trust most of the time), we should move from
testing to proving in computer science too.
In this course, you will learn how to perform such proofs, as well as the
theory behind it. Actually, the most complicated program we will prove correct
here is a sorting algorithm and I can already hear you thinking “come on, we
have been writing sorting algorithms for decades, we should know how to write
one by now”. While I understand your point, I have two remarks to provide
for this. Firstly, proving a more realistic program is only a matter of time
(and experience): the course covers most of the concepts required to perform
proofs, and attacking full-fledged code will not require new techniques, only
patience. Secondly, in 2015, some researchers found out, using formal methods,
that the default sorting algorithm (the one in the standard library, not some
obscure library found on GitHub) in both Python and Java (not some obscure
programming language) was flawed, and the bug had been there for more than
a decade [dGdBB+ 19]...
and the compiler will automatically infer a type for it. Here, it will be
('a -> 'b) -> ('b -> 'c) -> ('a -> 'c)
meaning that for any types ’a, ’b and ’c,
will be of type string (it will evaluate to "3"). Now, if we read -> as a logical
implication ⇒, the type can be written as
(A ⇒ B) ⇒ (B ⇒ C) ⇒ (A ⇒ C)
which is a valid formula. This is not by chance: in some sense, the program
comp can be considered as a way of proving that this formula is valid.
Of course, if we want to prove richer properties of programs (or use programs
to prove more interesting formulas), we should use a logic which is more expres-
sive than propositional logic. In this course, we will present dependent types
which achieve this, while keeping the proof-as-program correspondence. For in-
stance, the euclidean division, which computes the quotient and remainder of
two integers, is usually given the type
int -> int -> int * int
CHAPTER 0. INTRODUCTION 13
stating that it takes two integers as arguments and returns a pair of integers.
This typing is very weak, in the sense that there are many different functions
which also have this type. With dependent types, we will be able to give it the
type
and entirely specifies its behavior (here, int’ stands for the type of non-zero
integers, division by zero being undefined).
abstract proof
interpretation assistants
(AbsInt, Astrée, ...) (Agda, Coq, ...)
automation expressiveness
Hoare logic
(Why3, ...)
h1 h2
H1 H2
By induction hypothesis all the horses in H1 have the same color and all the
horses in H2 have the same color. Therefore, by transitivity, all the horses in H
CHAPTER 0. INTRODUCTION 15
have the same color. Of course this proof is not valid, because we all know that
there are horses of various colors (can you spot the mistake?). Formalizing the
proof in a proof assistant will force you to fill in all the details, thus removing
the possibility for potential errors in vague arguments, and will ensure that the
arguments given are actually valid, so that flaws such as in the above proof
will be uncovered. This is not limited to small proofs: large and important
proofs have been fully checked, such as the four color theorem (in Coq) in graph
theory [Gon08], the Feit-Thompson theorem (in Coq) which is central in the
classification of finite simple groups [GAA+ 13], a proof of the Kepler conjecture
on dense sphere packing (in HOL light and Isabelle) [HAB+ 17], or results from
condensed mathematics (the “liquid tensor experiment”, in Lean) [Sch22].
0.6 Foundations
At the beginning of the 20th century, some annoying paradoxes surfaced in
mathematics, such as Russell’s paradox, motivating Hilbert’s program to provide
an axiomatization on which all mathematics could be founded and show that
this axiomatization is consistent: this is sometimes called the foundational crisis.
Although Gödel’s incompleteness theorems established that there is no definite
answer to this question, various formalisms have been elaborated, in which one
CHAPTER 0. INTRODUCTION 16
can develop most of usual mathematics. One of the most widely used is set
theory, as axiomatized by Zermelo and Fraenkel, but other formalisms have
been proposed, such as Russell’s theory of types [WR12], where the modern
type theory originates from: in fact, type theory can be taken as a foundation
of mathematics. People usually see set theory as being more fundamental, since
we see a type as representing a set (e.g. A ⇒ B is the set of functions from
the set of A to the one of B), but we can also view type theory as being more
fundamental since we can formalize set theory in type theory. The one you take
for foundations is a matter of taste: are you more into chickens or into eggs?
Type theory also provides a solid framework in which one can study basic
philosophical questions such as: What is reasoning? What is a proof? If I know
that something exists, do I know this thing? What does it mean for two things
to be equal? and so on. We could spend pages discussing those matters (and
others have done so), but we rather like to formalize things, and we will see that
very satisfactory answers to those questions can be given with a few inference
rules. The meaning of life remains an open question, though.
By taking an increasingly important part in our lives and influencing the way
we see the (mathematical) world, these ideas even have evolved for some of us
into some sort of religion based on the computational trinitarism, which stems
from the observation that computation manifests itself in three forms [Har11]:
categories
logic programming
The aim of the present text is to explain the bottom line of the above diagram
and leave categories for other books [Mac71, LS88, Jac99]. Another closely
related religion is constructivism, a doctrine according to which something can
be accepted only if it can actually be constructed. It will play a central role in
here, because programs precisely constitute a mean to describe the construction
of things.
Reading on the beach. A printed copy of this course can be ordered from Ama-
zon: https://www.amazon.com/dp/B08C97TD9G/.
Color of the cover. In case you wonder, the color of the cover was chosen because
it seemed obvious to me that
Code snippets. Most of the code shown in this book is excerpted from larger files
which are regularly compiled in order to ensure their correctness. The process
of extracting snippets for inclusion into LATEX is automated with a tool whose
code is freely available at https://github.com/smimram/snippetor.
1.1 Introduction
As an illustration of typed functional programming, we present here the OCaml
programming language, which was developed by Leroy and collaborators, fol-
lowing ideas from Milner [Mil78]. We present here some of the basics of the
language both because it will be used in order to provide illustrative implemen-
tations, and also because we will detail the theory behind it and generalize it in
later chapters. This is not meant to be a complete introduction to programming
in OCaml: advanced courses and documentation can be found on the website
http://ocaml.org/, as well as in books [CMP00, MMH13].
After a brief tour of the language, we present the most important construc-
tions in section 1.2, and detail recursive types, which are the main way of con-
structing types throughout the book, in section 1.3. In section 1.4, we present
the ideas behind the typing system and the guarantees it brings. Finally, we
illustrate how types can be thought of as formulas in section 1.5.
1.1.1 Hello world. The mandatory “Hello world!” program, which prints Hello
world!, can be written as follows:
(* Our first program. *)
print_endline "Hello, world!"
This illustrates the concise syntax of the language (compared to Java for in-
stance). Comments are written using (* ... *). Application of a function to
arguments does not require parenthesis. The indentation is not relevant in pro-
grams (unlike e.g. Python), but you are of course strongly encouraged to indent
your programs nicely.
1.1.5 Other features. There are some other important features of the OCaml
language that we mention only briefly here, because we will not use them much.
Other traits. In addition to the functional programming style, OCaml has sup-
port for many other styles of programming including imperative (e.g. references
described above), objects, etc. OCaml also has support for records, arrays, mod-
ules, generalized algebraic data types, etc.
1.2.2 Functions. Functions are also defined using let definition, specifying
the arguments after the name of the variable. For instance,
let add x y = x + y
which would be of type
int -> int -> int
Note that arrows are implicitly bracketed to the right: this type means
The value incr thus defined is the function which takes an argument y and
returns add 1 y, so that the above definition is equivalent to
let incr y = add 1 y
This is in accordance to the bracketing of the types above: add is a function
which, when given an integer argument, returns a function of type int -> int.
As mentioned above, anonymous functions can be defined by the construc-
tion fun x -> .... The add function could thus have been equivalently defined
by
let add = fun x y -> x + y
or even
let add x = fun y -> x + y
Functions can be recursive, meaning that they can call themselves. In this case,
the rec keyword has to be used. For instance, the factorial function is defined
by
1.2.3 Booleans. The type corresponding to booleans is bool, its two values
being true and false. The usual operators are present: conjunction &&, dis-
junction ||, and negation not. In order to test whether two values x and y
are equal or different, one can use x = y and x <> y. They can be used in
conditional branchings
if ... then ... else ...
or loops
while ... do ... done
Beware that the operators == and != also exist, but they compare values
physically, i.e. check whether they have the same memory location, not if they
have the same contents. For instance, using the toplevel, we have:
# let x = ref 0;;
val x : int ref = {contents = 0}
# let y = ref 0;;
val y : int ref = {contents = 0}
# x = x;;
- : bool = true
# x = y;;
- : bool = true
# x == x;;
- : bool = true
# x == y;;
- : bool = false
1.2.4 Products. The pair of x and y is written x,y. For instance, we can
consider the pair 3,"hello" which has the product type int * string (it is a
pair consisting of an integer and a string). Note that addition could have been
defined as
let add' (x,y) = x + y
resulting in a slightly different function than above: it now has the type
(int * int) -> int
meaning that it takes one argument, which is a pair of integers, and returns an
integer. This means that partial application is not directly available as before,
although we could still write
let incr' = fun y -> add (1,y)
1.2.5 Lists. We quite often use lists in OCaml. The empty list is [], and
x::l is the list obtained by putting the value x before a list l. Most expected
functions on lists are available in the module List. For instance,
– @ concatenates two lists,
– List.length computes the length of a list,
– List.map applies a function to all the elements of a list,
– List.iter executes a function for all the elements of a list,
– List.mem tests whether a value belongs to a list.
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 23
1.2.6 Strings. Strings are written as "this is a string" and the related func-
tions can be found in the module String. For instance, the function String.length
computes the length of a string and String.sub computes a substring (at given
indices) of a string. Concatenation is obtained by ^.
1.2.7 Unit. In OCaml, the type unit contains only one element, written ().
As explained above, this is the value returned by functions which only have an
effect and return no meaningful value (e.g. printing a string). They are also
quite useful as an argument for functions which have an effect. For instance, if
we define
let f = print_string "hello"
the program will write “hello” at the beginning of the execution, because the
expression defining f is evaluated. However, if we define
let f () = print_string "hello"
nothing will be printed because we define a function taking a unit as argument.
In the course of the program, we can then use f () in order to print “hello”.
1.3.1 Trees. As a first example, consider trees (more specifically, planar binary
trees with integer labels) such as
4 1
1 3
5 2
Here, a tree consists of finitely many nodes which are labeled by an integer and
can either have two children, which are themselves trees, or none (in which case
they are called leaves). This description translates immediately to the following
type definition in OCaml:
type tree =
| Node of int * tree * tree
| Leaf of int
This says that a tree is recursively characterized as being Node applied to a
triple consisting of an integer and two trees or Leaf applied to an integer. For
instance, the above tree is represented as
let t = Node (3, Node (4, Leaf 1, Node (3, Leaf 5, Leaf 2)), Leaf 1)
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 24
Here, Node and Leaf are not functions (Leaf 1 does not reduce to anything),
they are called constructors. By convention, constructor names have to begin
with a capital letter, in order to distinguish them from function names (which
have to begin with a lowercase letter).
instead of
let f x = match x with ...
(this shortcut was introduced because it is very common to directly match on
the argument of a function).
1.3.2 Usual recursive types. It is interesting to note that many (most) usual
types can be encoded as recursive types.
although OCaml chose not to do that for performance reasons. A case construc-
tion
if b then e1 else e2
could then be encoded as
match b with
| True -> e1
| False -> e2
Coproducts. We have seen that the elements of a product type 'a * 'b are pairs
x , y consisting of an element x of type ’a and an element y of type ’b. We can
define coproducts consisting of an element of type ’a or an element of type ’b
by
type ('a, 'b) coprod =
| Left of 'a
| Right of 'b
An element of this type is of the form Left x with x of type ’a or Right y with
y of type ’b. For instance, we can define a function which provides the string
representation of a value which is either an integer or a float by
let to_string = function
| Left n -> string_of_int n
| Right x -> string_of_float x
which is of type (int, float) coprod -> string.
Unit. The type unit has () as the only value. It could have been defined as
type unit =
| T
having () being a notation for T.
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 26
The set associated to tree is intuitively the smallest set X ⊆ U which is closed
under adding nodes and leaves, i.e. such that F (X) = X, provided that such a
set exists. Such a set X satisfying F (X) = X is called a fixpoint of F .
In order to be able to interpret the type of trees as the smallest fixpoint of F ,
we should first show that such a fixpoint indeed exists. A crucial observation in
order to do so is the fact that the function F : P(U) → P(U) is monotone, in
the sense that, for X, Y ∈ U,
X ⊆ Y implies F (X) ⊆ F (Y ).
F (fix(F )) = fix(F )
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 27
fix(F ) ⊆ X
fix(F ) = F (fix(F )) ⊆ X
i.e. the fixpoint can be obtained by iterating F from the empty set. In the case
of trees,
F 0 (∅) = ∅
F 1 (∅) = {Leaf(n) | n ∈ N}
F 2 (∅) = {Leaf(n) | n ∈ N} ∪ {Nodes(n,t1 ,t2 ) | n ∈ N and t1 , t2 ∈ F 1 (∅)}
and more generally, F n (∅) is the set of trees of height strictly below n. The
theorem states that any tree is a tree of some (finite) height.
Remark 1.3.3.3. In general, there are multiple fixpoints. For instance, for the
function F corresponding to trees, the set of all “trees” where we allow to have
an infinite number of nodes is also a fixpoint of F .
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 28
We have
X = {n ∈ N | P (n)}
The requirement F (X) ⊆ X translates as P (0) holds and P (n) implies P (S n).
The induction principle is thus the classical induction principle for natural num-
bers:
P (0) ⇒ (∀n ∈ N.P (n) ⇒ P (S n)) ⇒ (∀n ∈ N.P (n))
Example 1.3.3.6. Consider the type empty. We have F (X) = ∅ and thus
fix(F ) = ∅. The induction principle states that any property is necessarily
valid on all the elements of the empty set:
∀x ∈ ∅.P (x)
Exercise 1.3.3.7. Define the function F associated to the type of lists. Show that
it also has a greatest fixpoint, distinct from the smallest fixpoint, and provide
a concrete description of it.
1.3.4 Option types and exceptions. Another quite useful recursive type
defined in the standard library is the option type
type 'a option =
| Some of 'a
| None
A value of this type is either of the form Some x for some x of type ’a or None.
It can be thought of as the type ’a extended with the default value None and
can be used for functions that, in some cases, do not return a value (in other
languages such as C or Java, one would return a NULL pointer in this case).
For instance, the function returning the head of a list is almost always defined,
except when the argument is the empty list. It thus makes sense to implement
it as the function of type 'a list -> 'a option defined by
let hd l =
match l with
| x::l -> Some x
| [] -> None
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 29
It is however quite cumbersome to use, because each time we want to use the
result of this function, we have to match it in order to decide whether the result
is None or not. For instance, in order to double the head of a list l of integers
known to be non-empty, we still have to write something like
match head l with
| Some n -> 2*n
| None -> 0 (* This case cannot happen *)
2 * (hd l)
to double the head of a list l. In the case where we take the head of the empty
list, the exception Not_found is raised. We can catch it with the following
construction if we need to:
try
...
with
| Not_found -> ...
Abstraction. Having a typing system is also good for abstraction: we can use a
data structure without knowing the details of implementation or even having
access to them. Taking the Queue.add function as example again, we only know
that the second argument is of type 'a queue, without any more details on
this type. This means that we cannot mess up with the internals of the data
structure, and that the implementation of queues can be radically modified
without us having to change our code.
Efficiency. Static typing can also be used to improve efficiency of compiled pro-
grams. Namely, since we know in advance the type of the values we are going to
handle, our code can be specific to the corresponding data structure, and avoid
performing some security checks. For instance, in OCaml, the concatenation
function on strings can simply put the two strings together; in contrast, in a
dynamically typed programming language such as Python, the concatenation
function on strings has first to ensure that the arguments are strings, if they are
not we will try to convert them as strings, and then we can put them together.
Dynamic vs static. The types of programs can either be checked during the ex-
ecution (the typing is dynamic) or during the compilation (the typing is static):
OCaml is using the latter. Static typing has many advantages: potential er-
rors are found very early, without having to perform tests, it can help to op-
timize programs, and provides very strong guarantees on the execution of the
program. The dynamic approach also has some advantages though: the code is
more flexible, the runtime can automatically perform conversions between types
if necessary, etc.
Weak vs strong. The typing system of OCaml is strong which means that it
ensures that the values in a type are actually of that type: there is no implicit
or dynamic type conversion, no NULL pointers, no explicit manipulation of
pointers, and so on. By opposition, when those requirements are not met, the
typing system is said to be weak.
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 31
Type inference. It is often cumbersome to have to specify the type of all the
terms (or even to give many type annotations). In OCaml, the compiler per-
forms type inference, which means that it automatically finds a type for the
program, when there is one.
Polymorphism. The types in OCaml are polymorphic, which means that they
can contain variables which are treated as universally quantified. For instance,
the identity function
let id x = x
has the type 'a -> 'a, which can also be read as the universally quantified type
∀A.A → A. This means that we can substitute ’a for any type and still get a
valid type for the identity.
Principal types. A program can admit multiple types. For instance, the identity
function admits the following types
'a -> 'a or int -> int or ('a -> 'b) -> ('a -> 'b)
and infinitely many others. The first one 'a -> 'a is however “more general”
than the others because all the other types can be obtained by substituting 'a
by some type. Such a most general type is called a principal type. The type
inference of OCaml has the property that it always produces a principal type.
1.4.3 Safety. The programs which are well-typed in OCaml are safe in the
sense that types are preserved during execution and programs do not get stuck.
In order to formalize these properties, we first need to introduce a notion of
reduction, which formalizes the way programs are executed. We will first do this
on a very small (but representative) subset of the language. Most of the concepts
used here, such as reduction or typing derivation, will be further detailed in
subsequent chapters.
n1 + n2 −→ n1 + n2
p1 −→ p′1 p2 −→ p′2
p1 + p2 −→ p′1 + p2 p1 + p2 −→ p1 + p′2
n1 < n2 n1 ⩾ n2
n1 < n2 −→ true n1 < n2 −→ false
p1 −→ p′1 p2 −→ p′2
p1 < p2 −→ p′1 < p2 p1 < p2 −→ p1 < p′2
p −→ p′
if p then p1 else p2 −→ if p′ then p1 else p2
5 + (5 + 4) ←− (3 + 2) + (5 + 4) −→ (3 + 2) + 9
n∈N
⊢ true : bool ⊢ false : bool ⊢ n : int
⊢ p : bool ⊢ p1 : A ⊢ p2 : A
⊢ if p then p1 else p2 : A
In the second case, the reason why the program 3 + true cannot be further
reduced is that an unexpected value was provided to the sum: we were hoping
for an integer instead of the value true. We will see that the typing system
precisely prevents such situations from arising.
⊢ 3 : int ⊢ 2 : int
⊢ 3 < 2 : bool ⊢ 5 : int ⊢ 1 : int
⊢ if 3 < 2 then 5 else 1 : int
Such a tree showing that a typing judgment is derivable is called a derivation
tree. The principle of type checking and type inference algorithms of OCaml
is to try to construct such a derivation of a typing judgment, using the above
rules. In our small toy language, this is quite easy and is presented in figure 1.4.
For a language with much more features as OCaml (where we have functions
and polymorphism, not to mention objects or generalized algebraic data types)
this is much more subtle, but still follows the same general principle.
It can be observed that a term can have at most one type. We can thus
speak of the type of a typable program:
Theorem 1.4.3.1 (Uniqueness of types). Given a program p, if p is both of
types A and A′ then A = A′ .
Proof. By induction on p: depending on the form of p, at most one rule applies.
For instance, if p is of the form if p0 then p1 else p2 , the only rule which
allows typing p is
⊢ p0 : bool ⊢ p1 : A ⊢ p2 : A
⊢ if p0 then p1 else p2 : A
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 35
exception Type_error
Since p1 and p2 admit at most one type A by induction hypothesis, p also does.
Other cases are similar.
As explained in section 1.4.2, full-fledged languages such as OCaml do not gen-
erally satisfy such a strong property. The type of a program is not generally
unique, but in good typing systems there exists instead a type which is “the
most general”.
Safety. We are now ready to formally state the safety properties guaranteed for
typed programs. The first one, called subject reduction, states that the reduction
preserves typing:
Theorem 1.4.3.2 (Subject reduction). Given programs p and p′ such that p −→ p′ ,
if p has type A then p′ also has type A.
Proof. By hypothesis, we have both a derivation of p −→ p′ and ⊢ p : A. We
reason by induction on the former. For instance, suppose that the last rule is
p1 −→ p′1
p1 + p2 −→ p′1 + p2
⊢ p1 : int ⊢ p2 : int
⊢ p1 + p2 : int
The safety property finally states that typable programs never encounter errors,
in the sense that their execution is never stuck: for instance, we will never try
to evaluate a program such as 3 + true during the reduction.
Theorem 1.4.3.4 (Safety). A program p of type A is safe: either
– p reduces to a value v in finitely many steps
p −→ p1 −→ p2 −→ · · · −→ pn −→ v
p −→ p1 −→ p2 −→ · · ·
Limitations of typing. The typing systems (such as the one described above or
the one of OCaml) reject legit programs such as
(if true then 3 else false) + 1
which reduces to a value. Namely, the system imposes the requirement that the
two branches of a conditional branching should have the same type, which is
not the case here, even though we know that only the first branch will be taken,
because the condition is the constant boolean true. We thus ensure that typable
programs are safe, but not that all safe programs are typable. In fact, this has
to be this way since an easy reduction from the halting problem shows that the
safety of programs is undecidable as soon as the language is rich enough.
Also, the typing system does not prevent all errors from occurring during
the execution, such as dividing by zero or accessing an array out of its bounds.
This is because the typing system is not expressive enough. For instance, the
function
let f x = 1 / (x - 2)
should intuitively be given the type
{n : int | n ̸= 2} → int
which states this function is correct as long as its input is an integer different
from 2, but this is of course not a valid type in OCaml. We will see in chapters 6
and 8 that some languages do allow such rich typing, at the cost of losing type
inference (but type checking is still decidable).
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 38
let comp : ('a -> 'b) -> ('b -> 'c) -> ('a -> 'c) =
fun f g x -> g (f x)
The formula (A ⇒ B ⇒ C) ⇒ (A ⇒ B) ⇒ (A ⇒ C) is proved by
let s : ('a -> 'b -> 'c) -> ('a -> 'b) -> ('a -> 'c) =
fun f g x -> f x (g x)
and so on.
Remark 1.5.1.1. In general, there is not a unique proof of a given formula. For
instance, A ⇒ A can also be proved by
fun x -> k x 3
where k is the function defined above.
1.5.2 Other connectives. For now, the fragment of the logic we have is very
poor (we only have implication as connective), but other usual connectives also
have counterparts in types.
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 39
A∧B corresponds to ’a * ’b
⊤ corresponds to unit
Falsity. The formula ⊥ corresponds to falsity and we do not expect that it can
be proved (because false is never true). We can make it correspond to the empty
type, which can be defined as a type with no constructor:
type empty = |
The formula ⊥ ⇒ A is then shown by
let empty_elim : empty -> 'a = fun x -> match x with _ -> .
(the “.” is a “refutation case” meaning that the compiler should ensure that
this case should never happen, it is almost never used in OCaml unless you are
doing tricky stuff such as the above).
(A ⇒ B) ⇒ (¬B ⇒ ¬A)
by
let contr : ('a -> 'b) -> (('b -> empty) -> ('a -> empty)) =
fun f g a -> g (f a)
or A ⇒ ¬¬A by
let nni : 'a -> (('a -> empty) -> empty) = fun a f -> f a
CHAPTER 1. TYPED FUNCTIONAL PROGRAMMING 40
Propositional logic
2.1 Introduction
2.1.1 From provability to proofs. Most of you are acquainted with boolean
logic based on the booleans, which we write here as 0 for false, and 1 for true.
In this setting, every propositional formula can be interpreted as a boolean,
provided that we have an interpretation for the variables. The truth tables for
usual connectives are
A∧B 0 1 A∨B 0 1 A⇒B 0 1
0 0 0 0 0 1 0 1 1
1 0 1 1 1 1 1 0 1
For instance, we know that the formula A ⇒ A is valid because, for whichever
interpretation of A as a boolean, the induced interpretation of the formula is 1.
We have this idea that propositions should correspond to types. Therefore,
rather than booleans, propositions should be interpreted as sets of values and
implications as functions between the corresponding values. For instance, if
we write N for a proposition interpreted as the set of natural numbers, the
type N ⇒ N would correspond to the set of functions from natural numbers to
themselves. We now see that the boolean interpretation is very weak: it only
cares about whether sets are empty or not. For instance, depending on whether
X is empty (∅) or non-empty (¬∅), the following table indicates whether the set
X → X of functions from X to X is empty or not:
A→B ∅ ¬∅
∅ ¬∅ ¬∅
¬∅ ∅ ¬∅
Reading ∅ as “false” and ¬∅ as “true”, we see that we recover the usual truth
table for implication. In this sense, the fact that the formula N ⇒ N is true only
shows that there exists such a function, but in fact there are many such func-
tions, and we would be able to reason about the various functions themselves.
CHAPTER 2. PROPOSITIONAL LOGIC 42
2.1.2 Intuitionism. This shift from provability to proofs was started by the
philosophical position of Brouwer starting in the early twentieth century, called
intuitionism. According to this point of view, mathematics does not consist
in discovering the properties of a preexisting objective reality, but is rather a
mental subjective construction, which is independent of the reality and has an
existence on its own, whose validity follows from the intuition of the mathe-
matician. From this point of view
– the conjunction A ∧ B of two propositions should be seen as having both
a proof of A and a proof of B: if we interpret propositions as sets, A ∧ B
should not be interpreted as the intersection A ∩ B, but rather are the
product A × B,
– a disjunction A∨B should be interpreted as having a proof of A or a proof
of B, i.e. it does not correspond to the union A ∪ B, but rather to the
disjoint union A ⊔ B,
– an implication A ⇒ B should be interpreted as having a way to construct
a proof of B from a proof of A,
CHAPTER 2. PROPOSITIONAL LOGIC 43
¬¬A ⇒ A
¬¬Key ⇒ Key
does not hold (explanation borrowed from Ingo Blechschmidt). For similar
reasons, Brouwer also rejected the excluded middle
¬A ∨ A
This is done in the following steps, resulting in the following transformed for-
mulas to be proved.
– Suppose given ε, we have to show:
Now that we have decomposed the proof into very small steps, it seems possible
to give a list of all the generic rules that we are allowed to apply in a reasoning.
We will do so and will introduce a convenient formalism and notations, so that
the above proof will be written as:
(when read from bottom to top, you should be able to see the precise corre-
spondence with the previous description of the proof).
2.1.4 Properties of the logical system. Once we have formalized our log-
ical system we should do some sanity checks. The first requirement is that it
should be consistent: there is at least one formula A which is not provable (oth-
erwise, the system would be entirely pointless). The second requirement is that
typechecking should be decidable: there should be an algorithm which checks
whether a proof is valid or not. In contrast, the question of whether a formula
is provable or not will not be decidable in general and we do not expect to have
an algorithm for that.
(ax)
Γ, A, Γ0 ` A
Γ`A⇒B Γ`A Γ, A ` B
(⇒E ) (⇒I )
Γ`B Γ`A⇒B
(>I )
Γ`>
Γ`⊥
(⊥E )
Γ`A
Γ ` ¬A Γ`A Γ, A ` ⊥
(¬E ) (¬I )
Γ`⊥ Γ ` ¬A
Γ 1 ⊢ A1 ... Γn ⊢ An
(2.1)
Γ⊢A
– the elimination rules allow the use of a formula with a given connec-
tive (which is in the formula in the leftmost premise, called the principal
premise),
– the introduction rules construct a formula with a given connective.
In figure 2.1, the elimination (resp. introduction) rules are displayed on the left
(resp. right) and bear names of the form (. . .E ) (resp. (. . .I )).
The axiom rule allows the use of a formula in the context Γ: supposing that
a formula A holds, we can certainly prove it. This rule is the only one to really
make use of the context: when read from the bottom to top, all the other rules
either propagate the context or add hypothesis to it, but never inspect it.
The introduction rules are the most easy to understand: they allow proving
a formula with a given logical connective from the proofs of the immediate
subformulas. For instance, (∧I ) states that from a proof of A and a proof of B,
we can construct a proof of A ∧ B. Similarly, the rule (⇒I ) follows the usual
reasoning principle for implication: if, after supposing that A holds, we can
show B, then A ⇒ B holds.
In contrast, the elimination rules allow the use of a connective. For instance,
the rule (⇒E ), which is traditionally called modus ponens or detachment rule,
says that if A implies B and A holds then certainly B must hold. The rule
(∨E ) is more subtle and corresponds to a case analysis: if we can prove A ∨ B
then, intuitively, we can prove A or we can prove B. If in both cases we can
deduce C then C must hold. The elimination rule (⊥E ) is sometimes called ex
falso quodlibet or the explosion principle: it states that if we can prove false
then the whole logic collapses, and we can prove anything.
We can notice that there is no elimination rule for ⊤ (knowing that ⊤ is
true does not bring any new information), and no introduction rule for ⊥ (we
do not expect that there is a way to prove falsity). There are two elimination
rules for ∧ which are respectively called left and right rules, and similarly there
are two introduction rules for ∨.
2.2.5 Proofs. The set of proofs (or derivations) is the smallest set such that
given proofs πi of the sequent Γi ⊢ Ai , for 1 ⩽ i ⩽ n, and an inference rule of
the form (2.1), there is a proof of Γ ⊢ A, often written in the form of a tree as
π1 πn
...
Γ 1 ⊢ A1 Γ n ⊢ An
Γ⊢A
(ax) (ax)
A ∨ B, A ` A A ∨ B, B ` B
(ax) (∨rI ) (∨lI )
A∨B `A∨B A ∨ B, A ` B ∨ A A ∨ B, B ` B ∨ A
(∨E )
A∨B `B∨A
(⇒I )
`A∨B ⇒B∨A
(A ∧ B) ∧ C ⇔ A ∧ (B ∧ C) A∧B ⇔B∧A
⊤∧A⇔A⇔A∧⊤ A∧A⇔A
A ∧ (B ∨ C) ⇔ (A ∧ B) ∨ (A ∧ C)
A ∨ (B ∧ C) ⇔ (A ∨ B) ∧ (A ∨ C)
A⇒A (A ⇒ B) ⇒ (B ⇒ C) ⇒ (A ⇒ C)
CHAPTER 2. PROPOSITIONAL LOGIC 49
– currying:
((A ∧ B) ⇒ C) ⇔ (A ⇒ (B ⇒ C))
Reasoning on proofs. In this formalism, the proofs are defined inductively and
therefore we can reason by induction on them, which is often useful. Precisely,
the induction principle on proofs is the following one:
Theorem 2.2.5.6 (Induction on proofs). Suppose given a predicate P (π) on
proofs π. Suppose moreover that for every rule of figure 2.1 and every proof π
ending with this rule
π1 πn
...
Γ 1 ⊢ A1 Γn ⊢ An
π =
Γ⊢A
if P (πi ) holds for every index i, with 1 ⩽ i ⩽ n, then P (π) also holds. Then
P (π) holds for every proof π.
A, B ::= X | A ⇒ B
2.2.7 Admissible rules. A rule is admissible when, whenever the premises are
provable, the conclusion is also provable. An important point here is that the
way the proof of the conclusion is constructed might depend on the proofs of the
premises, and not only on the fact that we know that the premises are provable.
Structural rules. We begin by showing that the structural rules are admissible.
Those rules are named in this way because they concern the structure of the
logical proofs, as opposed to the particular connectives we are considering for
formulas. They express some resource management possibilities for the hypothe-
ses in sequents: we can permute, merge and weaken them, see section 2.2.10.
CHAPTER 2. PROPOSITIONAL LOGIC 50
A first admissible rule is the weakening rule, which states that whenever
one can prove a formula with some hypotheses, we can still prove it with more
hypotheses. The proof with more hypotheses is “weaker” in the sense that it
apply in less cases (since more hypotheses have to be satisfied).
Proposition 2.2.7.1 (Weakening). The weakening rule
Γ, Γ′ ⊢ B
(wk)
Γ, A, Γ′ ⊢ B
is admissible.
Proof. By induction on the proof of the hypothesis Γ, Γ′ ⊢ B.
– If the proof is of the form
(ax)
Γ, Γ′ ⊢ B
with B occurring in Γ or Γ′ , then we conclude with
(ax)
Γ, A, Γ′ ⊢ B
Γ, A, B, Γ′ ⊢ C
(xch)
Γ, B, A, Γ′ ⊢ C
is admissible.
Proof. By induction on the proof of the hypothesis Γ, A, B, Γ′ ⊢ C.
Given a proof π of some sequent, we often write w(π) for a proof obtained by
weakening. Another admissible rule is contraction, which states that if we can
prove a formula with two occurrences of a hypothesis, we can also prove it with
one occurrence.
Proposition 2.2.7.3 (Contraction). The contraction rule
Γ, A, A, Γ′ ⊢ B
(contr)
Γ, A, Γ′ ⊢ B
is admissible.
Proof. By induction on the proof of the hypothesis Γ, A, A, Γ′ ⊢ B.
We can also formalize the fact that knowing ⊤ does not bring information, what
we call here truth strengthening (we are not aware of a standard terminology
for this one):
Proposition 2.2.7.4 (Truth strengthening). The following rule is admissible:
Γ, ⊤, Γ′ ⊢ A
(tstr)
Γ, Γ′ ⊢ A
Alternatively, the admissibility of the rule can also be deduced from the admis-
sibility of the cut rule (see theorem 2.2.7.5 below).
The cut rule. A most important admissible rule is the cut rule, which states
that if we can prove a formula B using a hypothesis A (thought of as a lemma
used in the proof) and we can prove the hypothesis A, then we can directly
prove the formula B.
Theorem 2.2.7.5 (Cut). The cut rule
Γ⊢A Γ, A, Γ′ ⊢ B
(cut)
Γ, Γ′ ⊢ B
is admissible.
CHAPTER 2. PROPOSITIONAL LOGIC 52
Proof. For simplicity, we restrict ourselves to the case where the context Γ′
is empty, which is not an important limitation because the exchange rule is
admissible. The cut rule can be derived from the rules of implication by
Γ, A ⊢ B
(⇒I )
Γ⊢A Γ⊢A⇒B
(⇒E )
Γ⊢B
We will see in section 2.3.2 that the above proof is not satisfactory and will
provide another one, which brings much more information about the dynamics
of the proofs.
from which it follows that, given a provable formula A, the formula A′ ob-
tained from A by changing all connectives ¬− into − ⇒ ⊥ is provable, without
using (¬E ) and (¬I ). Conversely, suppose given a formula A, such that the
transformed formula A′ is provable. We have to show that A is also provable,
which is more subtle. In the proof of A′ , for each subproof of the form
π
Γ⊢B⇒⊥
π
Γ⊢B⇒⊥
(wk) (ax)
Γ, B ⊢ B ⇒ ⊥ Γ, B ⊢ B
(⇒E )
Γ, B ⊢ ⊥
(¬I )
Γ ⊢ ¬B
A ⇒ B = ¬A ∨ B
A ⇔ B = (A ⇒ B) ∧ (B ⇒ A)
Γ, Γ′ ⊢ B Γ, ⊤, Γ′ ⊢ A
(wk) (tstr)
Γ, A, Γ′ ⊢ B Γ, Γ′ ⊢ A
We have seen in section 2.2.7 that they are admissible in our system.
Contexts as sets. The rules of exchange and contraction allow to think of con-
texts as sets (rather than lists) of formulas, because a set is a list “up to permu-
tation and duplication of its elements”. More precisely, given a set A, we write
P(A) for the set of subsets of A, and A∗ for the set of lists of elements of A.
We define an equivalence relation ∼ on A∗ as the smallest equivalence relation
such that
Γ, A, B, ∆ ∼ Γ, B, A, ∆ Γ, A, A, ∆ ∼ Γ, A, ∆
Lemma 2.2.10.1. The function f : A∗ → P(A) which to a list associates its set
of elements is surjective. Moreover, given Γ, ∆ ∈ A∗ , we have f (Γ) = f (∆) if
and only if Γ ∼ ∆.
We could therefore have directly defined contexts to be sets of formulas, as is
sometimes done, but this would be really unsatisfactory. Namely, a formula A
in a context can be thought of as some kind of hypothesis which is to be proved
by an auxiliary lemma and we might have twice the same formula A, but proved
by different means: in this case, we would like to be able to refer to a particular
instance of A (which is proved in a particular way), and we cannot do this
if we have a set of hypothesis. For instance, there are intuitively two proofs
of A ⇒ A ⇒ A: the one which uses the left A to prove A and the one which
uses the right one (this will become even more striking with the Curry-Howard
correspondence, see theorem 4.1.7.2). However, with contexts as sets, both are
the same:
(ax)
A⊢A
(⇒I )
A⊢A⇒A
(⇒I )
⊢A⇒A⇒A
A less harmful simplification which is sometimes done is to quotient by exchange
only (and not contraction), in which case the contexts become multisets, see
section A.3.5. We will refrain from doing that here as well.
CHAPTER 2. PROPOSITIONAL LOGIC 55
Variants of the proof system. The structural rules are usually taken as “real”
(as opposed to admissible) rules of the proof system. Here, we have carefully
chosen the formulation of rules, so that they are admissible, but it would not
hold anymore if we had used subtle variants instead. For instance, if we replace
the axiom rule by
(ax) or (ax)
Γ, A ⊢ A A⊢A
Γ⊢A ∆⊢B
(∧I )
Γ, ∆ ⊢ A ∧ B
the structural rules are not all admissible anymore. The study of the fine struc-
ture behind this lead Girard to introduce linear logic [Gir87].
A[B/X]
for the substitution of X by B in A, i.e. the formula A where all the occurrences
of X have been replaced by B. More generally, a substitution for A is a function
which to every variable X occurring in A assigns a formula σ(X), and we also
write
A[σ]
for the formula A where every variable X has been replaced by σ(X). Similarly,
given a context Γ = A1 , . . . , An , we define
We often write
[A1 /X1 , . . . , An /Xn ]
for the substitution σ such that σ(Xi ) = Ai and σ(X) = X for X different from
each Xi . It satisfies
{X ∈ X | σ(X) ̸= X}
In our reasoning to prove that 6 can be halved, we have used the fact that 6 is
even, which we must have proved in this way:
– 6 is even because 6 = 4 + 2 and 4 is even, where
– 4 is even because 4 = 2 + 2 and 2 is even, where
– 2 is even because 2 = 0 + 2 and 0 is even, where
– 0 is even by definition.
From the proof of the lemma, we know that the half of 6 is the successor of the
half of 4, which is the successor of the half of 2 which is the successor of the half
of 0, which is 0. Writing, as usual, n/2 for a half of n, we have
6/2 = (4/2) + 1 = (2/2) + 1 + 1 = (0/2) + 1 + 1 + 1 = 0 + 1 + 1 + 1 = 3
Therefore the half of 6 is 3: we have managed to extract the actual value of the
half of 6 from the proofs the 6 is even and the above lemma. This example is
further formalized in section 6.6.3.
CHAPTER 2. PROPOSITIONAL LOGIC 57
2.3.1 Cuts. In logic, the use of a lemma to show a result is called a “cut”. This
must not be confused with the (cut) rule presented in theorem 2.2.7.5, although
they are closely related. Formally, a cut in a proof is an elimination rule whose
principal premise is proved by an introduction rule of the same connective. For
instance, the following are cuts:
π π′ π
Γ⊢A Γ⊢B Γ, A ⊢ B π′
(∧I ) (⇒I )
Γ⊢A∧B Γ⊢A⇒B Γ⊢A
(∧lE ) (⇒E )
Γ⊢A Γ⊢B
The formula in the principal premise is called the cut formula: above, the cut
formulas are respectively A∧B and A ⇒ B. A proof containing a cut intuitively
does “useless work”. Namely, the one on the left starts from a proof π of A in
the context Γ, which it uses to prove A ∧ B, from which it deduces A: in order
to prove A, the proof π was already enough and the proof π ′ of B was entirely
superfluous. Similarly, for the proof on the right, we show in π that supposing A
we can prove B, and also in π ′ that we can prove A: we could certainly directly
prove B, replacing in π all the places where the hypothesis A is used (say by an
axiom) by the proof π ′ . For this reason, cuts are sometimes also called detours.
From a proof-theoretic point of view, it might seem a bit strange that some-
one would use such a kind of proof structure, but this is actually common in
mathematics: when we want to prove a result, we often prove a lemma which
is more general than the result we want to show and then deduce the result we
were aiming at. One of the reasons for proceeding in this way is that we can
use the same lemma to cover multiple cases, and thus have shorter proofs (not
to mention that they are generally more conceptual and modular, since we can
reuse the lemmas for other proofs). We will see that, however, we can always
avoid using cuts in order to prove formulas. Before doing so, we first need to
introduce the main technical result which allows this.
(ax) (ax)
Γ, A ⊢ A Γ, A ⊢ A
(∧I ) ..
Γ, A, B ⊢ A ∧ A ′ .
π= (⇒I ) π =
Γ, A ⊢ B ⇒ A ∧ A Γ⊢A
π′ π′
Γ⊢A Γ⊢A
(wk) (wk)
Γ, B ⊢ A Γ, B ⊢ A
(∧I )
Γ, B ⊢ A ∧ A
(⇒I )
Γ⊢B ⇒A∧A
π π′
and
Γ, A, Γ′ ⊢ B Γ⊢A
π[π ′ /A]
Γ, Γ′ ⊢ B
Γ⊢A Γ, A, Γ′ ⊢ B
(cut)
Γ, Γ′ ⊢ B
is admissible.
Proof. By induction on π.
We will see that the admissibility of this rule is the main ingredient to prove
cut elimination, thus its name.
2.3.3 Cut elimination. A logic has the cut elimination property when when-
ever a formula is provable then it is also provable with a proof which does not
involve cuts: we can always avoid doing unnecessary things. This procedure was
introduced by Gentzen under the name Hauptsatz [Gen35]. In general, we not
only want to know that such a proof exists, but also to have an effective cut elim-
ination procedure which transforms a proof into one without cuts. The reason
for this is that we will see in section 4.1.8 that this corresponds to “executing”
the proof (or the program corresponding to it): this is why Girard [Gir87] claims
that
A logic without cut elimination is like a car without an engine.
Although the proof obtained after eliminating cuts is “simpler” in the sense that
it does not contain unnecessary steps (cuts), it cannot always be considered as
“better”: it is generally much bigger than the original one. The quote above
explains it: think of a program computing the factorial of 1000. We see that a
result can be much bigger than the program computing it [Boo84], and it can
take much time to compute [Ore82].
Theorem 2.3.3.1. Intuitionistic natural deduction has the cut elimination prop-
erty.
CHAPTER 2. PROPOSITIONAL LOGIC 59
π
Γ, A ` B π0
(⇒I )
Γ`A⇒B Γ`A π[π 0 /A]
(⇒E )
Γ`B Γ`B
π π0
Γ`A Γ`B
(∧I )
Γ`A∧B π
(∧lE )
Γ`A Γ`A
π π0
Γ`A Γ`B
(∧I )
Γ`A∧B π0
(∧rE )
Γ`B Γ`B
π
Γ`A π0 π 00
(∨lI )
Γ`A∨B Γ, A ` C Γ, B ` C π 0 [π/A]
(∨E )
Γ`C Γ`C
π
Γ`B π0 π 00
(∨rI )
Γ`A∨B Γ, A ` C Γ, B ` C π 00 [π/B]
(∨E )
Γ`C Γ`C
Proof. Suppose given a proof which contains a cut. This means that at some
point in the proof we encounter one of the following situations (i.e. we have a
subproof of one of the following forms), in which case we transform the proof
as indicated by ⇝ in figure 2.2 (we do not handle the cut on ¬ since ¬A can be
coded as A ⇒ ⊥). For instance,
(ax) (ax)
Γ, A ⊢ A Γ, A ⊢ A
(∧I )
Γ, A ⊢ A ∧ A π
(⇒I )
Γ⊢A⇒A∧A Γ⊢A
(⇒E )
Γ⊢A∧A
is transformed into
π π
Γ⊢A Γ⊢A
(∧I )
Γ⊢A∧A
We iterate the process on the resulting proof until all the cuts have been re-
CHAPTER 2. PROPOSITIONAL LOGIC 60
moved.
As it can be noticed on the above example, applying the transformation ⇝
might duplicate cuts: if the above proof π contained cuts, then the transformed
proof contains twice the cuts of π. It is therefore not clear that the process
actually terminates, whichever order we choose to eliminate cuts. We will see
in section 4.2 that it indeed does, but the proof will be quite involved. It
is sufficient for now to show that a particular strategy for eliminating cuts is
terminating: at each step, we suppose that we eliminate a cut of highest depth,
i.e. there is no cut “closer to the axioms” (for instance, we could apply the above
transformation only if π has not cuts). We define the size |A| of a formula A as
its number of connectives and variables:
The degree of a cut is the size of the cut formula (e.g. of A ⇒ A ∧ A in the above
example, whose size is 2 + 3|A|), and the degree of a proof is then defined as the
multiset (see section A.3.5) of the degrees of the cuts it contains. It can then
be checked that whenever we apply ⇝, the newly created cuts are of strictly
lower degree than the cut we eliminated and therefore the degree of the proof
decreases according to the multiset order, see section A.3.5. For instance, if we
apply a transformation
π
Γ, A ⊢ B π′
(⇒I )
Γ⊢A⇒B Γ⊢A π[π ′ /A]
(⇒E ) ⇝
Γ⊢B Γ⊢B
we suppose that π ′ has no cuts (otherwise the eliminated cut would not be
of highest depth). The degree of the cut is |A ⇒ B|. All the cuts present
in the resulting proof where already present in the original proof, except for
the new cuts on A which might be created by the substitution of π ′ in π,
which are of degree |A| < |A ⇒ B|. Since the multiset order is well-founded,
see theorem A.3.5.1, the process will eventually come to an end: we cannot have
an infinite sequence of ⇝ transformations, chosen according to our strategy.
The previous theorem states that, as long as we are interested in provability,
we can restrict ourselves to cut-free proofs. This is of interest because we often
have a good idea of which rules can be used in those. In particular, we have the
following useful result:
Proposition 2.3.3.2. For any formula A, a cut-free proof of ⊢ A necessarily ends
with an introduction rule.
Proof. Consider the a cut-free proof π of ⊢ A. We reason by induction on it.
This proof cannot be an axiom because the context is empty. Suppose that π
ends with an elimination rule:
..
.
π= (?E )
⊢A
For each of the elimination rules, we observe that the principal premise is nec-
essarily of the form ⊢ A′ , and therefore ends with an introduction rule, by
CHAPTER 2. PROPOSITIONAL LOGIC 61
and thus contains a cut, which is impossible since we have supposed π to be cut-
free. Since π cannot end with an axiom nor an elimination rule, it necessarily
ends with an introduction rule.
In the above proposition, it is crucial that we consider a formula in an empty
context: a cut-free proof of Γ ⊢ A does not necessarily end with an introduction
rule if Γ is arbitrary.
2.3.4 Consistency. The least one can expect from a non-trivial logical system
is that not every formula is provable, otherwise the system is of no use. A logical
system is consistent when there is at least one formula which cannot be proved
in the system. Since, by (⊥E ), one can deduce any formula from ⊥, we have:
Lemma 2.3.4.1. The following are equivalent:
(i) the logical system is consistent,
(ii) the formula ⊥ cannot be proved,
Of course, the above theorem does not state that, for a particular given
formula A, the formula ¬A ∨ A is not provable. For instance, with A = ⊤, we
have
(⊤I )
⊢⊤
(∨rI )
⊢ ¬⊤ ∨ ⊤
It however states that we cannot prove ¬A ∨ A without knowing the details
of A. This will be studied in more detail in section 2.5, where other examples
of non-provable formulas are given.
Since the excluded-middle is not provable, maybe it is false in our logic? That
is not the case because we can show that the excluded-middle is not falsifiable
either, since we can prove the formula ¬¬(¬A ∨ A) as follows:
(ax)
¬(¬A ∨ A), A ` A
(ax) (∨rI )
¬(¬A ∨ A), A ` ¬(¬A ∨ A) ¬(¬A ∨ A), A ` ¬A ∨ A
(¬E )
¬(¬A ∨ A), A ` ⊥
(¬I )
¬(¬A ∨ A) ` ¬A
(ax) (∨lI )
¬(¬A ∨ A) ` ¬(¬A ∨ A) ¬(¬A ∨ A) ` ¬A ∨ A
(¬E )
¬(¬A ∨ A) ` ⊥
(¬I )
` ¬¬(¬A ∨ A)
Proof. Let us prove this in a slightly different way than in theorem 2.3.5.2. It
can be proved in NJ that ¬⊤ ⇒ ⊥:
(ax) (⊤I )
¬⊤ ⊢ ¬⊤ ¬⊤ ⊢ ⊤
(¬E )
¬⊤ ⊢ ⊥
(⇒I )
⊢ ¬⊤ ⇒ ⊥
2.3.6 Commutative cuts. Are the cuts the only situations where one is doing
useless work in proofs? No. It turns out that falsity and disjunction induce some
CHAPTER 2. PROPOSITIONAL LOGIC 64
Γ⊢⊥
(⊥E ) ...
Γ⊢A Γ⊢⊥
(?E ) ⇝ (⊥E )
Γ⊢B Γ⊢B
π π′ π ′′
Γ⊢A∨B Γ, A ⊢ C Γ, B ⊢ C
(∨E ) ...
Γ⊢C
(?E )
Γ⊢D
⇝
π′ π ′′
... ...
π Γ, A ⊢ C Γ, B ⊢ C
(?E ) (?E )
Γ⊢A∨B Γ, A ⊢ D Γ, B ⊢ D
(∨E )
Γ⊢D
more situations where we would like to eliminate “useless work”. For instance,
consider the following proof:
(ax)
⊥⊢⊥
(⊥E ) (ax) (ax)
⊥⊢A∨A ⊥, A ⊢ A ⊥, A ⊢ A
(∨E )
⊥⊢A
For the hypothesis ⊥, we deduce the “general” statement that A ∨ A holds, from
which we deduce that A holds. Clearly, we ought to be able to simplify this
proof by into
(ax)
⊥⊢⊥
(⊥E )
⊥⊢A
where we directly prove A instead of using the “lemma” A∨A as an intermediate
step. Another example of such a situation is the following one:
(ax) (ax) (ax) (ax)
A, B ∨ C, B ` A A, B ∨ C, B ` A A, B ∨ C, C ` A A, B ∨ C, C ` A
(ax) (∧I ) (∧I )
A, B ∨ C ` B ∨ C A, B ∨ C, B ` A ∧ A A, B ∨ C, C ` A ∧ A
(∨E )
A, B ∨ C ` A ∧ A
(∧lE )
A, B ∨ C ` A
2.4.2 Proof search. Proof search can be automated in NJ: there is an algo-
rithm which, given a sequent, determines whether it is provable or not. We
describe here such an algorithm where, for simplicity, we restrict ourselves here
to the implicational fragment (formulas are built out of variables and implica-
tion, and the rules are (ax), (⇒E ) and (⇒I )).
Suppose that we are trying to determine whether a given sequent Γ ⊢ A
is provable. It can be observed that, depending on the formula A (which is
either of the form B ⇒ C or a variable X), we can always look for proofs of the
following form:
(a) Γ ⊢ B ⇒ C: the last rule is
Γ, B ⊢ C
(⇒I )
Γ⊢B⇒C
A1 ⇒ . . . ⇒ An ⇒ X
Namely, the first case is justified by the fact that (⇒I ) is reversible so that it
can always be applied first, and the second one by the fact that we can look for
cut-free proofs (theorem 2.3.3.1) so that we can restrict to the cases where the
rules (⇒E ) have a principal premise which is a rule (ax) or (⇒E ), but not (⇒I ).
This suggests the following procedure to determine the provability of a given
sequent Γ ⊢ A:
CHAPTER 2. PROPOSITIONAL LOGIC 67
In order to prevent this kind of loops, we should ensure that, whenever we are
trying to construct a proof of a sequent Γ ⊢ A, we never try to construct again
a proof of Γ ⊢ A at a later stage, and this is easily done by remembering all
the sequents encountered during proof search. An actual implementation is
provided in figure 2.4, where we use a list seen to remember the sequents that
we have already seen, a sequent being encoded as a pair consisting of a context
(a list of formulas) and a formula.
Writing Γ for the context X ⇒ Y, (X ⇒ Y ) ⇒ X, our algorithm will find
that Γ ⊢ Y is provable because there is the proof
(ax) (ax)
Γ, X ⊢ X ⇒ Y Γ, X ⊢ X
(⇒E )
Γ, X ⊢ Y
(ax) (⇒I )
Γ ⊢ (X ⇒ Y ) ⇒ X Γ⊢X⇒Y
(ax) (⇒E )
Γ⊢X⇒Y Γ⊢X
(⇒E )
Γ⊢Y
Note that we are trying to prove Y twice during the proof search, but this is
authorized because this is done in different contexts (respectively in the contexts
Γ and Γ, X). As it can be observed in the above example, when looking for a
proof a sequent Γ ⊢ A, the contexts can grow during proof search. Termination
is however still guaranteed because it can be shown that all the formulas that
we add to the context are strict subformulas of the original formula A, and
there are only a finite number of those. The algorithm can be shown to be in
PSPACE (i.e. it requires an amount of memory which is polynomial in the size
of its input) and the problem is actually PSPACE-complete (it is harder than
any other problem in PSPACE, which in particular implies that it is harder
than any problem in NP), see [Sta79] and [SU06, section 6.6]. Other methods
for performing proof search in intuitionistic logic are presented in section 2.6.5.
(** Formulas. *)
type t =
| Var of string
| Imp of t * t
(theorem 2.3.5.2), which states that ¬A ∨ A holds. In contrast, the usual notion
of validity (e.g. coming from boolean models) is called classical logic. If classical
logic is closer to the usual intuition of validity, the main drawback for us is that
this logic is not constructive, in the sense that we cannot necessarily extract
witnesses from proofs: if we have proved A ∨ B in classical logic, we do not
necessarily know which one of A or B actually holds. For instance, a well-
known typical classical reasoning is the following:
Proposition 2.5.0.1. There exist two irrational numbers a and b such that ab is
rational.
√ √
Proof. We know that 2 is irrational: if 2 = p/q then p2 = 2q 2 , but the
number of prime factors is even on the left and odd on√the right. Reasoning
√ 2
using the excluded middle, we know that the number 2 is either rational or
irrational:
√
– if it is rational, we conclude with a = b = 2,
√
√ 2 √
– otherwise, we take a = 2 and b = 2, and we have ab = 2 which
concludes the proof.
While we could prove the property, we are not able, from the proof, to exhibit
a concrete value for a and b.
Another principle which is inherently classical is the double negation prin-
ciple, which states that ¬¬A ⇒ A. We can see it in action in the following
proof:
Proposition 2.5.0.2. Either (π + e) or (π − e) is irrational.
Proof. By contradiction. Suppose that both (π + e) and (π − e) are rational.
Then 2π would also be rational, since it can be obtained as their sum, and we
reach a contradiction, since it is well-known that π is irrational.
In the above reasoning, writing A for the proposition, we have shown that we
have ¬A ⇒ ⊥, from which we deduced A, i.e. we have implicitly used ¬¬A ⇒ A.
Again, we can see that the proof is not constructive: we cannot exact from it
which of the two numbers is irrational (and, in fact, this is currently an open
problem).
From the proof-as-program correspondence, the excluded middle is also quite
puzzling. Suppose that we are in a logic rich enough to encode Turing machines
(or, equivalently, execute a program in a usual programming language) and that
we have a predicate Halts(M ) which holds when M is halting (you should find
this quite plausible after having read chapter 6). In classical logic, the formula
¬ Halts(M ) ∨ Halts(M )
holds for every Turing machine M , which seems to mean that we should be able
to decide whether a Turing machine is halting or not, but there is no hope of
finding such an algorithm since Turing has shown that the halting problem is
undecidable [Tur37b].
CHAPTER 2. PROPOSITIONAL LOGIC 70
2.5.1 Axioms for classical logic. A logical system for classical logic, called
NK (for K lassical N atural deduction), can be obtained from NJ (figure 2.1) by
adding a new rule corresponding to the excluded middle
(lem)
Γ ⊢ ¬A ∨ A
In this sense, the excluded middle is the only thing which is missing in intu-
itionistic logic to be classical. This is shown in theorems 2.5.6.1 and 2.5.6.5.
In fact, excluded middle is not the only possible choice, and other equiva-
lent axioms can be added instead. Most of those axioms correspond to usual
reasoning patterns, which have been known for a long time, and thus bear latin
names.
Theorem 2.5.1.1. The following principles are equivalent in NJ:
(i) excluded middle, also called tertium non datur:
¬A ∨ A
¬¬A ⇒ A
(iii) contraposition:
(¬B ⇒ ¬A) ⇒ (A ⇒ B)
¬(A ⇒ B) ⇒ A ∧ ¬B
(¬A ⇒ A) ⇒ A
¬(¬A ∧ ¬B) ⇒ A ∨ B
¬(¬A ∨ ¬B) ⇒ A ∧ B
(A ⇒ (B ∨ C)) ⇒ ((A ⇒ B) ∨ C)
CHAPTER 2. PROPOSITIONAL LOGIC 71
By “equivalent” we mean here that if we suppose that one holds for every
formulas A, B and C then the other one also holds for every formulas A, B
and C, and conversely.
Proof. We only show here the equivalence between the first two, the other ones
being left as an exercise. Supposing that the excluded middle holds, we can
show reductio ad absurdum by
(ax) (ax)
¬¬A, ¬A ` ¬¬A ¬¬A, ¬A ` ¬A
(¬E ) (ax)
¬¬A ` ¬A ∨ A ¬¬A, ¬A ` A ¬¬A, A ` A
(∨E )
¬¬A ` A
(⇒I )
` ¬¬A ⇒ A
(2.2)
Supposing that reductio ad absurdum holds, we can show the excluded middle
by
π
⊢ ¬¬(¬A ∨ A) ⇒ (¬A ∨ A) ⊢ ¬¬(¬A ∨ A)
(⇒E )
⊢ ¬A ∨ A (2.3)
where π is the proof of ¬¬(¬A ∨ A) given on page 63.
Remark 2.5.1.2. One should be careful about the quantifications over formu-
las involved in theorem 2.5.1.1. In order to illustrate this, let us detail the
equivalence between excluded middle and reductio ad absurdum. We say that
a formula A is decidable when ¬A ∨ A holds and stable when ¬¬A ⇒ A holds.
The derivation (2.2) shows that every decidable formula is stable, but the con-
verse does not hold: the derivation (2.3) only shows that A is decidable when
¬A ∨ A (as opposed to A) is stable. In fact a concrete example of a formula
which is stable but not decidable can be given by taking A = ¬X: the for-
mula ¬¬¬X ⇒ ¬X holds (theorem 2.5.9.4), but ¬¬X ∨ ¬X cannot be proved
(theorem 2.3.5.3). Thus, it is important to note that theorem 2.5.1.1 does not
say that a formula is stable if and only if it is decidable, but rather that every
formula is stable if and only if every formula is decidable.
Among those axioms, Pierce’s law is less natural than others but has the ad-
vantage of requiring only implication, so that it still makes sense in some small
fragments of logic such as implicational logic. Also note that the fact that ma-
terial implication occurs in this list means that A ⇒ B is not equivalent to
¬A ∨ B in NJ, in contrast to NK. For each of these axioms, we could add more
or less natural forms of rules. For instance, the law of the excluded middle can
also be implemented by the nicer looking rule
Γ, ¬A ⊢ B Γ, A ⊢ B
(lem)
Γ⊢B
similarly, reductio ad absurdum can be implemented by one of the following
rules
Γ ⊢ ¬¬A Γ, ¬A ⊢ ⊥ Γ, ¬A ⊢ A
(¬¬E )
Γ ⊢ ¬¬A ⇒ A Γ⊢A Γ⊢A Γ⊢A
Since classical logic is obtained from intuitionistic by adding axioms, it is
obvious that
CHAPTER 2. PROPOSITIONAL LOGIC 72
2.5.2 The intuition behind classical logic. Let us try to give some proof
theoretic intuition about how classical logic works.
In other words, ¬¬A can be seen as the formula A where the only thing which
matters is not all the proofs of A (i.e. the elements of JAK), but only whether
there exists a proof of A or not, since we have reduced its contents to at most
one point. For this reason, doubly negated formulas are sometimes said to be
proof irrelevant: again, the actual proof does not matter, only its existence. For
instance, we now understand why
¬¬(¬A ∨ A)
is provable intuitionistically (see page 63): it states that it is true that there
exists a proof of ¬A or a proof of A, as opposed to ¬A ∨ A which states that we
have a proof of ¬A or a proof of A. From this point of view, the classical axiom
¬¬A ⇒ A
now seems like deep magic: it means that if we know that there exists a proof
of A, we can actually extract a proof of A. This can only be true if we assume
that there can be at most one proof for a formula, i.e. formulas are interpreted
as booleans and not sets (see section 2.5.4 for a logical point of view on this).
This also explains why we can actually embed classical logic into intuitionistic
logic by double-negating formulas, see section 2.5.9: if we are only interested in
their existence, intuitionistic proofs behave classically.
CHAPTER 2. PROPOSITIONAL LOGIC 73
Resetting proofs. Let us give another, more operational, point of view on the
axiom ¬¬A ⇒ A. We have mentioned that it is equivalent to having the rule
Γ ⊢ ¬¬A
(¬¬E )
Γ⊢A
so that when searching for a proof of A, we can instead prove ¬¬A. What do
we gain in doing so? At first it does not seem much, since we can go back to
proving A:
..
.
(ax)
Γ, ¬A ⊢ ¬A Γ, ¬A ⊢ A
(¬E )
Γ, ¬A ⊢ ⊥
(¬I )
Γ ⊢ ¬¬A
But there is one difference: we now have the additional hypothesis ¬A in our
context, and we can use it at any point in the proof to go back to proving A
instead of the current goal B, while keeping the current context:
..
.
(ax)
Γ′ , ¬A ⊢ ¬A ′
Γ , ¬A ⊢ A
(¬E )
Γ′ , ¬A ⊢ ⊥
(⊥E )
Γ′ , ¬A ⊢ B
In other words, we can “reset proofs” during proof search, i.e. we can implement
the following behavior (up to minor details such as weakening):
..
.
′
Γ ⊢A
(reset)
Γ′ ⊢ B
..
.
Γ⊢A
Γ⊢∆
where both Γ and ∆ are contexts. Such a sequent should be read as “supposing
all the formula in Γ, I can prove some formula in ∆”. This is a generalization of
previous sequents, where ∆ was restricted to exactly one formula. The rules for
this sequent calculus are given in figure 2.5. In order to simplify the presentation,
we consider here that the formulas of ∆ can be explicitly permuted, duplicated,
and so on, using the structural rules (xchR ), (wkR ), (contrR ) and (⊥R ), which
we generally leave implicit in examples. Those rules are essentially the same as
those for NJ, with contexts added on the right, except for the rules (∨lI ) and
(∨rI ), which are now combined into the rule
Γ ⊢ A, B, ∆
(∨I )
Γ ⊢ A ∨ B, ∆
(ax)
Γ, A, Γ′ ⊢ A, ∆
Γ ⊢ A ⇒ B, ∆ Γ ⊢ A, ∆ Γ, A ⊢ B, ∆
(⇒E ) (⇒I )
Γ ⊢ B, ∆ Γ ⊢ A ⇒ B, ∆
Γ ⊢ A ∧ B, ∆ l Γ ⊢ A ∧ B, ∆ r Γ ⊢ A, ∆ Γ ⊢ B, ∆
(∧E ) (∧E ) (∧I )
Γ ⊢ A, ∆ Γ ⊢ B, ∆ Γ ⊢ A ∧ B, ∆
(⊤I )
Γ ⊢ ⊤, ∆
Γ ⊢ A ∨ B, ∆ Γ, A ⊢ C, ∆ Γ, B ⊢ C, ∆ Γ ⊢ A, B, ∆
(∨E ) (∨I )
Γ ⊢ C, ∆ Γ ⊢ A ∨ B, ∆
Γ⊢∆
(⊥I )
Γ ⊢ ⊥, ∆
Γ ⊢ ¬A, ∆ Γ ⊢ A, ∆ Γ, A ⊢ ⊥, ∆
(¬E ) (¬I )
Γ ⊢ ⊥, ∆ Γ ⊢ ¬A, ∆
structural rules:
Γ ⊢ ∆, A, B, ∆′ Γ ⊢ ∆, ∆′
(xchR ) (wkR )
Γ ⊢ ∆, B, A, ∆′ Γ ⊢ ∆, A, ∆′
Γ ⊢ ∆, A, A, ∆′ Γ ⊢ ∆, ⊥, ∆′
(contrR ) (⊥R )
Γ ⊢ ∆, A, ∆′ Γ ⊢ ∆, ∆′
proved by
(ax)
¬¬A, A ⊢ A
(wkR )
¬¬A, A ⊢ ⊥, A
(ax) (¬I )
¬¬A ⊢ ¬¬A, A ¬¬A ⊢ ¬A, A
(¬E )
¬¬A ⊢ ⊥, A
(⊥E )
¬¬A ⊢ A, A
(contrR )
¬¬A ⊢ A
(⇒I )
⊢ ¬¬A ⇒ A
Γ ⊢ ⊥, ∆
(⊥R )
Γ ⊢ ⊥, ∆ Γ⊢∆
(⊥E ) (wkR )
Γ ⊢ A, ∆ Γ ⊢ A, ∆
In fact the constant ⊥ is now superfluous, since one can convince himself that
proving ⊥ amounts to proving the empty sequent ∆.
2.5.4 Cut-elimination in classical logic. Classical logic also does have the
cut-elimination property, see section 2.3.3, although this is more subtle to show
than in the case of intuitionistic logic due to the presence of structural rules. In
particular, in addition to the usual cut elimination steps, we need to add rules
making elimination rules “commute” with structural rules: namely, an intro-
duction and the corresponding elimination rules can be separated by structural
rules. For instance, suppose that we want to eliminate the following “cut”:
π π′
Γ⊢A Γ⊢B
(∧I )
Γ⊢A∧B
(wkR )
Γ ⊢ A ∧ B, C
(∧lE )
Γ ⊢ A, C
We first need to make the elimination rule for conjunction commute with the
weakening:
π π′
Γ⊢A Γ⊢B
(∧I )
Γ⊢A∧B
(∧lE )
Γ⊢A
(wkR )
Γ ⊢ A, C
and then we can finally properly eliminate the cut:
π
(∧lE )
Γ⊢A
(wkR )
Γ ⊢ A, C
CHAPTER 2. PROPOSITIONAL LOGIC 77
Γ ⊢ A ⇒ B, ∆ Γ ⊢ A, ∆ Γ, A ⊢ B, ∆
(⇒E ) (⇒I )
Γ ⊢ B, ∆ Γ ⊢ A ⇒ B, ∆
together with the four structural rules. Several other choices of connectives are
possible.
CHAPTER 2. PROPOSITIONAL LOGIC 78
Efficient computation of the clausal form. Given a clause C, we write L(C) for
the set of literals occurring in it:
L(X) = {X} L(¬X) = {¬X} L(C ∨ D) = L(C) ∪ L(D) L(⊥) = ∅
A variable X occurs positively (resp. negatively) in A if we have X ∈ L(C)
(resp. ¬X ∈ L(C)). Up to equivalence, formulas satisfy the laws of commutative
idempotent monoids with respect to ∨ and ⊥:
(A ∨ B) ∨ C ⇔ A ∨ (B ∨ C) ⊥∨A⇔A B∨A⇔A∨B
A∨⊥⇔A A∨A⇔A
Because of this, a clause is characterized by the set of literals occurring in it,
see section A.2:
CHAPTER 2. PROPOSITIONAL LOGIC 79
A ∨ B = {Ci ∪ Dj | 1 ⩽ i ⩽ m, 1 ⩽ j ⩽ n}
The notion of clausal form can be further improved as follows. We say that
a formula is in canonical clausal form when
1. it is in clausal form,
2. it does not contain twice the same clause or ⊤ (this is automatic if it is
represented as a set of clauses),
3. no clause contains twice the same literal or ⊥ (this is automatic if they
are represented as sets of literals),
4. no clause contains both a literal and its negation.
For the last point, given a clause C containing both X and ¬X, the equivalences
¬X ∨ X ⇔ ⊤ and ⊤ ∨ A ⇔ ⊤ imply that the whole clause is equivalent to ⊤ and
can thus be removed from the formula. For instance, the clausal form computed
in theorem 2.5.5.2 is not canonical because it does not satisfy the second point
above.
Exercise 2.5.5.4. Modify the algorithm of figure 2.6 so that it computes canonical
clausal forms.
De Morgan laws in intuitionistic logic. Let us insist once again on the fact that
the de Morgan laws do not hold in intuitionistic logic. Namely, the following
implications are intuitionistically true, but not their converse:
¬A ∧ ¬B ⇔ ¬(A ∨ B)
CHAPTER 2. PROPOSITIONAL LOGIC 80
(** Formulas. *)
type t =
| Var of var
| And of t * t
| Or of t * t
| Imp of t * t
| Not of t
| True | False
2.5.6 Boolean models. Classical natural deduction matches exactly the no-
tion of truth one would get from usual boolean models. Let us detail this. We
write B = {0, 1} for the set of booleans. A valuation ρ is a function X → B,
assigning booleans to variables. Such a valuation can be extended to a function
ρ : Prop → B, from propositions to booleans, by induction over the propositions
by
is derivable in NK.
CHAPTER 2. PROPOSITIONAL LOGIC 82
δX X = (X ⇒ ⊤) ∧ (¬X ⇒ ⊥)
and we have
(ax)
δX X, ¬X ⊢ (X ⇒ ⊤) ∧ (¬X ⇒ ⊥)
(∧rE ) (ax)
δX X, ¬X ⊢ ¬X ⇒ ⊥ δX X, ¬X ⊢ ¬X
(⇒E )
δX X, ¬X ⊢ ⊥
(¬I )
δX X ⊢ ¬¬X
(¬¬E )
δX X ⊢ X
(⇒I )
⊢ δX X ⇒ X
If A = Y with Y ̸= X, we have
δX Y = (X ⇒ Y ) ∧ (¬X ⇒ Y )
true under any valuation but are not derivable (theorem 2.3.5.2). One way to
understand this is that there are “not enough boolean models” in order to detect
that such formulas are not valid. A natural question is thus: is there a way to
generalize the notion of boolean model, so that intuitionistic natural deduction
is complete with respect to this generalized notion of model, i.e. a formula which
is valid in any such a model is necessarily intuitionistically provable? We will
see in section 2.8 that such a notion of model exists: Kripke models.
(** Formulas. *)
type t =
| Var of int
| And of t * t
| Or of t * t
| Not of t
| True | False
For the last step, various heuristics have been proposed for choosing the split-
ting variable such as MOM (a variable with Maximal number of Occurrences
in the clauses
P of Minimum size) or Jeroslow-Wang (a variable with maximum
−|C|
J(X) = C 2 where C ranges over clauses containing X and |C| is the
number of literals), and so on.
A concrete implementation is provided in figure 2.8. The function sub im-
plements substitution as described in theorem 2.5.7.2, the function unit finds a
unitary clause (or raises Not_found if there is none), the function pure finds a
pure literal (or raises Not_found) and finally the function dpll implements the
above algorithm. The function pure uses an auxiliary list vars of pairs X,b
where X is a variable and b is either Some true or Some false if the variable X
occurs only positively or negatively, or None if it occurs both positively and
negatively.
From a logical point of view, this deduction corresponds to the following reso-
lution rule:
Γ⊢C ∨X Γ ⊢ ¬X ∨ D
(res)
Γ⊢C ∨D
In the following, we implicitly consider formulas up to commutativity of dis-
junction, i.e. identify the formulas A ∨ B and B ∨ A, so that the above rule also
applies to clauses containing X and its negation:
Γ ⊢ C1 ∨ X ∨ C2 Γ ⊢ D1 ∨ ¬X ∨ D2
(res)
Γ ⊢ C1 ∨ C2 ∨ D1 ∨ D2
Γ ⊢ C′ ∨ X Γ ⊢ ¬X ∨ D′
Γ ⊢ C ′, X Γ ⊢ ¬X, D′
(wk R ) (wkR )
Γ ⊢ C ′ , X, D′ Γ ⊢ C ′ , ¬X, D′
(¬E )
Γ ⊢ C ′ , ⊥, D′
(⊥R )
Γ ⊢ C ′ , D′
ΓX = {C | C ∨ X ∈ Γ} Γ¬X = {D | ¬X ∨ D ∈ Γ}
and Γ′ for the set of clauses in Γ which contain neither X nor ¬X. We supposed
that the clauses are in canonical form, so that we have the following partition
of Γ:
Γ = Γ′ ⊎ {C ∨ X | C ∈ ΓX } ⊎ {¬X ∨ D | D ∈ Γ¬X }
The resolvent Γ \ X of Γ with respect to X is
Γ \ X = Γ′ ∪ {C ∨ D | C ∈ ΓX , D ∈ Γ¬X }
Remark 2.5.8.4. As defined above, the resolvent might contain clauses not in
canonical form, even if C and D are. In order to keep this invariant, we should
remove all clauses of the form C ∨ D such that C contains a literal and D its
negation, which we will implicitly do; in clauses, we should also remove duplicate
literals.
As indicated above, computing the resolvent reduces the number of free variables
of Γ:
Lemma 2.5.8.5. Given Γ in clausal form and a variable X, we have
The previous lemma implies that resolution is refutation complete in the sense
that it can always be used to show that a set of clauses cannot be satisfied (by
whichever valuation):
Theorem 2.5.8.7 (Refutation completeness). A set Γ of clauses is unsatisfiable
if and only if Γ ⊢ ⊥ can be proved using the axiom and resolution rules only.
Proof. Writing FV(Γ) = {X1 , . . . , Xn } for the free variables of Γ, define the
sequence of sets of clauses Γ0⩽i⩽n by Γ0 = Γ and Γi+1 = Γi \ Xi :
– the clauses of Γ0 can be deduced from those of Γ using the axiom rule,
– the clauses of Γi+1 can be deduced from those in Γi using the resolution
rule.
Theorem 2.5.8.6 ensures that Γi is satisfiable if and only if Γi+1 is satisfiable, and
thus, by induction, Γ0 is satisfiable if and only if Γn is satisfiable. Moreover,
by theorem 2.5.8.5, we have FV(Γn ) = ∅, thus Γn = ∅ or Γn = {⊥}, and
therefore Γn is unsatisfiable if and only if Γn = {⊥}. Finally, Γ is unsatisfiable
if and only if Γn = {⊥}, i.e. ⊥ can be deduced from Γ using axiom and resolution
rules.
let prove g c =
inconsistent ((neg c)::g)
As an application, we can prove theorem 2.5.8.9 with
let () =
let g = [
[false,0;true,1];
[false,1;true,2];
[true,0]
] in
let c = [true,2] in
assert (prove g c)
(ax)
¬(¬A ∨ A), A ` A
(ax) (∨rI )
¬(¬A ∨ A), A ` ¬(¬A ∨ A) ¬(¬A ∨ A), A ` ¬A ∨ A
(¬E )
¬(¬A ∨ A), A ` ⊥
(¬I )
¬(¬A ∨ A) ` ¬A
(ax) (∨lI )
¬(¬A ∨ A) ` ¬(¬A ∨ A) ¬(¬A ∨ A) ` ¬A ∨ A
(¬E )
¬(¬A ∨ A) ` ⊥
(¬I )
` ¬¬(¬A ∨ A)
One of the main ingredients behind this proof is that having ¬(¬A ∨ A) as
hypothesis in a context Γ allows to discard the current proof goal B and go
back to proving ¬A ∨ A:
..
.
(ax)
Γ ⊢ ¬(¬A ∨ A) Γ ⊢ ¬A ∨ A
(¬E )
Γ⊢⊥
(⊥E )
Γ⊢B
How is this better than proving ¬A ∨ A directly? The fact that, during the
proof, we can reset our proof goal to ¬A ∨ A! We thus start by proving ¬A ∨ A
by proving ¬A, which requires proving ⊥ from A. At this point, we change our
CHAPTER 2. PROPOSITIONAL LOGIC 92
mind and start again the proof of ¬A ∨ A, but this time we prove A, which we
can because we gained this information from the previously “aborted” proof.
A more detailed explanation of this kind of behavior was already developed
in section 2.5.2. This actually generalizes to any formula, by a result due to
Glivenko [Gli29]. Given a context Γ, we write ¬¬Γ for the context obtained
from Γ by double-negating every formula.
Theorem 2.5.9.1 (Glivenko’s theorem). Given a context Γ and propositional
formula A, the sequent Γ ⊢ A is provable in classical logic if and only if the
sequent ¬¬Γ ⊢ ¬¬A is provable in intuitionistic logic.
Proof. By induction on A (left as an exercise to the reader).
This result allows us to relate the consistency of classical and intuitionistic
logic in the following way.
Theorem 2.5.9.2. Intuitionistic logic is consistent if and only if classical logic is
consistent.
Proof. Suppose that intuitionistic logic is inconsistent: there is an intuitionistic
proof of ⊥. This proof is also a valid classical proof and thus classical logic is
inconsistent. Conversely, suppose that classical logic is inconsistent. There is
a classical proof of ⊥ and thus, by theorem 2.5.9.1, an intuitionistic proof π of
¬¬⊥. However, the implication ¬¬⊥ ⇒ ⊥ holds intuitionistically:
(ax)
¬¬⊥, ⊥ ⊢ ⊥
(ax) (¬I )
¬¬⊥ ⊢ ¬¬⊥ ¬¬⊥ ⊢ ¬⊥
(¬E )
¬¬⊥ ⊢ ⊥
(⇒I )
⊢ ¬¬⊥ ⇒ ⊥
X∗ = X
(A ∧ B)∗ = A∗ ∧ B ∗ (A ∨ B)∗ = ¬(¬A∗ ∧ ¬B ∗ )
⊤∗ = ⊤ ⊥∗ = ⊥
(A ⇒ B)∗ = A∗ ⇒ B ∗ (¬A)∗ = ¬A∗
CHAPTER 2. PROPOSITIONAL LOGIC 93
Finally, one can wonder if, by adding four negations to a formula, we could
gain even more proof power, but this is not the case: the process stabilizes after
the first iteration.
Lemma 2.5.9.4. For every natural number n > 0, we have ¬n+2 A ⇔ ¬n A.
Proof. The implication A ⇒ ¬¬A is intuitionistically provable, as already shown
in theorem 2.2.5.3, as well as the implication ¬¬¬A ⇒ ¬A:
(ax) (ax)
¬¬¬A, A, ¬A ` ¬A ¬¬¬A, A, ¬A ` A
(¬E )
¬¬¬A, A, ¬A ` ⊥
(ax) (¬I )
¬¬¬A, A ` ¬¬¬A ¬¬¬A, A ` ¬¬A
(¬E )
¬¬¬A, A ` ⊥
(¬I )
¬¬¬A ` ¬A
(⇒I )
` ¬¬¬A ⇒ ¬A
We conclude by induction on n.
In particular, ¬¬¬¬A ⇔ ¬¬A, so that we gain nothing by performing the
double-negation translation twice.
(A ⇒ B) ∨ (B ⇒ A)
Γ, B, A, Γ′ ⊢ ∆ Γ ⊢ ∆, B, A, ∆′
(xchL ) (xchR )
Γ, A, B, Γ′ ⊢ ∆ Γ ⊢ ∆, A, B, ∆
Γ, A, A, Γ′ ⊢ ∆ Γ ⊢ ∆, A, A, ∆′
(contrL ) (contrR )
Γ, A, Γ′ ⊢ ∆ Γ ⊢ ∆, A, ∆′
Γ, Γ′ ⊢ ∆ Γ ⊢ ∆, ∆′
(wkL ) (wkR )
Γ, A, Γ′ ⊢ ∆ Γ ⊢ ∆, A, ∆′
Γ, ⊤, Γ′ ⊢ ∆ Γ ⊢ ∆, ⊥, ∆′
(⊤L ) (⊥R )
Γ, Γ′ ⊢ ∆ Γ ⊢ ∆, ∆′
2.6.2 Rules. In all the systems we consider, unless otherwise stated, we always
suppose that we can permute, duplicate and erase formulas in context, i.e. that
the structural rules of figure 2.9 are always present. The additional rules for
sequent calculus are shown in figure 2.10 and the resulting system is called LK.
In sequent calculus, as opposed to natural deduction, the symmetry between
disjunction and conjunction has been restored: except for the axiom and cut, all
rules come in a left and right flavor. Although the presentation is quite different,
the provability power of this system is the same as the one for classical natural
deduction presented in section 2.5:
Theorem 2.6.2.1. A sequent Γ ⊢ ∆ is provable in NK (figure 2.5) if and only if
it is provable in LK (figure 2.10).
..
.
(ax)
Γ ⊢ A ∧ B, ∆ Γ, A, B ⊢ A, ∆
(wkR ) (∧L )
Γ ⊢ A ∧ B, A, ∆ Γ, A ∧ B ⊢ A, ∆
(cut)
Γ ⊢ A, ∆
Γ ⊢ A, ∆ Γ, A ⊢ ∆
(ax) (cut)
Γ, A ⊢ A, ∆ Γ⊢∆
Γ, A, B ⊢ ∆ Γ ⊢ A, ∆ Γ ⊢ B, ∆
(∧L ) (∧R )
Γ, A ∧ B ⊢ ∆ Γ ⊢ A ∧ B, ∆
(⊤R )
Γ ⊢ ⊤, ∆
Γ, A ⊢ ∆ Γ, B ⊢ ∆ Γ ⊢ A, B, ∆
(∨L ) (∨R )
Γ, A ∨ B ⊢ ∆ Γ ⊢ A ∨ B, ∆
(⊥L )
Γ, ⊥ ⊢ ∆
Γ ⊢ A, ∆ Γ, B ⊢ ∆ Γ, A ⊢ B, ∆
(⇒L ) (⇒R )
Γ, A ⇒ B ⊢ ∆ Γ ⊢ A ⇒ B, ∆
Γ ⊢ A, ∆ Γ, A ⊢ ∆
(¬L ) (¬R )
Γ, ¬A ⊢ ∆ Γ ⊢ ¬A, ∆
Γ ⊢ A, ∆ Γ ′ , A ⊢ ∆′
(ax) (cut)
A⊢A Γ, Γ ⊢ ∆, ∆′
′
Γ, A, B ⊢ ∆ Γ ⊢ A, ∆ Γ′ ⊢ B, ∆′
(∧L ) (∧R )
Γ, A ∧ B ⊢ ∆ Γ, Γ′ ⊢ A ∧ B, ∆, ∆′
(⊤R )
Γ ⊢ ⊤, ∆
Γ, A ⊢ ∆ Γ ′ , B ⊢ ∆′ Γ ⊢ A, B, ∆
(∨L ) (∨R )
Γ, Γ′ , A ∨ B ⊢ ∆, ∆′ Γ ⊢ A ∨ B, ∆
(⊥L )
Γ, ⊥ ⊢ ∆
Γ ⊢ A, ∆ Γ′ , B ⊢ ∆′ Γ, A ⊢ B, ∆
(⇒L ) (⇒R )
Γ, Γ′ , A ⇒ B ⊢ ∆, ∆′ Γ ⊢ A ⇒ B, ∆
Γ ⊢ A, ∆ Γ, A ⊢ ∆
(¬L ) (¬R )
Γ, ¬A ⊢ ∆ Γ ⊢ ¬A, ∆
X ∗ = ¬X (¬X)∗ = X
∗ ∗ ∗
(A ∧ B) = A ∨ B (A ∨ B)∗ = A∗ ∧ B ∗
⊤∗ = ⊥ ⊥∗ = ⊤
Because of this, we can restrict the system to sequents of the form ⊢ ∆, which
are called single-sided. All the rules preserve single-sidedness except for the
CHAPTER 2. PROPOSITIONAL LOGIC 98
(ax) (ax)
⊢ ∆, A∗ , ∆′ , A, ∆′′ ⊢ ∆, A, ∆′ , A∗ , ∆′′
⊢ ∆, A, ∆′ ⊢ ∆, A∗ , ∆′
(cut)
⊢ ∆, ∆′
⊢ ∆, A, ∆′ ⊢ ∆, B, ∆′ ⊢ ∆, A, B, ∆′
(∧) (∨)
⊢ ∆, A ∧ B, ∆′ ⊢ ∆, A ∨ B, ∆′
⊢ ∆, ∆′
(⊤) (⊥)
⊢ ∆, ⊤, ∆′ ⊢ ∆, ⊥, ∆′
axiom rule, which is easily modified in order to satisfy this property. With
some extra care, we can even come up with a presentation which does not
require any structural rules (those are admissible): the resulting presentation of
the calculus is given in figure 2.12. If we do not want to consider only formulas
where only variables can be negated, then the de Morgan laws can be added as
the following explicit rules:
⊢ ¬A ∨ ¬B, ∆ ⊢ ¬A ∧ ¬B, ∆ ⊢ ⊥, ∆ ⊢ ⊤, ∆ ⊢ A, ∆
⊢ ¬(A ∧ B), ∆ ⊢ ¬(A ∨ B), ∆ ⊢ ¬⊤, ∆ ⊢ ¬⊥, ∆ ⊢ ¬¬A, ∆
Γ`A Γ, A ` B
0 (ax) (cut)
Γ, A, Γ ` A Γ`B
Γ, A, B, Γ0 ` C Γ`A Γ`B
(∧L ) (∧R )
Γ, A ∧ B, Γ0 ` C Γ`A∧B
(>R )
Γ`>
Γ, A, Γ0 ` C Γ, B, Γ0 ` C Γ`A Γ`B
(∨L ) (∨lL ) (∨rL )
Γ, A ∨ B, Γ0 ` C Γ`A∨B Γ`A∨B
(⊥L )
Γ, ⊥, Γ0 ` A
Γ, A ⇒ B, Γ0 ` A Γ, B, Γ0 ` C Γ, A ` B
0 (⇒L ) (⇒R )
Γ, A ⇒ B, Γ ` C Γ`A⇒B
Γ, ¬A, Γ0 ` A Γ, A ` ⊥
(¬L ) (¬R )
Γ, ¬A, Γ0 ` ⊥ Γ ` ¬A
Proposition 2.6.5.1. LK has the subformula property: apart from the (cut) rule,
all the formulas occurring in the premise of a rule are subformulas of the formulas
occurring in the conclusion.
Since, by theorem 2.6.4.1, we can look for proofs without cuts, this means that
we never have to come up with a new formula during proof search! Moreover,
there is no harm in applying a rule whenever it applies thanks to the following
property:
Proposition 2.6.5.2. In LK, all the rules are reversible.
Proof search in intuitionistic logic. Proof search can be performed in LJ, but
the situation is more subtle. First note that, similarly to the situation in LK
(theorem 2.6.5.1), we have
Proposition 2.6.5.3. LJ has the subformula property.
As an immediate consequence, we deduce
Theorem 2.6.5.4. We can decide whether a sequent Γ ⊢ A is provable in LJ or
not.
Proof. There is only a finite number of subformulas of Γ ⊢ A. We can restrict
to sequents where a formula occurs at most 3 times in the context [Gir11,
section 4.2.2] and therefore there is a finite number of possible sequents formed
with those subformulas. By testing all the possible rules, we can determine
which of those are provable, and thus determine whether the initial sequent is
provable.
The previous theorem is constructive, but the resulting algorithm is quite inef-
ficient.
The problem of finding proofs is more delicate than for LK because not all
the rules are reversible: (∨lL ), (∨rL ) and (⇒L ) are not reversible. The rules (∨lL ),
CHAPTER 2. PROPOSITIONAL LOGIC 101
Γ, A, Γ′ ⊢ B X ∈ Γ, Γ′
(⇒X )
Γ, X ⇒ A, Γ′ ⊢ B
Γ, B ⇒ C, Γ′ ⊢ A ⇒ B Γ, C ⊢ D
′ (⇒⇒ )
Γ, (A ⇒ B) ⇒ C, Γ ⊢ D
Γ, A ⇒ (B ⇒ C), Γ′ ⊢ D Γ, A ⇒ C, B ⇒ C, Γ′ ⊢ D
(⇒∧ ) (⇒∨ )
Γ, (A ∧ B) ⇒ C, Γ′ ⊢ D Γ, (A ∨ B) ⇒ C, Γ′ ⊢ D
Γ, A, Γ′ ⊢ B Γ, Γ′ ⊢ B
(⇒⊤ ) (⇒⊥ )
Γ, ⊤ ⇒ A, Γ′ ⊢ B Γ, ⊥ ⇒ A, Γ′ ⊢ B
(∨rL ) are easy to handle when performing proof search: when trying to prove a
formula A ∨ B, we either try to prove A or to prove B. The rule (⇒L )
Γ, A ⇒ B, Γ′ ⊢ A Γ, B, Γ′ ⊢ C
(⇒L )
Γ, A ⇒ B, Γ′ ⊢ C
is more difficult to handle. If we apply it naively, it can loop for the same
reasons as in section 2.4.2:
.. ..
. .
(⇒L ) ..
Γ, A ⇒ B ⊢ A Γ, B ⊢ B .
(⇒L )
Γ, A ⇒ B ⊢ A Γ, B ⊢ B
(⇒L )
Γ, A ⇒ B ⊢ A
Although we can detect loops by looking at whether we encounter the same
sequent twice during the proof search, this is quite impractical. Also, since the
rule (⇒L ) is not reversible, the order in which we apply it during proof search
is relevant, and we would like to minimize the number of times we have to
backtrack.
The logic LJT was introduced by Dyckoff in order to overcome this prob-
lem [Dyc92]. It is obtained from LJ by replacing the (⇒L ) rule with the six
rules of figure 2.14, which allow proving sequents of the form
Γ, A ⇒ B, Γ′ ⊢ C
depending on the form of A.
Proposition 2.6.5.5. A sequent is provable in LJ if and only if it is provable
in LJT.
The main interest of this variant is that proof search is always terminating (thus
the T in LJT). Moreover, the rules (⇒∧ ), (⇒∨ ), (⇒⊤ ) and (⇒⊥ ) are reversible
and can thus always be applied during proof search. Many variants of this idea
have been explored, such as the SLJ calculus [GLW99].
A proof search procedure based on this sequent calculus can be implemented
as follows. We describe terms as usual as
CHAPTER 2. PROPOSITIONAL LOGIC 102
type t =
| Var of string
| Imp of t * t
| And of t * t
| Or of t * t
| True | False
The procedure which determines whether a formula is provable is then shown
in figure 2.15. This procedure takes as argument two contexts Γ′ and Γ (respec-
tively called env’ and env) and a formula A. Initially, the context Γ′ is empty;
it will be used to store the formulas of Γ which have already been “processed”.
The procedure first applies all the reversible right rules, then all the reversible
left rules; a formula of Γ which does not give rise to a reversible left rule is put
in Γ′ . Once this is done, the procedure tries to apply the axiom rule, handles
disjunctions by trying to apply either (∨lL ) or (∨rL ), and finally successively tries
all the possible applications of the non-reversible rules (⇒X ) and (⇒⇒ ). Here
the function context_formulas returns, given a context Γ, the list of all the
pairs consisting of a formula A and a context Γ′ , Γ′′ such that Γ = Γ′ , A, Γ′′ ,
i.e. the context Γ where some formula A has been removed.
Γ⊢A⇒B Γ⊢A
′ (ax) (⇒E )
Γ, A, Γ ⊢ A Γ⊢B
respectively called axiom and modus ponens. Of course, there is very little that
we can deduce with only these two rules. The other necessary logical principles
are added in the form of axiom schemes, which can be assumed at any time
during the proofs. In the case of the implicational fragment (implication is the
only connective with which the formulas are built), those are
(K) A ⇒ B ⇒ A,
(S) (A ⇒ B ⇒ C) ⇒ (A ⇒ B) ⇒ A ⇒ C.
By “axiom schemes”, we mean that the above formulas can be assumed for any
given formulas A, B and C. In other words, this amounts to adding the rules
(K) (S)
Γ⊢A⇒B⇒A Γ ⊢ (A ⇒ B ⇒ C) ⇒ (A ⇒ B) ⇒ A ⇒ C
A sequent is provable when it is the conclusion of a proof built from the above
rules, and a formula A is provable when the sequent ⊢ A is provable.
CHAPTER 2. PROPOSITIONAL LOGIC 103
2.7.2 Other connectives. In the case where connectives other than implica-
tion are considered, appropriate axioms should be added:
conjunction: A∧B ⇒A A⇒B ⇒A∧B
A∧B ⇒B
truth: A⇒⊤
disjunction: A ∨ B ⇒ (A ⇒ C) ⇒ (B ⇒ C) ⇒ C A⇒A∨B
B ⇒A∨B
falsity: ⊥⇒A
negation: ¬A ⇒ A ⇒ ⊥ A ⇒ ⊥ ⇒ ¬A
It can be observed that the axioms are in correspondence with elimination
and introduction rules in natural deduction (respectively left and right column
above). The classical variants of the system can be obtained by further adding
one of the axioms from theorem 2.5.1.1.
CHAPTER 2. PROPOSITIONAL LOGIC 105
Γ, A, B, Γ′ ⊢ C Γ, A, A ⊢ C Γ, ⊤ ⊢ A Γ⊢C
Γ, B, A, Γ′ ⊢ C Γ, A ⊢ C Γ⊢A Γ, A ⊢ C
Γ, A, Γ′ ⊢ B
(⇒I )
Γ, Γ′ ⊢ A ⇒ B
– If it is of the form
Γ, A, Γ′ ⊢ C Γ, A, Γ′ ⊢ C ⇒ B
(⇒E )
Γ, A, Γ′ ⊢ B
allows us to conclude.
CHAPTER 2. PROPOSITIONAL LOGIC 106
We can thus show that provability in this system is the usual one.
Theorem 2.7.3.3. A sequent Γ ⊢ A is provable in Hilbert calculus if and only if
it is provable in natural deduction.
(this is deliberately too small to read, you should prove this by yourself) and
(ax)
A, B ⊢ A
(⇒I )
A⊢B⇒A
(⇒I )
⊢A⇒B⇒A
w ⊨X iff ρ(w, X)
w ⊨⊤ holds
w ⊨⊥ does not hold
w ⊨A∧B iff w ⊨ A and w ⊨ B
w ⊨A∨B iff w ⊨ A or w ⊨ B
w ⊨A⇒B iff, for every w′ ⩾ w, w′ ⊨ A implies w′ ⊨ B
w ⊨ ¬A iff, for every w′ ⩾ w, w′ ⊨ A does not hold
The contrapositive of this theorem says that if we can find a Kripke structure
in which there is a world where a formula A is not satisfied, then A is not
intuitionistically provable. This thus provides an alternative to methods based
on cut-elimination (see section 2.3.5) in order to establish the non-provability
of formulas.
CHAPTER 2. PROPOSITIONAL LOGIC 108
X
· ·
w0 w1
A A A
· · · · · ·
w0 w1 w0 w1 w0 w1
In the two first cases, ¬¬A is satisfied and in the last one ¬A is satisfied.
Therefore, the weak excluded middle ¬¬A ∨ ¬A is always satisfied: this shows
that the weak excluded middle does not imply the excluded middle. By using a
similar reasoning, it can be shown that the linearity axiom (A ⇒ B) ∨ (B ⇒ A)
does not imply the excluded middle. Both thus give rise to intermediate logics,
see section 2.5.10.
Example 2.8.1.5. The Kripke structure
X Y
· · ·
In the first case, it is obvious that Φn+1 ⊬ A. In the second one, we have
Φn ⊢ B ∨ C and Φn , B ⊢ A, if we also had Φn , C ⊢ A then, by (∨E ), we would
S Φn ⊢ A, which is excluded by induction hypothesis. Finally, we take
also have
Φ = n∈N Φn .
A set Φ of formulas is saturated if, for every formula A, Φ ⊢ A implies A ∈ Φ.
Lemma 2.8.2.3. Given a set Φ of formulas, the set Φ = {A | Φ ⊢ A} is saturated.
A set is complete if it is consistent, disjunctive and saturated. Combining the
above lemmas we obtain,
Lemma 2.8.2.4. Given a set Φ of formulas and a formula A such that Φ ⊭ A,
there exists a complete set Φ such that Φ ⊆ Φ and A ̸∈ Φ.
Proof. By theorem 2.8.2.2, there exists a disjunctive set of formulas Φ such that
Φ ⊆ Φ and Φ ⊬ A. This set of consistent by theorem 2.8.2.1. Moreover, by
theorem 2.8.2.3, we can suppose that this set is saturated (the construction is
easily checked to preserve consistency and disjunctiveness) and such that A ̸∈ Φ.
W = {wΦ | Φ is complete}
– If A = B ∧ C.
Suppose that wΦ ⊨ B ∧ C. Then wΦ ⊨ B and wΦ ⊨ C, and therefore
Φ ⊢ B and Φ ⊢ C by induction hypothesis. We deduce Φ ⊢ B ∧ C by (∧I )
and weakening and thus B ∧ C ∈ Φ by saturation.
Conversely, suppose B∧C ∈ Φ and thus Φ ⊢ B∧C. This entails Φ ⊢ B and
Φ ⊢ C by (∧lE ) and (∧rE ), and thus B ∈ Φ and C ∈ Φ by saturation. By
induction hypothesis, we have wΦ ⊨ B and wΦ ⊨ C, and thus wΦ ⊨ B ∧ C.
CHAPTER 2. PROPOSITIONAL LOGIC 110
– If A = B ∨ C.
Suppose that wΦ ⊨ B ∨ C. Then wΦ ⊨ B or wΦ ⊨ C, and therefore Φ ⊢ B
or Φ ⊢ C by induction hypothesis. We deduce Φ ⊢ B ∨ C by (∨lI ) or (∨rI )
and thus B ∨ C ∈ Φ by saturation.
Conversely, suppose B ∨ C ∈ Φ. Since Φ is disjunctive, we have B ∈ Φ or
C ∈ Φ. By induction hypothesis, we have wΦ ⊨ B or wΦ ⊨ C, and thus
wΦ ⊨ B ∨ C.
– If A = B ⇒ C.
Suppose that wΦ ⊨ B ⇒ C. Our goal is to show B ⇒ C ∈ Φ. By (⇒I )
and saturation, it is enough to show Φ, B ⊢ C. Suppose that it is not
the case. By theorem 2.8.2.4, we can construct a complete set Φ′ with
Φ ⊆ Φ′ , B ∈ Φ′ and C ̸∈ Φ′ .