Interactive Theorem Proving in Lean

Lean logo

Compact course
Heidelberg Graduate School
Mathematical and Computational Methods for the Sciences

Florent Schaffhauser
Heidelberg University

Interactive Theorem Proving in Lean - Lecture 3

Outline of the lectures

  • Lecture 1: An introduction to Lean.
  • Lecture 2: Tactics.
  • Lecture 3: Dependent types.
  • Lecture 4: Algebraic structures.
Interactive Theorem Proving in Lean - Lecture 3

Recap from Lecture 2

  • Propositions are defined as types. We can form new propositions from old ones using , , and . The modus ponens rule corresponds to evaluating a function.
  • The logic is not external to our typing system. There are no truth values or truth tables. The rules of inference are syntactic rules, not axioms.
  • To prove a theorem, you write a program. If the program type-checks, the theorem is proved.
  • To write proofs in Lean, you can get assistance from the compiler by entering Lean's tactic mode.
  • In this lecture, we will learn how to encode the and quantifiers, so we can state and prove more sophisticated mathematical statements.
Interactive Theorem Proving in Lean - Lecture 3

Lecture 3 - Dependent types

  1. Type families and dependently-typed functions.
  2. Existential and universal statements.
  3. Formal mathematics.
Interactive Theorem Proving in Lean - Lecture 3

Practice file

If you prefer to use this time to learn more advanced tactics instead, here is a practice file:

Practice File QR Code Advanced tactics

Interactive Theorem Proving in Lean - Lecture 3

Type families and dependently-typed functions

  • Type families.
  • Dependently-typed functions.
  • Universes.
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Many kinds of functions

  • So far, we have worked mostly with basic functions, such as square : ℕ → ℕ or fact : ℕ → ℕ. These are simply-typed functions, from a type to a type.
  • But in fact, we have also seen type formers, such as Prod : Type → Type → Type or Sum, which takes types as inputs and returns a type. Another common example would be List : Type → Type.
  • For a fixed type X, the type List X is defined inductively: you start with the empty list and then prepend terms of type X.
inductive List (X : Type) : Type
  | nil  : List X
  | cons : XList XList X

#check @List  -- List : Type → Type
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Terms that depend on types, types that depend on terms

So far, we have seen:

  • Terms that depend on terms (simply-typed functions).
  • Types that depend on types (type formers).

There should be:

  • Terms that depend on types (polymorphic functions).
  • Types that depends on terms (type families).
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Polymorphic functions

A polymorphic function is a function that takes a type as an argument. The simplest polymorphic function is the identity function:

def id {X : Type} : XX := fun x ↦ x

