1. Introduction

The Lean Language Reference is intended as a comprehensive, precise description of Lean. It is first and foremost a reference work in which Lean users can look up detailed information, rather than a tutorial for new users. At the moment, this reference manual is a public preview. Many sections are still to be written. For tutorials and learning materials, please visit the Lean documentation page.

This document describes version 4.12.0-nightly-2024-10-14 of Lean.

1.1. Lean

Lean is an interactive theorem prover based on dependent type theory, designed for use both in cutting-edge mathematics and in software verification. Lean's core type theory is expressive enough to capture very complicated mathematical objects, but simple enough to admit independent implementations, reducing the risk of bugs that affect soundness. The core type theory is implemented in a minimal kernel that does nothing other than check proof terms. This core theory and kernel are supported by advanced automation, realized in an expressive tactic language. Each tactic produces a term in the core type theory that is checked by the kernel, so bugs in tactics do not threaten the soundness of Lean as a whole. Along with many other parts of Lean, the tactic language is user-extensible, so it can be built up to meet the needs of a given formalization project. Tactics are written in Lean itself, and can be used immediately upon definition; rebuilding the prover or loading external modules is not required.

Lean is also a pure functional programming language, with features such as a run-time system based on reference counting that can efficiently work with packed array structures, multi-threading, and monadic IO. As befits a programming language, Lean is primarily implemented in itself, including the language server, build tool, elaborator, and tactic system. This very book is written in Verso, a documentation authoring tool written in Lean.

Familiarity with Lean's programming features is valuable even for users whose primary interest is in writing proofs, because Lean programs are used to implement new tactics and proof automation. Thus, this reference manual does not draw a barrier between the two aspects, but rather describes them together so they can shed light on one another.

1.1.1. History

Leonardo de Moura launched the Lean project when he was at Microsoft Research in 2013, and Lean 0.1 was officially released on June 16, 2014. The goal of the Lean project is to combine the high level of trust provided by a small, independently-implementable logical kernel with the convenience and automation of tools like SMT solvers, while scaling to large problems. This vision still guides the development of Lean, as we invest in improved automation, improved performance, and user-friendliness; the trusted core proof checker is still minimal and independent implementations exist.

The initial versions of Lean were primarily configured as C++ libraries in which client code could carry out trustworthy proofs that were independently checkable. In these early years, the design of Lean rapidly evolved towards traditional interactive provers, first with tactics written in Lua, and later with a dedicated front-end syntax. January 20, 2017 saw the first release of the Lean 3.0 series. Lean 3 achieved widespread adoption by mathematicians, and pioneered self-extensibility: tactics, notations, and top-level commands could all be defined in Lean itself. The mathematics community built Mathlib, which at the end of Lean 3 had over one million lines of formalized mathematics, with all proofs mechanically checked. The system itself, however, was still implemented in C++, which imposed limits on Lean's flexibility and made it more difficult to develop due to the diverse skills required.

Development of Lean 4 began in 2018, culminating in the 4.0 release on September 8, 2023. Lean 4 represents an important milestone: as of version 4, Lean is self-hosted - approximately 90% of the code that implements Lean is itself written in Lean. Lean 4's rich extension API provides users with the ability to adapt it to their needs, rather than relying on the core developers to add necessary features. Additionally, self-hosting makes the development process much faster, so features and performance can be delivered more quickly; Lean 4 is faster and scales to larger problems than Lean 3. Mathlib was successfully ported to Lean 4 in 2023 through a community effort supported by the Lean developers, and it has now grown to over 1.5 million lines Even though Mathlib has grown by 50%, Lean 4 checks it faster than Lean 3 could check its smaller library. The development process for Lean 4 was approximately as long as that of all prior versions combined, and we are now delighted with its designβ€”no further rewrites are planned.

Leonardo de Moura and his co-founder, Sebastian Ullrich, launched the Lean Focused Research Organization (FRO) nonprofit in July of 2023 within Convergent Research, with philanthropic support from the Simons Foundation International, the Alfred P. Sloan Foundation, and Richard Merkin. The FRO currently has more than ten employees working to support the growth and scalability of Lean and the broader Lean community.

