-- Copyright (C) 2025 Eric Klavins -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version.

UNDER CONSTRUCTION
Code for this chapter

Propositional Logic Connectives

One of the remarkable things about inductive types is that the capture all of propositional logic, first order logic, and more. Thus, instead of defining and, or and the other logical connectives as built-in operators in the Lean language, they are just defined in the standard library in terms of more primited inductive types.

namespace Temp

And is an Inductive Type

Recall the inference rule

                 Γ ⊢ φ   Γ ⊢ ψ
    ∧-Intro ———————————————————
                  Γ ⊢ φ ∧ ψ

It states that whenever we know propositions φ and ψ, then we know φ ∧ ψ. From the point of view of types, it says that if φ and ψ are of type Prop, then so is φ ∧ ψ. In Lean we can write this as an inductive type definition as follows.

inductive And (φ ψ : Prop) : Prop where
  | intro : φ → ψ → And φ ψ

You can think of h : And p q as

  • h has type And p q
  • h is evidence that the type And p q is not empty
  • h is a proof of the proposition And p q.

A Proof of a Simple Proposition

Consider the proposition

p → q → And p q

As a type, this proposition is a function from p to q to And p q. Thus, we know that an element of this type has the form

λ hp => λ hq => sorry

For the body of this lambda abstraction, we need to introduce an And type, which requires proofs of p and q respectively. Using the inductive definition of And we get

λ hp hq => And.intro hp hq
def g (p q : Prop) : p → q → And p q :=
  λ hp => λ hq => And.intro hp hq

And Eliminiation

The elimination rules for And are

                Γ ⊢ φ ∧ ψ                          Γ ⊢ φ ∧ ψ
  ∧-Elim-Left ——————————————         ∧-Elim-Right —————————————
                  Γ ⊢ φ                              Γ ⊢ ψ

which we can write in Lean as

def And.left {p q : Prop} (hpq : And p q) :=
  match hpq with
  | And.intro hp _ => hp

def And.right {p q : Prop} (hpq : And p q) :=
  match hpq with
  | And.intro _ hq => hq

Proofs with And-Elimination

With these inference rules, we can do even more proofs:

example (p q : Prop) : (And p q) → p :=
  λ hpq => And.left hpq

example (p q : Prop) : (And p q) → (And q p) :=
  λ hpq => And.intro hpq.right hpq.left

Match is Enough

Note that the elimination rules above are a convenience we defined to make the proof look more like propositional logic. We could also just write:

example (p q : Prop) : (And p q) → p :=
  λ hpq => match hpq with
    | And.intro hp _ => hp

This pattern suggests that with inductive types, we can think of match as a generic elimination rule.

Or is Inductive

To introduce new OR propositions, we use the two introduction rules

                 Γ ⊢ φ                              Γ ⊢ ψ
 ∨-Intro-Left ———————————          ∨-Intro-Right ————————————
               Γ ⊢ φ ∨ ψ                          Γ ⊢ φ ∨ ψ

In Lean, we have

inductive Or (φ ψ : Prop) : Prop where
  | inl (h : φ) : Or φ ψ
  | inr (h : ψ) : Or φ ψ

And we can use this inference rule in proofs as well.

example (p q : Prop) : And p q → Or p q :=
  λ hpq => Or.inr hpq.right

Or Elimination

Recall the inference rule

           Γ,p ⊢ r    Γ,q ⊢ r    Γ ⊢ p ∨ q
  ∨-Elim ————————————————————————————————————
                       Γ ⊢ r

It allows us to prove r given proofs that p → r, q → r and p ∨ q. We can define this rule in Lean with:

def Or.elim {p q r : Prop} (hpq : Or p q) (hpr : p → r) (hqr : q → r) :=
  match hpq with
  | Or.inl hp => hpr hp
  | Or.inr hq => hqr hq

Example of and Or-Elim Proof

Here is an example proof using introduction and elimination.

example (p q : Prop): Or p q → Or q p :=
  λ hpq => Or.elim
    hpq                               -- p ∨ q
    (λ hp => Or.inr hp)               -- p → (q ∨ p)
    (λ hq => Or.inl hq)               -- q → (q ∨ p)

Once again, the elimination rule is just a convenience and the proof could be written with match.

False is Inductive

Finally, we have False, which has no introduction rule, kind of like Empty, except we add the requirement that False is also type of Prop.

inductive False : Prop

From False we get the Not connective, which is just "syntactic sugar".

def Not (p : Prop) : Prop := p → False

Here is an example proof:

example (p q : Prop): (p → q) → (Not q → Not p) :=
  λ hpq hq => λ hp => hq (hpq hp)

False Elimination

To define the elimination rule for false

           Γ ⊢ ⊥
  ⊥-Elim ——————————
           Γ ⊢ p

we take advantage of the fact that False was defined inductively.

def False.elim { p : Prop } (h : False) : p :=
  nomatch h

Here is an example proof that from False you can conclude anything:

example (p q : Prop): And p (Not p) → q :=
  λ h => False.elim (h.right h.left)

By the way, this is another way to prove the HW1 example:

example : False → True :=
  λ h => False.elim h

Notation

The main difference between what we have defined here and Lean is that Lean defines notation like and . We won't redo that entire infrastructure here. But to give a sense of it, here is how Lean defines infix notation for Or and And and Not notation.

infixr:30 " ∨ "  => Temp.Or
infixr:35 " ∧ "   => Temp.And
notation:max "¬" p:40 => Temp.Not p

The numbers define the precedence of the operations. So v has lower precedence than , which has lower precedence than -.

Now we can write

end Temp -- start using Lean's propositions

example (p q : Prop): (p ∧ (¬p)) → q :=
  λ h => False.elim (h.right h.left)

Examples

You should try to do as many of these as possible. These are borrowed from the Theorem Proving in Lean Book.

variable (p q r : Prop)

example (h : p ∨ q) : q ∨ p := sorry
example : p ∧ q ↔ q ∧ p := sorry
example : p ∨ q ↔ q ∨ p := sorry
example : (p ∨ q) ∨ r ↔ p ∨ (q ∨ r) := sorry
example : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) := sorry
example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) := sorry
example : (p → (q → r)) ↔ (p ∧ q → r) := sorry
example : ((p ∨ q) → r) ↔ (p → r) ∧ (q → r) := sorry
example : ¬(p ∨ q) ↔ ¬p ∧ ¬q := sorry
example : ¬p ∨ ¬q → ¬(p ∧ q) := sorry
example : ¬(p ∧ ¬p) := sorry
example : p ∧ ¬q → ¬(p → q) := sorry
example : ¬p → (p → q) := sorry
example : (¬p ∨ q) → (p → q) := sorry
example : p ∨ False ↔ p := sorry
example : p ∧ False ↔ False := sorry
example : (p → q) → (¬q → ¬p) := sorry
example : (p → q) → (¬q → ¬p) := sorry

References

  • https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html

  • Homotypy Type Theory Book https://homotopytypetheory.org/book/ Chapter 5 covers inductive types

 

Copyright © 2025 Eric Klavins