3. The Type System🔗

Terms, also known as expressions, are the fundamental units of meaning in Lean's core language. They are produced from user-written syntax by the elaborator. Lean's type system relates terms to their types, which are also themselves terms. Types can be thought of as denoting sets, while terms denote individual elements of these sets. A term is well-typed if it has a type under the rules of Lean's type theory. Only well-typed terms have a meaning.

Terms are a dependently typed λ-calculus: they include function abstraction, application, variables, and let-bindings. In addition to bound variables, variables in the term language may refer to constructors, type constructors, recursors, defined constants, or opaque constants. Constructors, type constructors, recursors, and opaque constants are not subject to substitution, while defined constants may be replaced with their definitions.

A derivation demonstrates the well-typedness of a term by explicitly indicating the precise inference rules that are used. Implicitly, well-typed terms can stand in for the derivations that demonstrate their well-typedness. Lean's type theory is explicit enough that derivations can be reconstructed from well-typed terms, which greatly reduces the overhead that would be incurred from storing a complete derivation, while still being expressive enough to represent modern research mathematics. This means that proof terms are sufficient evidence of the truth of a theorem and are amenable to independent verification.

In addition to having types, terms are also related by definitional equality. This is the mechanically-checkable relation that equates terms modulo their computational behavior. Definitional equality includes the following forms of reduction:

β (beta)

Applying a function abstraction to an argument by substitution for the bound variable

δ (delta)

Replacing occurrences of defined constants by the definition's value

ι (iota)

Reduction of recursors whose targets are constructors (primitive recursion)

ζ (zeta)

Replacement of let-bound variables by their defined values

Terms in which all possible reductions have been carried out are in normal form.

Definitional equality includes η-equivalence of functions and single-constructor inductive types. That is, fun x => f x is definitionally equal to f, and S.mk x.f1 x.f2 is definitionally equal to x, if S is a structure with fields f1 and f2. It also features proof irrelevance, so any two proofs of the same proposition are definitionally equal. It is reflexive, symmetric, and a congruence.

Definitional equality is used by conversion: if two terms are definitionally equal, and a given term has one of them as its type, then it also has the other as its type. Because definitional equality includes reduction, types can result from computations over data.

Computing types

When passed a natural number, the function LengthList computes a type that corresponds to a list with precisely that many entries in it:

def LengthList (α : Type u) : Nat Type u | 0 => PUnit | n + 1 => α × LengthList α n

Because Lean's tuples nest to the right, multiple nested parentheses are not needed:

example : LengthList Int 0 := () example : LengthList String 2 := ("Hello", "there", ())

If the length does not match the number of entries, then the computed type will not match the term:

example : LengthList String 5 := ("Wrong", "number", application type mismatch ("number", ()) argument () has type Unit : Type but is expected to have type LengthList String 3 : Type())
application type mismatch
  ("number", ())
argument
  ()
has type
  Unit : Type
but is expected to have type
  LengthList String 3 : Type

The basic types in Lean are universes, function types, and type constructors of inductive types. Defined constants, applications of recursors, function application, axioms or opaque constants may additionally give types, just as they can give rise to terms in any other type.

  1. 3.1. Functions
    1. 3.1.1. Function Abstractions
    2. 3.1.2. Currying
    3. 3.1.3. Extensionality
    4. 3.1.4. Totality and Termination
  2. 3.2. Propositions
  3. 3.3. Universes
    1. 3.3.1. Predicativity
    2. 3.3.2. Polymorphism
      1. 3.3.2.1. Level Expressions
      2. 3.3.2.2. Universe Variable Bindings
      3. 3.3.2.3. Universe Unification
      4. 3.3.2.4. Universe Lifting
  4. 3.4. Inductive Types
    1. 3.4.1. Inductive Type Declarations
      1. 3.4.1.1. Parameters and Indices
      2. 3.4.1.2. Example Inductive Types
      3. 3.4.1.3. Anonymous Constructor Syntax
      4. 3.4.1.4. Deriving Instances
    2. 3.4.2. Structure Declarations
      1. 3.4.2.1. Structure Parameters
      2. 3.4.2.2. Fields
      3. 3.4.2.3. Structure Constructors
      4. 3.4.2.4. Structure Inheritance
    3. 3.4.3. Logical Model
      1. 3.4.3.1. Recursors
        1. 3.4.3.1.1. Recursor Types
          1. 3.4.3.1.1.1. Subsingleton Elimination
        2. 3.4.3.1.2. Reduction
      2. 3.4.3.2. Well-Formedness Requirements
        1. 3.4.3.2.1. Universe Levels
        2. 3.4.3.2.2. Strict Positivity
        3. 3.4.3.2.3. Prop vs Type
      3. 3.4.3.3. Constructions for Termination Checking
    4. 3.4.4. Run-Time Representation
      1. 3.4.4.1. Exceptions
      2. 3.4.4.2. Relevance
      3. 3.4.4.3. Trivial Wrappers
      4. 3.4.4.4. Other Inductive Types
        1. 3.4.4.4.1. FFI
    5. 3.4.5. Mutual Inductive Types
      1. 3.4.5.1. Requirements
        1. 3.4.5.1.1. Mutual Dependencies
        2. 3.4.5.1.2. Parameters Must Match
        3. 3.4.5.1.3. Universe Levels
        4. 3.4.5.1.4. Positivity
      2. 3.4.5.2. Recursors
      3. 3.4.5.3. Run-Time Representation
  5. 3.5. Quotients