A minimal working example is the smallest complete Lean fragment that demonstrates a definition, theorem, error, or technique.
A minimal working example is the smallest complete Lean fragment that demonstrates a definition, theorem, error, or technique. It should compile by itself inside a project, use only the imports it needs, and contain no unrelated code. Minimal examples are essential for learning, debugging, documentation, and reporting issues.
Problem
You want to isolate a Lean idea in a short file that another person can run and understand immediately.
Solution
Start with the smallest import set, write one or two declarations, and include a check or evaluation command.
def double (n : Nat) : Nat :=
n + n
#eval double 21Expected output:
42This example is complete. It defines one function and shows one observable result.
Minimal Proof Example
A proof example should include only the statement and the proof.
theorem id_prop (P : Prop) : P -> P := by
intro h
exact hThis theorem needs no imports. It is minimal because it uses only core logical features.
A slightly richer example:
theorem and_swap (P Q : Prop) : P ∧ Q -> Q ∧ P := by
intro h
constructor
· exact h.right
· exact h.leftThis example demonstrates implication, conjunction, introduction, and field access on a conjunction proof.
Minimal Import Example
If an example requires a library, include the import.
import Std
#eval Std.HashMap.emptyWithCapacityFor mathlib examples, prefer narrow imports when you know them.
import Mathlib.Data.Nat.Basic
theorem add_zero_example (n : Nat) : n + 0 = n := by
simpA minimal example should not import a large library unless the behavior being demonstrated depends on it.
Minimal Structure Example
structure Point where
x : Nat
y : Nat
deriving Repr
def p : Point :=
{ x := 3, y := 4 }
#eval p.x + p.yExpected output:
7This example shows structure declaration, construction, projection, and evaluation.
Minimal Inductive Example
inductive Color where
| red
| green
| blue
deriving Repr, DecidableEq
def isRed : Color -> Bool
| Color.red => true
| _ => false
#eval isRed Color.red
#eval isRed Color.blueExpected output:
true
falseThis demonstrates constructors, pattern matching, and derived instances.
Minimal Rewriting Example
theorem rewrite_example (a b : Nat) (h : a = b) :
a + 1 = b + 1 := by
rw [h]The example contains the needed equality as a hypothesis. Nothing else is required.
Minimal Debugging Example
When reporting an error, remove everything not needed to reproduce it.
Bad example:
import Mathlib
namespace LargeProject
-- hundreds of unrelated declarations
theorem broken (n : Nat) : n = n + 0 := by
rfl
end LargeProjectBetter example:
theorem broken (n : Nat) : n = n + 0 := by
rflThis isolates the problem: rfl cannot prove the statement because n and n + 0 are not definitionally equal.
A fixed version:
theorem fixed (n : Nat) : n = n + 0 := by
simpMinimal Project Example
For examples involving imports or executables, include the project structure.
hello/
├── lakefile.lean
├── lean-toolchain
├── Hello/
│ └── Basic.lean
└── Main.leanHello/Basic.lean:
namespace Hello
def message : String :=
"hello"
end HelloMain.lean:
import Hello.Basic
def main : IO Unit := do
IO.println Hello.messageRun:
lake exe helloExpected output:
helloThis is minimal for demonstrating a Lake executable with a local module.
What to Remove
When minimizing an example, remove:
| Remove | Keep |
|---|---|
| unrelated imports | imports needed for the failing name |
| unrelated namespaces | namespace only if it affects resolution |
| unused variables | variables used in the statement or proof |
| long theorem chains | the first theorem that reproduces the issue |
| automation noise | the tactic that demonstrates the behavior |
The goal is to preserve the behavior while reducing the context.
What to Keep
Keep enough information for another person or tool to reproduce the result:
- Lean version, when version-sensitive
- required imports
- complete declaration
- exact error or expected output
- project context, if module resolution matters
For toolchain-sensitive issues, include the contents of lean-toolchain.
leanprover/lean4:v4.12.0Recipe: Minimize a Failed Proof
Start with the failing theorem.
Replace the proof with a hole.
theorem target (n : Nat) : n = n + 0 := by
_Inspect the goal.
Try the failing tactic.
theorem target (n : Nat) : n = n + 0 := by
rflIf it still fails without surrounding code, you have a minimal example.
If it succeeds, restore only the nearest dependency until the failure returns.
Recipe: Create a Teaching Example
A teaching example should demonstrate one idea.
For rw:
theorem rw_teaching (a b : Nat) (h : a = b) :
a + a = b + b := by
rw [h]For constructor:
theorem constructor_teaching (P Q : Prop) (hp : P) (hq : Q) :
P ∧ Q := by
constructor
· exact hp
· exact hqFor cases:
theorem cases_teaching (P Q : Prop) :
P ∨ Q -> Q ∨ P := by
intro h
cases h with
| inl hp =>
right
exact hp
| inr hq =>
left
exact hqEach example introduces one tactic in a clear setting.
Common Pitfalls
If the example imports too much, the real dependency may be hidden.
If the example uses project-local names, include their definitions.
If the example depends on notation, include the notation declaration or use the underlying name.
If the example uses automation, make sure the imports explain why the automation works.
If the example is too small and no longer reproduces the issue, restore the last removed dependency.
Takeaway
A minimal working example is a complete, small, reproducible Lean fragment. It is the main unit for debugging, teaching, and communication. Good examples keep only the declarations, imports, and context needed to demonstrate one behavior.