VIASM Mini-Course · Hanoi 2026 · Lecture 3

Propositional logic proofs

A proof is a program — natural deduction, BHK, and Curry–Howard, played hands-on in a Lean game.

dr Bartosz Naskręcki · Adam Mickiewicz University in Poznań · CCAI, Warsaw Univ. of Technology

▷ live lab: /lab-lambda

What, precisely, is a proof?

A first logic course decides formulas with truth tables: a tautology is true under every valuation.

A proof assistant cannot work this way. Its kernel does not evaluate a table — it checks a derivation, a syntactic object built from a fixed stock of inference rules.

Before Lean can help us with real mathematics, we must answer the question that opens this lecture.

Proofs = programs

The answer that makes machine-checked mathematics possible: a proof is a construction, and a construction is a typed program. This is the Curry–Howard correspondence.

  • every connective becomes a type former,
  • every inference rule becomes a term former,
  • every Lean tactic becomes a recipe that fills a hole in a proof term.

The same moves you learn here on toy propositions build the kernel-checked theorems of the Lecture 6 formalization.

Roadmap

  • Gentzen's natural deduction — intro / elim rules
  • The BHK meaning of each connective
  • The Curry–Howard dictionary
  • Lean tactics as term construction
  • The classical boundary: $A\lor\neg A$, $\neg\neg A\to A$, Peirce
  • Play it live in Emily Riehl's Lean game

We mark precisely where intuitionistic reasoning ends and classical logic begins.

Natural deduction — implication

Each connective gets introduction rules (how to prove it) and elimination rules (how to use it). Implication is subtle: introduction discharges a hypothesis $[A]$.

$$ \frac{\begin{array}{c}[A]\\ \vdots\\ B\end{array}}{A\to B}\;{\to}I \qquad\qquad \frac{A\to B \qquad A}{B}\;{\to}E $$

${\to}E$ is modus ponens. A derivation is a finite tree; the formula at the root is the conclusion.

Conjunction, disjunction, falsity

$$ \frac{A \quad B}{A\land B}\;{\land}I \qquad \frac{A\land B}{A}\;{\land}E_1 \qquad \frac{A\land B}{B}\;{\land}E_2 $$

$$ \frac{A}{A\lor B}\;{\lor}I_1 \qquad \frac{B}{A\lor B}\;{\lor}I_2 \qquad \frac{A\lor B \quad [A]\Rightarrow C \quad [B]\Rightarrow C}{C}\;{\lor}E $$

Falsity has an elimination but no introduction — that absence is the whole point:

$$ \frac{\bot}{C}\;{\bot}E \quad(\text{ex falso quodlibet}). $$

${\lor}E$ is case analysis. Negation is derived: $\neg A := A\to\bot$.

BHK — what a proof is

Read each connective as a recipe for constructions, not as a truth value.

  • a proof of $A\land B$ is a pair $\langle a,b\rangle$;
  • a proof of $A\lor B$ is a tagged proof $(i,p)$ — you must know which side holds;
  • a proof of $A\to B$ is a function turning proofs of $A$ into proofs of $B$;
  • there is no proof of $\bot$;
  • a proof of $\neg A = A\to\bot$ is a map you apply, never something you evaluate.

The tag clause is why there is no construction witnessing $A\lor\neg A$ — you would have to decide $A$.

Curry–Howard for the connectives

LogicTypeIntroduceEliminate
$A \to B$function $A\to B$$\lambda$ fun a => …application $f\,a$
$A \land B$product $A\times B$$\langle a,b\rangle$$\pi_1,\pi_2$
$A \lor B$sum $A+B$$\mathsf{inl},\mathsf{inr}$case analysis
$\bot$empty $\varnothing$— (no intro)False.elim
$\neg A$$A\to\varnothing$assume $A$, derive $\bot$apply to a proof of $A$
$\top$unit $\mathbf 1$trivial

Provability becomes inhabitation: $A$ is provable iff the type $A$ has a closed term.

Worked example — $A\land B\to B\land A$

The proof term is $\lambda h.\,\langle h.2,\,h.1\rangle$. Term mode and tactic mode build the same kernel object:

-- term mode: the proof IS the program
theorem and_comm' {P Q : Prop} : P ∧ Q → Q ∧ P :=
  fun h => ⟨h.2, h.1⟩