#check id  -- id {X : Type} :  X → X
  • id is indeed a term that depends (implicitely) on a type. For instance, id (X := Nat) (also denoted by @id Nat) is a term of type Nat → Nat, i.e. a function from Nat to Nat.
  • id is an example of an overloaded term: whatever the type X, we may denote its identity function simply by id, so an expression such as id (3 : Nat) is well-typed (and of type Nat).
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Type families

  • A type family parameterised by X is a function F: X → Type, so indeed types that depend on terms: for all x : X, F x is a type.
  • As an example, you can think of the type family Tuples : Nat → Type such that Tuples n is the type of lists of integers of length n:
    Tuples n := {L : List Int // List.length L = n}.
  • If you put all of these together, you get a so-called -type, for instance List Int, which you can picture as the sum of all the Tuples n.
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Dependent pairs

  • Given a type family F: X → Type, we can form the associated -type, sometimes denoted by (x : X) × F x, whose terms are called dependent pairs and are of the form ⟨x, t⟩ where x : X and t : F x.
  • For instance ⟨2, [1, -1]⟩ is a term of type (n : Nat) × Tuples n. Another possible notation would be Sigma Tup, where Tuples : Nat → Type. And the classical type-theoretic notation would be:

  • Dependent pairs generalize usual pairs: if for all x : X, we have F x = Y, then
    ((x : X) × F x) = (X × Y).
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Representation of a -type

Un Sigma-tipo

Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Formal definition of a -type

Given a type family F: X → Type, the associated -type is an inductive type with a single constructor. The type Sigma F defined in this way can be denoted by (x : X) × F x.

inductive Sigma {X : Type} (F : XType) 
  | mk (x : X) (t : F x) : Sigma F

Projection to the first factor can be defined by pattern matching (which under the hood calls upon the induction principle associated to the inductive type Sigma F):

def pr₁ {X : Type} {F : XType} : Sigma FX
  | Sigma.mk x t => x
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Dependently-typed functions

  • We can also use type families F : X → Type to define so-called -types (also called types of dependent functions).
  • A dependent function is a function f : (x : X) → F x whose return type depends on the input value.
  • The classical type-theoretic notation for the type of dependent functions (x : X) → F x is

  • This generalizes function types: if for all x : X, we have F x = Y, then
    ((x : X) → F x) = (X → Y).
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

An example: the zero-tuple function

  • Let us define a function zero-tuple : (n : ℕ) → Tuples n. We proceed by induction.
  • For n = 0, we set zero-tuple 0 := ([] : List Int) (the empty list). If zero-tuple n : Tuples n is defined, we set zero-tuple (n + 1) := (0 :: zero-tuple n), which is indeed of type Tuples (n + 1).
  • Can you implement this in Lean? 😅 Whoever finishes first gets a ☕, on me!
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Relations between -types and -types

  • A -type comes equipped with a second projection, which is a dependent function, defined by pattern matching.
def pr₂ {X : Type} {F : XType} : (p : Sigma F) → F (pr₁ p)
  | Sigma.mk x t => t
  • We can use this projection to establish an equivalence between dependent functions of the form and sections of .

  • This equivalence is induced by the function that sends a dependent function to the function defined by

Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Representation of a -type

Un Pi-tipo

Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Barendregt's -cube

  • We have generalised simply-typed functions in three directions: type formers, polymorphic functions and type families. Each combination of these enriches the typing system.
  • The vertex represents the calculus of constructions. Together with inductive types, it enables us to formalise a surprising amount of mathematics.

Barendregt's lambda-cube By Tellofou - Own work, CC BY-SA 4.0

Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Universes

  • If you #check the type of List that we have defined, you will find that it is of type Type → Type. To be able to write this, we need to be able to treat Type as a term. But of what type?
  • In Lean, Type is a term of type Type 1. As a consequence, type formers with values in Type are also terms of type Type 1.
  • This is a feature of theory: in order to control the process of type formation, we need a hierarchy of so-called universes. This is how paradoxes similar to Russell's paradox are avoided in type theory.
  • Roughly speaking, a universe is a type whose terms are also types. In Lean, Prop is a universe, of type Type (also denoted by Type 0). You can think of Type l as the universe of types of level l (we will not define this further here).
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Hierarchy of universes and coercions

  • We have already seen the need to work with universes to perform certain polymorphic operations on types (such as taking lists or marking points).
  • A universe is a type whose terms are types and that is stable under the operations

  • Following Grothendieck and Martin-Löf, we postulate the existence of a hierarchy of universes , where is a natural number. In particular, there is a universe .
  • This hierarchy is cumulative in the sense that if , then . In practice, this means implementing coercions: if we have two types and , we can construct etc. and they will be terms of type .
  • A type belongs to a universe but there is no universe of all types, as that would lead to a paradox of the Burali-Forti or Girard persuasion.
Interactive Theorem Proving in Lean - Lecture 3
Type families and dependently-typed functions

Dependent type theory in a nutshell

Dependent type theory in a nutshell

Interactive Theorem Proving in Lean - Lecture 3

Existential and universal statements

  • The existential quantifier .
  • The universal quantifier .
Interactive Theorem Proving in Lean - Lecture 3
Existential and universal statements

The existential quantifier

  • Remarkably, we can use dependent pairs to define propositions with an existential quantifier.
  • Take for instance a complex number z : ℂ and consider the proposition z ^ 2 = -1. Thinking of propositions-as-types, this defines a type family F : ℂ → Prop.
  • Then, we can interpret a dependent pair ⟨z, p⟩, where p : z ^ 2 = -1 (so p is a proof of z ^ 2 = -1), as a proof that -1 has a square root in .
Interactive Theorem Proving in Lean - Lecture 3
Existential and universal statements

Existential statements

  • Given a predicate P : X → Prop on a type X, the proposition ∃ x : X, P x is the proposition defined inductively as follows.
inductive Exists {X : Type} (P : XProp) : Prop
  | intro (x : X) (p : P x) : Exists P
  • This means that, in order to prove that ∃ x : X, P x, you need to construct a term x : X (a witness) and a proof of the proposition P x (the evidence).
  • We see that this is again a constructive approach to existential statements: in general, saying that ¬(∀ x : X, ¬(P x)) is weaker than saying that ∃ x : X, P x.
Interactive Theorem Proving in Lean - Lecture 3
Existential and universal statements

Universal quantifiers

  • Let us use dependent functions to define propositions with a universal quantifier.
  • Take for instance a real number x : ℝ and consider the proposition x ^ 2 ≥ 0. Thinking of propositions-as-types, this defines a type family F : ℝ → Prop.
  • Then, a dependent function f : (x : ℝ) → x ^ 2 ≥ 0 sends to a real number x to a proof of x ^ 2 ≥ 0. So we can interpret such a dependent function f as a proof of the proposition ∀ x : ℝ, x ^ 2 ≥ 0.
Interactive Theorem Proving in Lean - Lecture 3
Existential and universal statements

Universal statements

  • Given a predicate P : X → Prop on a type X, the proposition ∀ x : X, P x is the proposition defined by the type of dependent functions (x : X) → P x.
  • In particular, in order to prove such a universal statement, you must define a function, so you start your proof with fun x ↦ _ (if you are in term mode) or intro x (if you are in tactic mode).
  • For instance, if you want to prove that ∀ w : ℂ, ∃ z : ℂ, z ^ 2 = w, then intro w will change your goal to ∃ z : ℂ, z ^ 2 = w, for a w that is now fixed. Then you have to construct a square root of w to conclude.
  • Note that there might be more than one witness z : ℂ for the property z ^ 2 = w, but this piece of data cannot be recovered from the existential statement itself!
Interactive Theorem Proving in Lean - Lecture 3

Formal mathematics

  • Propositions and sub-types.
  • The type of propositions.
Interactive Theorem Proving in Lean - Lecture 3
Formal mathematics

Propositions and subtypes

  • A proposition can be formally defined as a type for which the following property holds: : (a b : A) → a = b, meaning that to any two arbitrary terms a and b of type A, there is associated an identification a = b.
  • Propositions can be used to define subtypes of a type : given a predicate , a subtype of is defined as a particular case of a -type.

  • In Lean, the identity types A := (x = y) for x, y in some type X are all propositions. The detailed study of identity types is a fundamental topic in homotopy type theory. For instance, it can be proven that, for all type A, the type IsProp A is a proposition 😅.
Interactive Theorem Proving in Lean - Lecture 3
Formal mathematics

The type of propositions

  • By viewing propositions as types, and using inductive types, dependent functions, and universes, we can formalize a large amount of mathematics.
theorem FLT {n : Nat} {x y z : Int} : (n > 2) → x ^ n + y ^ n = z ^ n → x * y * z = 0
  • Voevodsky's homotopy type theory refines this further by constructing the type of propositions in a universe as a subtype of . For instance, the FLT type introduced above is a proposition 👌.
  • Note that if and are propositions, the type is a proposition but the type is not a proposition. To construct the proposition , we must take a quotient in order to identify proofs of with proofs of (this is known as proof irrelevance or truncation).
Interactive Theorem Proving in Lean - Lecture 3
Formal mathematics

Wrap-up and where to go from here

  • Besides simply-typed functions, we can define type formers, polymorphic functions and type families.
  • From a type family F : X → Type, we define an associated -type (the type of dependent pairs (x : X) × (F x)) and an associated -type (the type of dependent functions (x : X) → F x).
  • Given a predicate P : X → Prop, the proposition ∃ x : X, P x is the proposition whose proofs are constructed using dependent pairs (x : X) ×' (P x). And a proof of the proposition ∀ x : X, P x is a dependent function (x : X) → P x.
  • Now we can prove state some theorems 💻 ! We can actually formalise a remarkable amount of mathematics.
Interactive Theorem Proving in Lean - Lecture 3
Formal mathematics

Exercises on advanced tactics

Practice File QR Code Advanced tactics

Interactive Theorem Proving in Lean - Lecture 3

Still missing: the fantastic drawing about Sigma-types and Pi-types.