Stefano M. Nicoletti

Lecture 3: From Natural Deduction to Proofs in Lean

1. Aim of the lecture

In the previous lecture, we learned to read a proof state and used tactics such as intro, apply, have, exact, and cases. We now connect those commands to the rules of natural deduction. Tactics are not arbitrary moves: they build and use proofs according to the logical structure of propositions.

The lecture has five aims:

2. Types and inhabitants

A type describes a class of possible objects. A type is inhabited when there is at least one term of that type. If t has type T, we write t : T and say that t inhabits T.

The idea is not limited to Lean. The informal type “moon of Jupiter” is inhabited because Io is a moon of Jupiter. Io is a concrete object satisfying the description expressed by the type NASA Science, Io: Facts.

#check 4          -- 4 : Nat
#check True       -- True : Prop
#check True.intro -- True.intro : True

Nat is inhabited, for example, by 4. True is also inhabited: True.intro has exactly type True. This observation leads from the general relation between terms and types to the relation between proofs and propositions.

3. The Curry-Howard correspondence

Under the Curry-Howard correspondence, propositions and types are two ways of describing the same structure. A proposition specifies what must be proved; the corresponding type specifies what kind of term must be built. A proof of the proposition is a term inhabiting that type Wadler, Propositions as Types.

LogicType theory
propositiontype
proofterm
A → Bfunction from proofs of A to proofs of B
introduction of →function construction
elimination of →function application

Checking a proof therefore means checking that the constructed term has the declared type. A derivation does not merely certify that a proposition is true: it specifies how to construct its proof Theorem Proving in Lean 4, Propositions and Proofs.

4. Natural deduction and the proof state

Natural deduction presents a proof as a sequence of local steps governed by rules. Each rule shows how to obtain a conclusion from premises. Introduction rules explain how to construct a proof with a particular main connective; elimination rules explain how to use an available proof containing that connective Logic and Proof, Natural Deduction for Propositional Logic.

A judgment has the form Γ ⊢ A. Here Γ is the context of currently available assumptions and A is the conclusion to derive. Lean's proof state has the same organization: the context appears above the turnstile and the goal after it.

Some rules introduce temporary assumptions. To prove A → B, for example, we temporarily assume A and construct B. Once the implication is complete, the assumption has been incorporated into a function from proofs of A to proofs of B.

5. Implication

Implication introduction, →I

Implication introduction, →I

To prove A → B, we introduce an assumption of type A and construct a proof of B. In Lean, intro performs precisely this step.

We want to prove that if it rains and it is cold, then it rains. We introduce the assumption that it rains and is cold; we obtain that it rains by taking the left component; we use exactly that fact.

-- Every example follows the same path: a natural-deduction rule, its reading -- in natural language, a concrete instance, and a term built in the proof state. -- Implication introduction, →I. -- To prove `A → B`, we introduce the temporary assumption `A` and construct `B`. -- Example: if it rains and it is cold, then it rains. theorem lecture03_imp_intro (Rains IsCold : Prop) : Rains ∧ IsCold → Rains := Rains:PropIsCold:Prop⊢ Rains ∧ IsCold → Rains Rains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsCold⊢ Rains Rains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsColdhRains:Rains⊢ Rains All goals completed! 🐙

Implication elimination, →E

Implication elimination, →E

If we have A → B and A, we apply the first proof to the second and obtain B. This is modus ponens.

-- Implication elimination, →E: modus ponens. -- From `A → B` and `A`, we obtain `B`. -- Example: if it rains, I take the umbrella; it rains; therefore I take it. theorem lecture03_imp_elim (Rains TakeUmbrella : Prop) (hRainsUmbrella : Rains → TakeUmbrella) (hRains : Rains) : TakeUmbrella := Rains:PropTakeUmbrella:ProphRainsUmbrella:Rains → TakeUmbrellahRains:Rains⊢ TakeUmbrella Rains:PropTakeUmbrella:ProphRainsUmbrella:Rains → TakeUmbrellahRains:RainshTakeUmbrella:TakeUmbrella⊢ TakeUmbrella All goals completed! 🐙

hRainsUmbrella behaves as a function: it receives a term of type Rains and returns a term of type TakeUmbrella.

6. Conjunction

Conjunction introduction, ∧I

Conjunction introduction, ∧I

To prove A ∧ B, we must construct both components. Applying And.intro splits the goal into two cases: first A, then B.