1.2. Typographical Conventions

This document makes use of a number of typographical and layout conventions to indicate various aspects of the information being presented.

1.2.1. Lean Code

This document contains many Lean code examples. They are formatted as follows:

def hello : IO Unit := IO.println "Hello, world!"

Compiler output (which may be errors, warnings, or just information) is shown both in the code and separately:

"The answer is 4"#eval s!"The answer is {2 + 2}" theorem declaration uses 'sorry'bogus : False := ⊒ False All goals completed! πŸ™ example := Nat.succ application type mismatch Nat.succ "two" argument "two" has type String : Type but is expected to have type Nat : Type"two"

Informative output, such as the result of Lean.Parser.Command.eval : command`#eval e` evaluates the expression `e` by compiling and evaluating it. * The command attempts to use `ToExpr`, `Repr`, or `ToString` instances to print the result. * If `e` is a monadic value of type `m ty`, then the command tries to adapt the monad `m` to one of the monads that `#eval` supports, which include `IO`, `CoreM`, `MetaM`, `TermElabM`, and `CommandElabM`. Users can define `MonadEval` instances to extend the list of supported monads. The `#eval` command gracefully degrades in capability depending on what is imported. Importing the `Lean.Elab.Command` module provides full capabilities. Due to unsoundness, `#eval` refuses to evaluate expressions that depend on `sorry`, even indirectly, since the presence of `sorry` can lead to runtime instability and crashes. This check can be overridden with the `#eval! e` command. Options: * If `eval.pp` is true (default: true) then tries to use `ToExpr` instances to make use of the usual pretty printer. Otherwise, only tries using `Repr` and `ToString` instances. * If `eval.type` is true (default: false) then pretty prints the type of the evaluated value. * If `eval.derive.repr` is true (default: true) then attempts to auto-derive a `Repr` instance when there is no other way to print the result. See also: `#reduce e` for evaluation by term reduction. #eval, is shown like this:

"The answer is 4"

Warnings are shown like this:

declaration uses 'sorry'

Error messages are shown like this:

application type mismatch
  Nat.succ "two"
argument
  "two"
has type
  String : Type
but is expected to have type
  Nat : Type

The presence of tactic proof states is indicated by the presence of small lozenges that can be clicked to show the proof state, such as after rfl below:

example : 2 + 2 = 4 := ⊒ 2 + 2 = 4 All goals completed! πŸ™

Proof states may also be shown on their own. When attempting to prove that 2 + 2 = 4, the initial proof state is:

⊒ 2 + 2 = 4

After using All goals completed! πŸ™, the resulting state is:

All goals completed! πŸ™

Identifiers in code examples are hyperlinked to their documentation.

1.2.2. Examples

Illustrative examples are in callout boxes, as below:

Even Numbers

This is an example of an example.

One way to define even numbers is via an inductive predicate:

inductive Even : Nat β†’ Prop where | zero : Even 0 | plusTwo : Even n β†’ Even (n + 2)

1.2.3. Technical Terminology

Technical terminology refers to terms used in a very specific sense when writing technical material, such as this reference. Uses of technical terminology are frequently hyperlinked to their definition sites, using links like this one.

1.2.4. Constant, Syntax, and Tactic References

Definitions, inductive types, syntax formers, and tactics have specific descriptions. These descriptions are marked as follows:

/-- Evenness: a number is even if it can be evenly divided by two. -/ inductive Even : Nat β†’ Prop where | /-- 0 is considered even here -/ zero : Even 0 | /-- If `n` is even, then so is `n + 2`. -/ plusTwo : Even n β†’ Even (n + 2)
inductive predicate
Even : Nat β†’ Prop

Evenness: a number is even if it can be evenly divided by two.

Constructors

  • zero : _root_.Even 0

    0 is considered even here

  • plusTwo {n : Nat} : _root_.Even n β†’ _root_.Even (n + 2)

    If n is even, then so is n + 2.