Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/paulch42/lean-spec/llms.txt

Use this file to discover all available pages before exploring further.

In this guide you will install Lean 4, clone the lean-spec repository, open it in Visual Studio Code, and write your first formal program specification using Lean’s dependent type system. By the end you will have a working Lean file that defines a specification, an implementation, and a machine-checked verification that the implementation meets the specification — all in fewer than ten lines of code.
1

Install Lean 4

Follow the official Lean 4 setup instructions to install elan (the Lean version manager) and the Lean 4 toolchain.The lean-spec repository includes a lean-toolchain file at the root that pins the exact Lean version used by the tutorial:
leanprover/lean4:v4.5.0-rc1
When you open the project, elan reads this file and automatically downloads and activates the correct toolchain — you do not need to manage versions manually.
2

Clone the Repository

Clone the lean-spec repository from GitHub:
git clone https://github.com/paulch42/lean-spec.git
cd lean-spec
The repository layout is:
PathContents
LeanSpec/Lean source files (the actual specifications)
md/Generated markdown documentation
lean-toolchainPins the Lean version via elan
lakefile.leanLake build configuration
lake-manifest.jsonLocked dependency versions
The project depends on two Lake packages declared in lake-manifest.json:
  • std from leanprover/std4 — the Lean 4 standard library, providing collection types, algorithms, and utilities used throughout the specifications.
  • mdgen from Seasawher/mdgen — the tool used to generate the md/ documentation from the Lean source files.
Fetch the dependencies with:
lake update
3

Open in VS Code

Open the cloned directory in Visual Studio Code:
code lean-spec.code-workspace
If you have the Lean 4 VS Code extension installed, it will detect the lean-toolchain file (leanprover/lean4:v4.5.0-rc1) and activate the correct Lean toolchain automatically.Open any file under LeanSpec/ — for example LeanSpec/Introduction.lean — and the Lean server will start. You will see blue squiggles while the server initialises, which resolve once the file is checked. The Lean Infoview panel (opened with Ctrl+Shift+Enter / Cmd+Shift+Enter) shows types, goals, and #check / #eval output inline.
4

Your First Specification

The canonical introductory example in lean-spec is specifying a function that doubles a natural number. Work through this progression to understand how propositions, types, and subtypes relate.Step 1 — A proposition (no computational content):
def DoubleProp := ∀n : Nat, ∃m : Nat, m = 2 * n
DoubleProp is a valid Lean proposition, but propositions have no computational content. You could prove it, but you cannot evaluate it or use it as a type signature for a function without a separate proof step.Step 2 — A subtype specification (the right approach):
def Double₃ (n : Nat) := { m : Nat // m = 2 * n }
Double₃ is a type — specifically, for each n, it is the subtype of natural numbers m for which m = 2 * n holds. A function whose return type is Double₃ n is a function that must return a value together with machine-checked evidence that the value is twice n. This is the specification.Step 3 — An implementation:
def double (n : Nat) : { m : Nat // m = 2 * n } :=
  {val := 2 * n, property := rfl}
The implementation returns a subtype structure with two fields:
  • val — the computed value 2 * n.
  • property — evidence that val = 2 * n, discharged here by rfl (reflexivity, since 2 * n = 2 * n is definitionally true).
Step 4 — Verify the implementation meets the specification:
variable (n : Nat)
#check (double n : Double₃ n)
Place your cursor after the #check line in VS Code. The Lean Infoview will confirm:
double n : Double₃ n
This is machine-checked evidence that double implements Double₃ for every n.Step 5 — Evaluate:
#eval double 4
Lean outputs 8. The non-computational content (the property field) is erased at evaluation time — you get a plain natural number, with no runtime overhead from the specification machinery.
5

Build the Markdown Documentation

The md/ directory contains documentation generated from the Lean source files using the mdgen tool. To regenerate it after making changes to the Lean sources, run:
lake exe mdgen LeanSpec md
This processes all files under LeanSpec/, extracts the documentation comments (written in /-! ... -/ and /- ... -/ blocks), and produces corresponding .md files under md/. The Lean code blocks in the source become fenced code blocks in the output.

Key Lean Concepts

The specifications in lean-spec are built from a small vocabulary of Lean logic and type constructs. The following tables summarise the most important ones, drawn directly from LeanSpec/Introduction.lean.

Logical Connectives and Quantifiers

These are the building blocks of propositions in Lean’s logic:
NotationMeaning
P ∧ QConjunction — both P and Q hold
P ∨ QDisjunction — at least one of P or Q holds
P → QImplication — if P then Q
P ↔ QLogical equivalence — P if and only if Q
¬ PNegation — P does not hold
∀x, P xUniversal quantification — P x holds for all x
∃x, P xExistential quantification — there exists an x such that P x holds
TrueThe always-true proposition
FalseThe never-true proposition

Core Types

These are the types used to construct specifications:
NotationMeaning
T × UCartesian product — pairs of a T and a U
T ⊕ UDisjoint union — a value that is either a T or a U
T → UFunction type — functions from T to U
NatNatural numbers (0, 1, 2, …)
StringCharacter sequences
List TFinite sequences of elements of type T
(a : A) → B aDependent function type — corresponds to
(a : A) × B aDependent product type — corresponds to
{ a : A // P a }Subtype — elements of A satisfying proposition P
The last three are characteristic of dependent type theory. The non-dependent T → U and T × U are degenerate cases of (a : A) → B a and (a : A) × B a respectively, where B does not depend on a. The subtype { a : A // P a } is the workhorse of lean-spec: it bridges the gap between types (which have computational content) and propositions (which do not), making it the natural tool for expressing what a function must return.
Naming conventions. Lean-Spec follows standard Lean naming conventions: type and proposition names are camel case with an initial upper case letter (e.g. Double₃, DoubleProp), while function names are camel case with an initial lower case letter (e.g. double). Subscript numerals (e.g. Double₁, Double₂, Double₃) are used within the tutorial to distinguish successive refinements of the same definition.

Next Steps

Lean as a Spec Language

Understand how Lean’s logic and type system combine to create a single unified specification, programming, and proof language.

Types and Propositions

Explore the Curry–Howard correspondence and why the distinction between types and propositions matters for specification.

Subtypes and Dependent Types

Master the subtype { a : A // P a } and the dependent function and product types — the core tools of lean-spec.

Build docs developers (and LLMs) love