-- Conjunction introduction, ∧I. -- From a proof of A and a proof of B, we construct a proof of A ∧ B. theorem lecture03_and_intro (Rains IsCold : Prop) (hRains : Rains) (hIsCold : IsCold) : Rains ∧ IsCold := Rains:PropIsCold:ProphRains:RainshIsCold:IsCold⊢ Rains ∧ IsCold Rains:PropIsCold:ProphRains:RainshIsCold:IsCold⊢ RainsRains:PropIsCold:ProphRains:RainshIsCold:IsCold⊢ IsCold Rains:PropIsCold:ProphRains:RainshIsCold:IsCold⊢ Rains All goals completed! 🐙 Rains:PropIsCold:ProphRains:RainshIsCold:IsCold⊢ IsCold All goals completed! 🐙

The bullets belong to distinct goals, corresponding to the two conjuncts.

Conjunction elimination, ∧Eₗ and ∧Eᵣ

Left conjunction elimination, ∧Eₗ
Right conjunction elimination, ∧Eᵣ

A proof of A ∧ B contains a proof of A and a proof of B. We select the left component with .left and the right component with .right.

theorem lecture03_and_elim_left (Rains IsCold : Prop) (hBoth : Rains ∧ IsCold) : Rains := Rains:PropIsCold:ProphBoth:Rains ∧ IsCold⊢ Rains Rains:PropIsCold:ProphBoth:Rains ∧ IsColdhRains:Rains⊢ Rains All goals completed! 🐙
theorem lecture03_and_elim_right (Rains IsCold : Prop) (hBoth : Rains ∧ IsCold) : IsCold := Rains:PropIsCold:ProphBoth:Rains ∧ IsCold⊢ IsCold Rains:PropIsCold:ProphBoth:Rains ∧ IsColdhIsCold:IsCold⊢ IsCold All goals completed! 🐙

Introduction constructs a conjunction from its components; elimination travels in the opposite direction and retrieves a component.

7. Disjunction

Disjunction introduction, ∨Iₗ and ∨Iᵣ

Left disjunction introduction, ∨Iₗ
Right disjunction introduction, ∨Iᵣ

To prove A ∨ B, it is enough to construct one side, but we must specify which one. Or.inl chooses the left side; Or.inr chooses the right side.

-- Left disjunction introduction, ∨Iₗ. theorem lecture03_or_intro_left (Rains Snows : Prop) (hRains : Rains) : Rains ∨ Snows := Rains:PropSnows:ProphRains:Rains⊢ Rains ∨ Snows Rains:PropSnows:ProphRains:Rains⊢ Rains All goals completed! 🐙
-- Right disjunction introduction, ∨Iᵣ. theorem lecture03_or_intro_right (Rains Snows : Prop) (hSnows : Snows) : Rains ∨ Snows := Rains:PropSnows:ProphSnows:Snows⊢ Rains ∨ Snows Rains:PropSnows:ProphSnows:Snows⊢ Snows All goals completed! 🐙

Disjunction elimination, ∨E

Disjunction elimination, ∨E

If we have A ∨ B, we do not know which side was proved. To obtain one conclusion C, we must derive it both in the A case and in the B case.

-- Disjunction elimination, ∨E. -- From `A ∨ B`, `A → C`, and `B → C`, we obtain C by cases. theorem lecture03_or_elim (Rains Snows TakeUmbrella : Prop) (hRainsOrSnows : Rains ∨ Snows) (hRainsUmbrella : Rains → TakeUmbrella) (hSnowsUmbrella : Snows → TakeUmbrella) : TakeUmbrella := Rains:PropSnows:PropTakeUmbrella:ProphRainsOrSnows:Rains ∨ SnowshRainsUmbrella:Rains → TakeUmbrellahSnowsUmbrella:Snows → TakeUmbrella⊢ TakeUmbrella cases hRainsOrSnows with Rains:PropSnows:PropTakeUmbrella:ProphRainsUmbrella:Rains → TakeUmbrellahSnowsUmbrella:Snows → TakeUmbrellahRains:Rains⊢ TakeUmbrella Rains:PropSnows:PropTakeUmbrella:ProphRainsUmbrella:Rains → TakeUmbrellahSnowsUmbrella:Snows → TakeUmbrellahRains:RainshTakeUmbrella:TakeUmbrella⊢ TakeUmbrella All goals completed! 🐙 Rains:PropSnows:PropTakeUmbrella:ProphRainsUmbrella:Rains → TakeUmbrellahSnowsUmbrella:Snows → TakeUmbrellahSnows:Snows⊢ TakeUmbrella Rains:PropSnows:PropTakeUmbrella:ProphRainsUmbrella:Rains → TakeUmbrellahSnowsUmbrella:Snows → TakeUmbrellahSnows:SnowshTakeUmbrella:TakeUmbrella⊢ TakeUmbrella All goals completed! 🐙