-- tactic mode: a recipe that fills the same hole
theorem and_comm'' {P Q : Prop} : P ∧ Q → Q ∧ P := by
  intro h            -- goal Q ∧ P, with h : P ∧ Q   (→I / λ)
  obtain ⟨p, q⟩ := h  -- destructure the pair         (∧E)
  exact ⟨q, p⟩        -- build the swapped pair        (∧I)

Negation, constructively

Three theorems people wrongly assume need classical logic. All are pure constructions ($\neg\neg A = (A\to\bot)\to\bot$):

$$ A\to\neg\neg A,\qquad \neg(A\land\neg A),\qquad \neg\neg\neg A\to\neg A. $$

theorem dni       {P : Prop} : P → ¬¬P        := fun p k => k p
theorem noncontra {P : Prop} : ¬(P ∧ ¬P)      := fun h => h.2 h.1
theorem tne       {P : Prop} : ¬¬¬P → ¬P      := fun h p => h (fun k => k p)

The converse $\neg\neg A\to A$ is not available here — it is the classical boundary in disguise.

ch term \p k. k p

Algorithm W infers the principal type α → (α → β) → β — read β as $\bot$ and this is exactly $A\to\neg\neg A$: the program came first, the proposition is its type.

De Morgan — and its classical cousin

One equivalence is fully constructive; one implication is genuinely classical:

$$ \neg(A\lor B)\Leftrightarrow(\neg A\land\neg B)\ \text{(intuitionistic)},\qquad \neg(A\land B)\to(\neg A\lor\neg B)\ \text{(classical)}. $$

theorem deMorgan_or {P Q : Prop} : ¬(P ∨ Q) ↔ (¬P ∧ ¬Q) :=
  ⟨fun h => ⟨fun p => h (Or.inl p), fun q => h (Or.inr q)⟩,
   fun ⟨np, nq⟩ h => h.elim np nq⟩

The missing direction would force you to pick a tag — decide which conjunct fails. BHK forbids that.

Tactics = proof-term construction

TacticRuleTerm action
intro h${\to}I$ (discharge)$\lambda h.\,?$
exact ecloseplug in $e$
apply f${\to}E$ backwardbuild $f\,?$
constructor / ⟨a,b⟩${\land}I$pair
rcases / obtain${\land}E,{\lor}E,{\bot}E$project / match
left / right${\lor}I_1$ / ${\lor}I_2$$\mathsf{inl}$ / $\mathsf{inr}$
exfalso${\bot}E$ (always valid)False.elim ?
by_contra hclassical ($\neg\neg$-elim)byContradiction

Only the last row leaves the intuitionistic fragment. Don't confuse exfalso with by_contra.

prove P -> Q -> P

The Lambda Lab speaks this table: intro, intro, exact p closes it, and qed prints the extracted proof term \p. \q. p with its principal type — the K combinator, live. Stuck? Type hint.

The classical boundary

Equivalent over intuitionistic logic — adding any one recovers full classical logic:

$$ A\lor\neg A,\qquad \neg\neg A\to A,\qquad ((A\to B)\to A)\to A. $$

theorem peirce {P Q : Prop} : ((P → Q) → P) → P := by
  intro h
  by_contra hnp                     -- hnp : ¬P, goal : False
  exact hnp (h (fun p => absurd p hnp))

Every step but by_contra is constructive — the classical content is isolated in exactly one move. Glivenko: $\vdash_c A$ iff $\vdash_i \neg\neg A$.

ch type ((P -> Q) -> P) -> P

The lab's inhabitation search answers not inhabited in intuitionistic STLC — a machine check that no constructive witness exists. Compare ch type (P -> Q -> R) -> (P -> Q) -> P -> R, which finds one instantly.

Run it yourself

Feel the "proof = program" identity: $\land$-elimination is projection. In the Lambda Lab, type:

reduce FST (PAIR a b)

It computes to a; likewise reduce SND (PAIR a b) gives b. Then clear the constructive core of Riehl's A Reintroduction to Proofs — TypeWorld → Function/Implication → Conjunction/Disjunction → Empty/Negation — without touching ClassicalWorld.

Recap & references

  • A proof is a construction; Curry–Howard makes it a typed term, and detour removal is $\beta$-reduction.
  • $\to$ a function, $\land$ a product, $\lor$ a sum, $\bot$ the empty type, $\neg A = A\to\bot$.
  • Every tactic builds a piece of the term; only by_contra crosses into classical logic.

Wadler, Propositions as Types (2015) · Sørensen–Urzyczyn, Lectures on the Curry–Howard Isomorphism · Howard (1969/80) · Riehl, A Reintroduction to Proofs · Theorem Proving in Lean 4