~ / track G / neighboring paradigms
Proof assistants: Agda, Idris, Lean
AdvancedA proof assistant is a programming language whose type-checker is also a
proof-checker. Via Curry-Howard, writing a program of type T is
constructing a proof of proposition T. These tools take that identity
seriously and let you prove your code correct — sometimes about the code,
sometimes about mathematics itself.
The big four
| Tool | Logic | Main use | Notable result |
|---|---|---|---|
| Coq | Calculus of Inductive Constructions | Verified software, verified math | CompCert (verified C compiler), 4-color theorem |
| Agda | Martin-Löf type theory | Dependently-typed FP, teaching | Most "Haskell-ish" feel |
| Idris | Type theory, with effects | Practical dependently-typed programming | Pioneered "dependent types as a working tool" |
| Lean | Calculus of Inductive Constructions + classical extensions | Formalized mathematics | Mathlib (largest formalized math library); used by Fields medalists |
All four are dependently typed (types can mention values), and all four can express both functional programs and mathematical proofs in the same language.
What "proof" means
You don't prove a property about the code — the code itself is the proof. The type expresses the proposition. Construct a value of that type and you've proved it.
-- Agda: the proposition "for all naturals n, n + 0 = n"
+-identityʳ : ∀ (n : ℕ) → n + zero ≡ n
+-identityʳ zero = refl
+-identityʳ (suc n) = cong suc (+-identityʳ n)
The right-hand side is a value of the type on the left. Type-checks ⇒ proof holds.
The pragmatic spectrum
Idris ←————————————————————————————————→ Coq
"write programs, occasionally prove" "write proofs, occasionally extract"
- Idris wants you to ship code. Total functions, runtime efficiency, effect system, foreign function interface. Proofs sneak in where types carry invariants.
- Coq is grown out of constructive logic research. Code extraction (to
OCaml, Haskell) exists but the focus is the proof. The Russell-style
tactics language (
Ltac) is half the experience. - Agda sits between — closer to a programming language than Coq, but with the dependent-type machinery exposed all the way down. Great for teaching the theory.
- Lean has eclipsed Coq for new math formalization due to its speed, tactic ergonomics, and the enormous Mathlib library. Lean 4 is also a serious programming language.
What gets proved in practice
| Domain | Example |
|---|---|
| Compilers | CompCert (verified C → assembly), CakeML (verified ML) |
| Operating systems | seL4 microkernel (functional correctness, isolation, no buffer overruns) |
| Cryptography | Verified primitives (e.g., HACL*, fiat-crypto) used in production Firefox/Chrome |
| Math | Four-color theorem, Feit-Thompson, Liquid Tensor experiment, Polynomial Freiman-Ruzsa |
| Smart contracts | Tezos uses Coq-verified components |
| Concurrent data structures | Verified lock-free queues, RCU |
What it feels like
Imagine GHC's type-checker, but the error messages are the steps still missing in a proof, and you talk to the compiler interactively via tactics:
;; Coq-ish pseudocode
Theorem rev_involutive : forall (xs : list nat), rev (rev xs) = xs.
Proof.
induction xs as [| h t IH]. ;; case split: nil and cons
- reflexivity. ;; nil case is trivial
- simpl. rewrite rev_app. ;; unfold and use a lemma
rewrite IH. reflexivity. ;; finish using the induction hypothesis
Qed.
Each line peels off a goal. When all goals are closed, Qed. checks the
underlying term and you have a certificate.
Connection to mainstream FP
You don't need to use a proof assistant to benefit from their ideas:
- GADTs in Haskell / OCaml borrow inductive type tooling.
- Refinement types (LiquidHaskell, F*) bring lightweight proofs into ordinary FP.
- Type-driven development (the Idris idea — write a type, then let the IDE help you fill the holes) has migrated to Haskell, Rust, even TypeScript.
- Property-based testing (QuickCheck) is "the engineer's version of a proof" — try the property on a thousand random inputs instead of proving it for all.
Clojure has no proof assistant, but clojure.spec and malli move in
the property-checking direction (generate inputs, run the program, observe
the postcondition).
When to reach for one
| Situation | Tool |
|---|---|
| Implementing a primitive that everything else trusts (crypto, kernel, compiler) | Coq, F*, Lean |
| Formalizing a math theorem | Lean (Mathlib) |
| Want stronger types than HM but still ship | Idris, F* |
| Teaching/learning type theory | Agda |
The cost: 5–10× the dev time relative to a regular FP language. The payoff: absolute correctness in domains where bugs are catastrophic.
Check yourself
? quiz
In a proof assistant, what is the relationship between 'writing a program' and 'writing a proof'?
Exercise
Pick a small property you believe about a function you've written (e.g.,
"reverse is involutive: reverse (reverse xs) = xs"). Sketch the induction
you would do to prove it on paper — base case + inductive step. That's the
skeleton you'd type into Agda or Coq.