cases eliminates the disjunction by making all possible forms explicit.

8. Negation, truth, and falsity

Negation

In Lean, ¬A is defined as A → False. A proof of ¬A is therefore a function taking every hypothetical proof of A to a contradiction.

Negation introduction, ¬I

To introduce ¬A, we introduce A and construct False.

-- Negation introduction, ¬I. -- To prove `¬A`, we introduce A and derive False. theorem lecture03_not_intro (DrinkCoffee StayAwake : Prop) (hCoffeeAwake : DrinkCoffee → StayAwake) (hNotAwake : ¬StayAwake) : ¬DrinkCoffee := DrinkCoffee:PropStayAwake:ProphCoffeeAwake:DrinkCoffee → StayAwakehNotAwake:¬StayAwake⊢ ¬DrinkCoffee DrinkCoffee:PropStayAwake:ProphCoffeeAwake:DrinkCoffee → StayAwakehNotAwake:¬StayAwakehDrinkCoffee:DrinkCoffee⊢ False DrinkCoffee:PropStayAwake:ProphCoffeeAwake:DrinkCoffee → StayAwakehNotAwake:¬StayAwakehDrinkCoffee:DrinkCoffeehStayAwake:StayAwake⊢ False DrinkCoffee:PropStayAwake:ProphCoffeeAwake:DrinkCoffee → StayAwakehNotAwake:¬StayAwakehDrinkCoffee:DrinkCoffeehStayAwake:StayAwakehContradiction:False⊢ False All goals completed! 🐙
Negation elimination, ¬E

To eliminate a negation, we apply ¬A to A and obtain False.

theorem lecture03_not_elim (LabOpen : Prop) (hOpen : LabOpen) (hNotOpen : ¬LabOpen) : False := LabOpen:ProphOpen:LabOpenhNotOpen:¬LabOpen⊢ False LabOpen:ProphOpen:LabOpenhNotOpen:¬LabOpenhContradiction:False⊢ False All goals completed! 🐙

Truth and falsity

Truth introduction, ⊤I

True has a canonical constructor and requires no assumptions.

-- Truth introduction, ⊤I. theorem lecture03_true_intro : True := ⊢ True All goals completed! 🐙 -- Alternatively: trivial

exact True.intro can also be replaced by trivial.

Falsity elimination, ⊥E

False has no constructors. If the context already contains a proof of False, we can eliminate falsity and obtain any proposition. This is the principle of ex falso quodlibet.

-- Falsity elimination, ⊥E. theorem lecture03_false_elim (Rains : Prop) (hContradiction : False) : Rains := Rains:ProphContradiction:False⊢ Rains Rains:ProphContradiction:False⊢ False -- Alternatively: exfalso All goals completed! 🐙

The rule does not let us prove anything arbitrarily: it applies only after a contradiction has been constructed.

9. Biconditional

A proof of A ↔ B contains two functions: one from A to B and one from B to A.

Biconditional introduction, ↔I

Biconditional introduction, ↔I

To prove that “it rains and it is cold” is equivalent to “it is cold and it rains,” we construct both directions.

-- Biconditional introduction, ↔I: construct both directions. theorem lecture03_iff_intro (Rains IsCold : Prop) : Rains ∧ IsCold ↔ IsCold ∧ Rains := Rains:PropIsCold:Prop⊢ Rains ∧ IsCold ↔ IsCold ∧ Rains Rains:PropIsCold:Prop⊢ Rains ∧ IsCold → IsCold ∧ RainsRains:PropIsCold:Prop⊢ IsCold ∧ Rains → Rains ∧ IsCold Rains:PropIsCold:Prop⊢ Rains ∧ IsCold → IsCold ∧ Rains Rains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsCold⊢ IsCold ∧ Rains Rains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsCold⊢ IsColdRains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsCold⊢ Rains Rains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsCold⊢ IsCold All goals completed! 🐙 Rains:PropIsCold:ProphRainsAndIsCold:Rains ∧ IsCold⊢ Rains All goals completed! 🐙 Rains:PropIsCold:Prop⊢ IsCold ∧ Rains → Rains ∧ IsCold Rains:PropIsCold:ProphIsColdAndRains:IsCold ∧ Rains⊢ Rains ∧ IsCold Rains:PropIsCold:ProphIsColdAndRains:IsCold ∧ Rains⊢ RainsRains:PropIsCold:ProphIsColdAndRains:IsCold ∧ Rains⊢ IsCold Rains:PropIsCold:ProphIsColdAndRains:IsCold ∧ Rains⊢ Rains All goals completed! 🐙 Rains:PropIsCold:ProphIsColdAndRains:IsCold ∧ Rains⊢ IsCold All goals completed! 🐙

Biconditional elimination, ↔Eₗ and ↔Eᵣ

Left-to-right biconditional elimination, ↔Eₗ
Right-to-left biconditional elimination, ↔Eᵣ

Iff.mp extracts the left-to-right direction; Iff.mpr extracts the right-to-left direction.

-- Left-to-right biconditional elimination, ↔Eₗ. theorem lecture03_iff_elim_left (EvenNumber DivisibleByTwo : Prop) (hEquivalence : EvenNumber ↔ DivisibleByTwo) (hEvenNumber : EvenNumber) : DivisibleByTwo := EvenNumber:PropDivisibleByTwo:ProphEquivalence:EvenNumber ↔ DivisibleByTwohEvenNumber:EvenNumber⊢ DivisibleByTwo EvenNumber:PropDivisibleByTwo:ProphEquivalence:EvenNumber ↔ DivisibleByTwohEvenNumber:EvenNumberhDirection:EvenNumber → DivisibleByTwo⊢ DivisibleByTwo EvenNumber:PropDivisibleByTwo:ProphEquivalence:EvenNumber ↔ DivisibleByTwohEvenNumber:EvenNumberhDirection:EvenNumber → DivisibleByTwohDivisibleByTwo:DivisibleByTwo⊢ DivisibleByTwo All goals completed! 🐙
-- Right-to-left biconditional elimination, ↔Eᵣ. theorem lecture03_iff_elim_right (EvenNumber DivisibleByTwo : Prop) (hEquivalence : EvenNumber ↔ DivisibleByTwo) (hDivisibleByTwo : DivisibleByTwo) : EvenNumber := EvenNumber:PropDivisibleByTwo:ProphEquivalence:EvenNumber ↔ DivisibleByTwohDivisibleByTwo:DivisibleByTwo⊢ EvenNumber EvenNumber:PropDivisibleByTwo:ProphEquivalence:EvenNumber ↔ DivisibleByTwohDivisibleByTwo:DivisibleByTwohDirection:DivisibleByTwo → EvenNumber⊢ EvenNumber EvenNumber:PropDivisibleByTwo:ProphEquivalence:EvenNumber ↔ DivisibleByTwohDivisibleByTwo:DivisibleByTwohDirection:DivisibleByTwo → EvenNumberhEvenNumber:EvenNumber⊢ EvenNumber All goals completed! 🐙

After extracting the needed direction, we apply it as an ordinary implication.

10. Choosing a rule

When reading a proof state, ask a few questions. First: what is the main connective of the goal? It often suggests an introduction rule. Second: which compound proofs are already in the context? They suggest elimination rules.

Lean tactic or termNatural-deduction reading
intro hintroduce an assumption
apply Capply a constructor or rule
have h := ...obtain an intermediate fact
exact huse exactly the required term
cases h withconsider the possible cases
h.left, h.righteliminate a conjunction
hAB hAeliminate an implication

This vocabulary describes the structure of the term Lean is constructing and makes the relationship between formal rule, natural-language argument, and proof script explicit.

11. Working strategy

When constructing a proof:

1. read the goal and assumptions; 2. identify the goal's main connective; 3. choose an introduction rule when the goal suggests one; 4. look for a useful elimination rule in the context; 5. name important intermediate results with have; 6. close the goal with exact when the required term is available; 7. verify that every case and subgoal has been solved.

Classroom.lean presents each rule separately. Exercises.lean begins with direct applications and then combines rules into complete arguments. Solutions.lean keeps the proof structure explicit so that each Lean step can be connected to its natural-deduction rule.

12. Sources and further reading