The Lean Language Reference

11.5. Basic Classes🔗

Many Lean type classes exist in order to allow built-in notations such as addition or array indexing to be overloaded.

11.5.1. Boolean Equality Tests

The Boolean equality operator == is overloaded by defining instances of BEq. The companion class Hashable specifies a hashing procedure for a type. When a type has both BEq and Hashable instances, then the hashes computed should respect the BEq instance: two values equated by BEq.bEq should always have the same hash.

🔗type class
BEq.{u} (α : Type u) : Type u

BEq α is a typeclass for supplying a boolean-valued equality relation on α, notated as a == b. Unlike DecidableEq α (which uses a = b), this is Bool valued instead of Prop valued, and it also does not have any axioms like being reflexive or agreeing with =. It is mainly intended for programming applications. See LawfulBEq for a version that requires that == and = coincide.

Typically we prefer to put the "more variable" term on the left, and the "more constant" term on the right.

Instance Constructor

BEq.mk.{u}

Methods

beq : ααBool

Boolean equality, notated as a == b.

Conventions for notations in identifiers:

  • The recommended spelling of == in identifiers is beq.

🔗type class
Hashable.{u} (α : Sort u) : Sort (max 1 u)

Types that can be hashed into a UInt64.

Instance Constructor

Hashable.mk.{u}

Methods

hash : αUInt64

Hashes a value into a UInt64.

🔗opaque
mixHash (u₁ u₂ : UInt64) : UInt64

An opaque hash mixing operation, used to implement hashing for products.

🔗type class
LawfulBEq.{u} (α : Type u) [BEq α] : Prop

A Boolean equality test coincides with propositional equality.

In other words:

  • a == b implies a = b.

  • a == a is true.

Instance Constructor

LawfulBEq.mk.{u}

Methods

eq_of_beq : ∀ {a b : α}, (a == b) = truea = b

If a == b evaluates to true, then a and b are equal in the logic.

rfl : ∀ {a : α}, (a == a) = true

== is reflexive, that is, (a == a) = true.

🔗type class
LawfulHashable.{u} (α : Type u) [BEq α]
  [Hashable α] : Prop

The BEq α and Hashable α instances on α are compatible. This means that that a == b implies hash a = hash b.

This is automatic if the BEq instance is lawful.

Instance Constructor

LawfulHashable.mk.{u}

Methods

hash_eq : ∀ (a b : α), (a == b) = truehash a = hash b

If a == b, then hash a = hash b.

🔗
hash_eq.{u_1} {α : Type u_1} [BEq α]
  [Hashable α] [LawfulHashable α] {a b : α} :
  (a == b) = truehash a = hash b

A lawful hash function respects its Boolean equality test.

11.5.2. Ordering

There are two primary ways to order the values of a type:

  • The Ord type class provides a three-way comparison operator, compare, which can indicate that one value is less than, equal to, or greater than another. It returns an Ordering.

  • The LT and LE classes provide canonical Prop-valued ordering relations for a type that do not need to be decidable. These relations are used to overload the < and operators.

🔗type class
Ord.{u} (α : Type u) : Type u

Ord α provides a computable total order on α, in terms of the compare : α α Ordering function.

Typically instances will be transitive, reflexive, and antisymmetric, but this is not enforced by the typeclass.

There is a derive handler, so appending deriving Ord to an inductive type or structure will attempt to create an Ord instance.

Instance Constructor

Ord.mk.{u}

Methods

compare : ααOrdering

Compare two elements in α using the comparator contained in an [Ord α] instance.

The compare method is exported, so no explicit Ord namespace is required to use it.

🔗def
compareOn.{u_1, u_2} {β : Type u_1}
  {α : Sort u_2} [ord : Ord β] (f : αβ)
  (x y : α) : Ordering

Compares two values by comparing the results of applying a function.

In particular, x is compared to y by comparing f x and f y.

Examples:

🔗def
Ord.opposite.{u_1} {α : Type u_1}
  (ord : Ord α) : Ord α

Inverts the order of an Ord instance.

The result is an Ord α instance that returns Ordering.lt when ord would return Ordering.gt and that returns Ordering.gt when ord would return Ordering.lt.

🔗inductive type
Ordering : Type

The result of a comparison according to a total order.

The relationship between the compared items may be:

Constructors

lt : Ordering

Less than.

eq : Ordering

Equal.

gt : Ordering

Greater than.

🔗def
Ordering.swap : OrderingOrdering

Swaps less-than and greater-than ordering results.

Examples:

🔗def
Ordering.then (a b : Ordering) : Ordering

If a and b are Ordering, then a.then b returns a unless it is .eq, in which case it returns b. Additionally, it has “short-circuiting” behavior similar to boolean &&: if a is not .eq then the expression for b is not evaluated.

This is a useful primitive for constructing lexicographic comparator functions. The deriving Ord syntax on a structure uses the Ord instance to compare each field in order, combining the results equivalently to Ordering.then.

Use compareLex to lexicographically combine two comparison functions.

Examples:

structure Person where name : String age : Nat -- Sort people first by name (in ascending order), and people with the same name by age (in -- descending order) instance : Ord Person where compare a b := (compare a.name b.name).then (compare b.age a.age)
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Dana", 50⟩
Ordering.gt
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 50⟩
Ordering.gt
#eval Ord.compare (⟨"Gert", 33⟩ : Person) ⟨"Gert", 20⟩
Ordering.lt
🔗def
Ordering.isLT : OrderingBool

Checks whether the ordering is lt.

🔗def
Ordering.isLE : OrderingBool

Checks whether the ordering is lt or eq.

🔗def
Ordering.isEq : OrderingBool

Checks whether the ordering is eq.

🔗def
Ordering.isNe : OrderingBool

Checks whether the ordering is not eq.

🔗def
Ordering.isGE : OrderingBool

Checks whether the ordering is gt or eq.

🔗def
Ordering.isGT : OrderingBool

Checks whether the ordering is gt.

🔗def
compareOfLessAndEq.{u_1} {α : Type u_1}
  (x y : α) [LT α] [Decidable (x < y)]
  [DecidableEq α] : Ordering

Uses decidable less-than and equality relations to find an Ordering.

In particular, if x < y then the result is Ordering.lt. If x = y then the result is Ordering.eq. Otherwise, it is Ordering.gt.

compareOfLessAndBEq uses BEq instead of DecidableEq.

🔗def
compareOfLessAndBEq.{u_1} {α : Type u_1}
  (x y : α) [LT α] [Decidable (x < y)] [BEq α] :
  Ordering

Uses a decidable less-than relation and Boolean equality to find an Ordering.

In particular, if x < y then the result is Ordering.lt. If x == y then the result is Ordering.eq. Otherwise, it is Ordering.gt.

compareOfLessAndEq uses DecidableEq instead of BEq.

🔗def
compareLex.{u_1, u_2} {α : Sort u_1}
  {β : Sort u_2} (cmp₁ cmp₂ : αβOrdering)
  (a : α) (b : β) : Ordering

Compares a and b lexicographically by cmp₁ and cmp₂.

a and b are first compared by cmp₁. If this returns Ordering.eq, a and b are compared by cmp₂ to break the tie.

To lexicographically combine two Orderings, use Ordering.then.

syntaxOrdering Operators

The less-than operator is overloaded in the LT class:

term ::= ...
    | The less-than relation: `x < y` 

Conventions for notations in identifiers:

 * The recommended spelling of `<` in identifiers is `lt`.term < term

The less-than-or-equal-to operator is overloaded in the LE class:

term ::= ...
    | The less-equal relation: `x ≤ y` 

Conventions for notations in identifiers:

 * The recommended spelling of `≤` in identifiers is `le`.term  term

The greater-than and greater-than-or-equal-to operators are the reverse of the less-than and less-than-or-equal-to operators, and cannot be independently overloaded:

term ::= ...
    | `a > b` is an abbreviation for `b < a`. 

Conventions for notations in identifiers:

 * The recommended spelling of `>` in identifiers is `gt`.term > term
term ::= ...
    | `a ≥ b` is an abbreviation for `b ≤ a`. 

Conventions for notations in identifiers:

 * The recommended spelling of `≥` in identifiers is `ge`.term  term
🔗type class
LT.{u} (α : Type u) : Type u

LT α is the typeclass which supports the notation x < y where x y : α.

Instance Constructor

LT.mk.{u}

Methods

lt : ααProp

The less-than relation: x < y

Conventions for notations in identifiers:

  • The recommended spelling of < in identifiers is lt.

🔗type class
LE.{u} (α : Type u) : Type u

LE α is the typeclass which supports the notation x y where x y : α.

Instance Constructor

LE.mk.{u}

Methods

le : ααProp

The less-equal relation: x y

Conventions for notations in identifiers:

  • The recommended spelling of in identifiers is le.

  • The recommended spelling of <= in identifiers is le (prefer over <=).

An Ord can be used to construct BEq, LT, and LE instances with the following helpers. They are not automatically instances because many types are better served by custom relations.

🔗def
ltOfOrd.{u_1} {α : Type u_1} [Ord α] : LT α

Constructs an LT instance from an Ord instance that asserts that the result of compare is Ordering.lt.

🔗def
leOfOrd.{u_1} {α : Type u_1} [Ord α] : LE α

Constructs an LT instance from an Ord instance that asserts that the result of compare satisfies Ordering.isLE.

🔗def
Ord.toBEq.{u_1} {α : Type u_1} (ord : Ord α) :
  BEq α

Constructs a BEq instance from an Ord instance.

🔗def
Ord.toLE.{u_1} {α : Type u_1} (ord : Ord α) :
  LE α

Constructs an LE instance from an Ord instance.

🔗def
Ord.toLT.{u_1} {α : Type u_1} (ord : Ord α) :
  LT α

Constructs an LT instance from an Ord instance.

Using Ord Instances for LT and LE Instances

Lean can automatically derive an Ord instance. In this case, the Ord Vegetable instance compares vegetables lexicographically:

structure Vegetable where color : String size : Fin 5 deriving Ord def broccoli : Vegetable where color := "green" size := 2 def sweetPotato : Vegetable where color := "orange" size := 3

Using the helpers ltOfOrd and leOfOrd, LT Vegetable and LE Vegetable instances can be defined. These instances compare the vegetables using compare and logically assert that the result is as expected.

instance : LT Vegetable := ltOfOrd instance : LE Vegetable := leOfOrd

The resulting relations are decidable because equality is decidable for Ordering:

true#eval broccoli < sweetPotato
true
true#eval broccoli sweetPotato
true
false#eval broccoli < broccoli
false
true#eval broccoli broccoli
true

11.5.2.1. Instance Construction

🔗def
Ord.lex.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} : Ord αOrd βOrd (α × β)

Constructs the lexicographic order on products α × β from orders for α and β.

🔗def
Ord.lex'.{u_1} {α : Type u_1}
  (ord₁ ord₂ : Ord α) : Ord α

Constructs an Ord instance from two existing instances by combining them lexicographically.

The resulting instance compares elements first by ord₁ and then, if this returns Ordering.eq, by ord₂.

The function compareLex can be used to perform this comparison without constructing an intermediate Ord instance. Ordering.then can be used to lexicographically combine the results of comparisons.

🔗def
Ord.on.{u_1, u_2} {β : Type u_1}
  {α : Type u_2} : Ord β → (f : αβ) → Ord α

Constructs an Ord instance that compares values according to the results of f.

In particular, ord.on f compares x and y by comparing f x and f y according to ord.

The function compareOn can be used to perform this comparison without constructing an intermediate Ord instance.

11.5.3. Minimum and Maximum Values

The classes Max and Min provide overloaded operators for choosing the greater or lesser of two values. These should be in agreement with Ord, LT, and LE instances, if they exist, but there is no mechanism to enforce this.

🔗type class
Min.{u} (α : Type u) : Type u

An overloaded operation to find the lesser of two values of type α.

Instance Constructor

Min.mk.{u}

Methods

min : ααα

Returns the lesser of its two arguments.

🔗type class
Max.{u} (α : Type u) : Type u

An overloaded operation to find the greater of two values of type α.

Instance Constructor

Max.mk.{u}

Methods

max : ααα

Returns the greater of its two arguments.

Given an LE α instance for which LE.le is decidable, the helpers minOfLe and maxOfLe can be used to create suitable Min α and Max α instances. They can be used as the right-hand side of an Lean.Parser.Command.declaration : commandinstance declaration.

🔗def
minOfLe.{u_1} {α : Type u_1} [LE α]
  [DecidableRel LE.le] : Min α

Constructs a Min instance from a decidable operation.

🔗def
maxOfLe.{u_1} {α : Type u_1} [LE α]
  [DecidableRel LE.le] : Max α

Constructs a Max instance from a decidable operation.

11.5.4. Decidability🔗

A proposition is decidable if it can be checked algorithmically. The Law of the Excluded Middle means that every proposition is true or false, but it provides no way to check which of the two cases holds, which can often be useful. By default, only algorithmic Decidable instances for which code can be generated are in scope; opening the Classical namespace makes every proposition decidable.

🔗inductive type
Decidable (p : Prop) : Type

Either a proof that p is true or a proof that p is false. This is equivalent to a Bool paired with a proof that the Bool is true if and only if p is true.

Decidable instances are primarily used via if-expressions and the tactic decide. In conditional expressions, the Decidable instance for the proposition is used to select a branch. At run time, this case distinction code is identical to that which would be generated for a Bool-based conditional. In proofs, the tactic decide synthesizes an instance of Decidable p, attempts to reduce it to isTrue h, and then succeeds with the proof h if it can.

Because Decidable carries data, when writing @[simp] lemmas which include a Decidable instance on the LHS, it is best to use {_ : Decidable p} rather than [Decidable p] so that non-canonical instances can be found via unification rather than instance synthesis.

Constructors

isFalse {p : Prop} (h : ¬p) : Decidable p

Proves that p is decidable by supplying a proof of ¬p

isTrue {p : Prop} (h : p) : Decidable p

Proves that p is decidable by supplying a proof of p

🔗def
DecidablePred.{u} {α : Sort u} (r : αProp) :
  Sort (max 1 u)

A decidable predicate.

A predicate is decidable if the corresponding proposition is Decidable for each possible argument.

🔗def
DecidableRel.{u, v} {α : Sort u} {β : Sort v}
  (r : αβProp) : Sort (max (max 1 u) v)

A decidable relation.

A relation is decidable if the corresponding proposition is Decidable for all possible arguments.

🔗def
DecidableEq.{u} (α : Sort u) : Sort (max 1 u)

Propositional equality is Decidable for all elements of a type.

In other words, an instance of DecidableEq α is a means of deciding the proposition a = b is for all a b : α.

🔗def
DecidableLT.{u} (α : Type u) [LT α] : Type u

Abbreviation for DecidableRel (· < · : α α Prop).

🔗def
DecidableLE.{u} (α : Type u) [LE α] : Type u

Abbreviation for DecidableRel (· · : α α Prop).

🔗def
Decidable.decide (p : Prop) [h : Decidable p] :
  Bool

Converts a decidable proposition into a Bool.

If p : Prop is decidable, then decide p : Bool is the Boolean value that is true if p is true and false if p is false.

🔗def
Decidable.byCases.{u} {p : Prop} {q : Sort u}
  [dec : Decidable p] (h1 : pq)
  (h2 : ¬pq) : q

Construct a q if some proposition p is decidable, and both the truth and falsity of p are sufficient to construct a q.

This is a synonym for dite, the dependent if-then-else operator.

Excluded Middle and Decidable

The equality of functions from Nat to Nat is not decidable:

example (f g : Nat Nat) : Decidable (f = g) := failed to synthesize Decidable (f = g) Additional diagnostic information may be available using the `set_option diagnostics true` command.inferInstance
failed to synthesize
  Decidable (f = g)

Additional diagnostic information may be available using the `set_option diagnostics true` command.

Opening Classical makes every proposition decidable; however, declarations and examples that use this fact must be marked Lean.Parser.Command.declaration : commandnoncomputable to indicate that code should not be generated for them.

open Classical noncomputable example (f g : Nat Nat) : Decidable (f = g) := inferInstance

11.5.5. Inhabited Types

🔗type class
Inhabited.{u} (α : Sort u) : Sort (max 1 u)

Inhabited α is a typeclass that says that α has a designated element, called (default : α). This is sometimes referred to as a "pointed type".

This class is used by functions that need to return a value of the type when called "out of domain". For example, Array.get! arr i : α returns a value of type α when arr : Array α, but if i is not in range of the array, it reports a panic message, but this does not halt the program, so it must still return a value of type α (and in fact this is required for logical consistency), so in this case it returns default.

Instance Constructor

Inhabited.mk.{u}

Methods

default : α

default is a function that produces a "default" element of any Inhabited type. This element does not have any particular specified properties, but it is often an all-zeroes value.

🔗inductive predicate
Nonempty.{u} (α : Sort u) : Prop

Nonempty α is a typeclass that says that α is not an empty type, that is, there exists an element in the type. It differs from Inhabited α in that Nonempty α is a Prop, which means that it does not actually carry an element of α, only a proof that there exists such an element. Given Nonempty α, you can construct an element of α nonconstructively using Classical.choice.

Constructors

intro.{u} {α : Sort u} (val : α) : Nonempty α

If val : α, then α is nonempty.

11.5.6. Subsingleton Types

🔗type class
Subsingleton.{u} (α : Sort u) : Prop

A subsingleton is a type with at most one element. It is either empty or has a unique element.

All propositions are subsingletons because of proof irrelevance: false propositions are empty, and all proofs of a true proposition are equal to one another. Some non-propositional types are also subsingletons.

Instance Constructor

Subsingleton.intro.{u}

Prove that α is a subsingleton by showing that any two elements are equal.

Methods

allEq : ∀ (a b : α), a = b

Any two elements of a subsingleton are equal.

🔗
Subsingleton.elim.{u} {α : Sort u}
  [h : Subsingleton α] (a b : α) : a = b

If a type is a subsingleton, then all of its elements are equal.

🔗
Subsingleton.helim.{u} {α β : Sort u}
  [h₁ : Subsingleton α] (h₂ : α = β) (a : α)
  (b : β) : HEq a b

If two types are equal and one of them is a subsingleton, then all of their elements are heterogeneously equal.

11.5.7. Arithmetic and Bitwise Operators

🔗type class
Zero.{u} (α : Type u) : Type u

A type with a zero element.

Instance Constructor

Zero.mk.{u}

Methods

zero : α

The zero element of the type.

🔗type class
NeZero.{u_1} {R : Type u_1} [Zero R] (n : R) :
  Prop

A type-class version of n 0.

Instance Constructor

NeZero.mk.{u_1}

Methods

out : n0

The proposition that n is not zero.

🔗type class
HAdd.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous addition. This enables the notation a + b : γ where a : α, b : β.

Instance Constructor

HAdd.mk.{u, v, w}

Methods

hAdd : αβγ

a + b computes the sum of a and b. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of + in identifiers is add.

🔗type class
Add.{u} (α : Type u) : Type u

The homogeneous version of HAdd: a + b : α where a b : α.

Instance Constructor

Add.mk.{u}

Methods

add : ααα

a + b computes the sum of a and b. See HAdd.

🔗type class
HSub.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous subtraction. This enables the notation a - b : γ where a : α, b : β.

Instance Constructor

HSub.mk.{u, v, w}

Methods

hSub : αβγ

a - b computes the difference of a and b. The meaning of this notation is type-dependent.

  • For natural numbers, this operator saturates at 0: a - b = 0 when a b.

Conventions for notations in identifiers:

  • The recommended spelling of - in identifiers is sub (when used as a binary operator).

🔗type class
Sub.{u} (α : Type u) : Type u

The homogeneous version of HSub: a - b : α where a b : α.

Instance Constructor

Sub.mk.{u}

Methods

sub : ααα

a - b computes the difference of a and b. See HSub.

🔗type class
HMul.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous multiplication. This enables the notation a * b : γ where a : α, b : β.

Instance Constructor

HMul.mk.{u, v, w}

Methods

hMul : αβγ

a * b computes the product of a and b. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of * in identifiers is mul.

🔗type class
Mul.{u} (α : Type u) : Type u

The homogeneous version of HMul: a * b : α where a b : α.

Instance Constructor

Mul.mk.{u}

Methods

mul : ααα

a * b computes the product of a and b. See HMul.

🔗type class
HDiv.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous division. This enables the notation a / b : γ where a : α, b : β.

Instance Constructor

HDiv.mk.{u, v, w}

Methods

hDiv : αβγ

a / b computes the result of dividing a by b. The meaning of this notation is type-dependent.

  • For most types like Nat, Int, Rat, Real, a / 0 is defined to be 0.

  • For Nat, a / b rounds downwards.

  • For Int, a / b rounds downwards if b is positive or upwards if b is negative. It is implemented as Int.ediv, the unique function satisfying a % b + b * (a / b) = a and 0 a % b < natAbs b for b 0. Other rounding conventions are available using the functions Int.fdiv (floor rounding) and Int.tdiv (truncation rounding).

  • For Float, a / 0 follows the IEEE 754 semantics for division, usually resulting in inf or nan.

Conventions for notations in identifiers:

  • The recommended spelling of / in identifiers is div.

🔗type class
Div.{u} (α : Type u) : Type u

The homogeneous version of HDiv: a / b : α where a b : α.

Instance Constructor

Div.mk.{u}

Methods

div : ααα

a / b computes the result of dividing a by b. See HDiv.

🔗type class
Dvd.{u_1} (α : Type u_1) : Type u_1

Notation typeclass for the operation (typed as \|), which represents divisibility.

Instance Constructor

Dvd.mk.{u_1}

Methods

dvd : ααProp

Divisibility. a b (typed as \|) means that there is some c such that b = a * c.

Conventions for notations in identifiers:

  • The recommended spelling of in identifiers is dvd.

🔗type class
HMod.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous modulo / remainder. This enables the notation a % b : γ where a : α, b : β.

Instance Constructor

HMod.mk.{u, v, w}

Methods

hMod : αβγ

a % b computes the remainder upon dividing a by b. The meaning of this notation is type-dependent.

  • For Nat and Int it satisfies a % b + b * (a / b) = a, and a % 0 is defined to be a.

Conventions for notations in identifiers:

  • The recommended spelling of % in identifiers is mod.

🔗type class
Mod.{u} (α : Type u) : Type u

The homogeneous version of HMod: a % b : α where a b : α.

Instance Constructor

Mod.mk.{u}

Methods

mod : ααα

a % b computes the remainder upon dividing a by b. See HMod.

🔗type class
HPow.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous exponentiation. This enables the notation a ^ b : γ where a : α, b : β.

Instance Constructor

HPow.mk.{u, v, w}

Methods

hPow : αβγ

a ^ b computes a to the power of b. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of ^ in identifiers is pow.

🔗type class
Pow.{u, v} (α : Type u) (β : Type v) :
  Type (max u v)

The homogeneous version of HPow: a ^ b : α where a : α, b : β. (The right argument is not the same as the left since we often want this even in the homogeneous case.)

Types can choose to subscribe to particular defaulting behavior by providing an instance to either NatPow or HomogeneousPow:

  • NatPow is for types whose exponents is preferentially a Nat.

  • HomogeneousPow is for types whose base and exponent are preferentially the same.

Instance Constructor

Pow.mk.{u, v}

Methods

pow : αβα

a ^ b computes a to the power of b. See HPow.

🔗type class
NatPow.{u} (α : Type u) : Type u

The homogeneous version of Pow where the exponent is a Nat. The purpose of this class is that it provides a default Pow instance, which can be used to specialize the exponent to Nat during elaboration.

For example, if x ^ 2 should preferentially elaborate with 2 : Nat then x's type should provide an instance for this class.

Instance Constructor

NatPow.mk.{u}

Methods

pow : αNatα

a ^ n computes a to the power of n where n : Nat. See Pow.

🔗type class
HomogeneousPow.{u} (α : Type u) : Type u

The completely homogeneous version of Pow where the exponent has the same type as the base. The purpose of this class is that it provides a default Pow instance, which can be used to specialize the exponent to have the same type as the base's type during elaboration. This is to say, a type should provide an instance for this class in case x ^ y should be elaborated with both x and y having the same type.

For example, the Float type provides an instance of this class, which causes expressions such as (2.2 ^ 2.2 : Float) to elaborate.

Instance Constructor

HomogeneousPow.mk.{u}

Methods

pow : ααα

a ^ b computes a to the power of b where a and b both have the same type.

🔗type class
HShiftLeft.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The typeclass behind the notation a <<< b : γ where a : α, b : β.

Instance Constructor

HShiftLeft.mk.{u, v, w}

Methods

hShiftLeft : αβγ

a <<< b computes a shifted to the left by b places. The meaning of this notation is type-dependent.

  • On Nat, this is equivalent to a * 2 ^ b.

  • On UInt8 and other fixed width unsigned types, this is the same but truncated to the bit width.

Conventions for notations in identifiers:

  • The recommended spelling of <<< in identifiers is shiftLeft.

🔗type class
ShiftLeft.{u} (α : Type u) : Type u

The homogeneous version of HShiftLeft: a <<< b : α where a b : α.

Instance Constructor

ShiftLeft.mk.{u}

Methods

shiftLeft : ααα

The implementation of a <<< b : α. See HShiftLeft.

🔗type class
HShiftRight.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The typeclass behind the notation a >>> b : γ where a : α, b : β.

Instance Constructor

HShiftRight.mk.{u, v, w}

Methods

hShiftRight : αβγ

a >>> b computes a shifted to the right by b places. The meaning of this notation is type-dependent.

  • On Nat and fixed width unsigned types like UInt8, this is equivalent to a / 2 ^ b.

Conventions for notations in identifiers:

  • The recommended spelling of >>> in identifiers is shiftRight.

🔗type class
ShiftRight.{u} (α : Type u) : Type u

The homogeneous version of HShiftRight: a >>> b : α where a b : α.

Instance Constructor

ShiftRight.mk.{u}

Methods

shiftRight : ααα

The implementation of a >>> b : α. See HShiftRight.

🔗type class
Neg.{u} (α : Type u) : Type u

The notation typeclass for negation. This enables the notation -a : α where a : α.

Instance Constructor

Neg.mk.{u}

Methods

neg : αα

-a computes the negative or opposite of a. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of - in identifiers is neg (when used as a unary operator).

🔗type class
HAnd.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The typeclass behind the notation a &&& b : γ where a : α, b : β.

Instance Constructor

HAnd.mk.{u, v, w}

Methods

hAnd : αβγ

a &&& b computes the bitwise AND of a and b. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of &&& in identifiers is and.

🔗type class
HOr.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The typeclass behind the notation a ||| b : γ where a : α, b : β.

Instance Constructor

HOr.mk.{u, v, w}

Methods

hOr : αβγ

a ||| b computes the bitwise OR of a and b. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of ||| in identifiers is or.

🔗type class
HXor.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The typeclass behind the notation a ^^^ b : γ where a : α, b : β.

Instance Constructor

HXor.mk.{u, v, w}

Methods

hXor : αβγ

a ^^^ b computes the bitwise XOR of a and b. The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of ^^^ in identifiers is xor.

11.5.8. Append

🔗type class
HAppend.{u, v, w} (α : Type u) (β : Type v)
  (γ : outParam (Type w)) :
  Type (max (max u v) w)

The notation typeclass for heterogeneous append. This enables the notation a ++ b : γ where a : α, b : β.

Instance Constructor

HAppend.mk.{u, v, w}

Methods

hAppend : αβγ

a ++ b is the result of concatenation of a and b, usually read "append". The meaning of this notation is type-dependent.

Conventions for notations in identifiers:

  • The recommended spelling of ++ in identifiers is append.

🔗type class
Append.{u} (α : Type u) : Type u

The homogeneous version of HAppend: a ++ b : α where a b : α.

Instance Constructor

Append.mk.{u}

Methods

append : ααα

a ++ b is the result of concatenation of a and b. See HAppend.

11.5.9. Data Lookups

🔗type class
GetElem.{u, v, w} (coll : Type u) (idx : Type v)
  (elem : outParam (Type w))
  (valid : outParam (collidxProp)) :
  Type (max (max u v) w)

The classes GetElem and GetElem? implement lookup notation, specifically xs[i], xs[i]?, xs[i]!, and xs[i]'p.

Both classes are indexed by types coll, idx, and elem which are the collection, the index, and the element types. A single collection may support lookups with multiple index types. The relation valid determines when the index is guaranteed to be valid; lookups of valid indices are guaranteed not to fail.

For example, an instance for arrays looks like GetElem (Array α) Nat α (fun xs i => i < xs.size). In other words, given an array xs and a natural number i, xs[i] will return an α when valid xs i holds, which is true when i is less than the size of the array. Array additionally supports indexing with USize instead of Nat. In either case, because the bounds are checked at compile time, no runtime check is required.

Given xs[i] with xs : coll and i : idx, Lean looks for an instance of GetElem coll idx elem valid and uses this to infer the type of the return value elem and side condition valid required to ensure xs[i] yields a valid value of type elem. The tactic get_elem_tactic is invoked to prove validity automatically. The xs[i]'p notation uses the proof p to satisfy the validity condition. If the proof p is long, it is often easier to place the proof in the context using have, because get_elem_tactic tries assumption.

The proof side-condition valid xs i is automatically dispatched by the get_elem_tactic tactic; this tactic can be extended by adding more clauses to get_elem_tactic_trivial using macro_rules.

xs[i]? and xs[i]! do not impose a proof obligation; the former returns an Option elem, with none signalling that the value isn't present, and the latter returns elem but panics if the value isn't there, returning default : elem based on the Inhabited elem instance. These are provided by the GetElem? class, for which there is a default instance generated from a GetElem class as long as valid xs i is always decidable.

Important instances include:

  • arr[i] : α where arr : Array α and i : Nat or i : USize: does array indexing with no runtime bounds check and a proof side goal i < arr.size.

  • l[i] : α where l : List α and i : Nat: index into a list, with proof side goal i < l.length.

Instance Constructor

GetElem.mk.{u, v, w}

Methods

getElem : (xs : coll) → (i : idx) → valid xs ielem

The syntax arr[i] gets the i'th element of the collection arr. If there are proof side conditions to the application, they will be automatically inferred by the get_elem_tactic tactic.

Conventions for notations in identifiers:

  • The recommended spelling of xs[i] in identifiers is getElem.

  • The recommended spelling of xs[i]'h in identifiers is getElem.

🔗type class
GetElem?.{u, v, w} (coll : Type u)
  (idx : Type v) (elem : outParam (Type w))
  (valid : outParam (collidxProp)) :
  Type (max (max u v) w)

The classes GetElem and GetElem? implement lookup notation, specifically xs[i], xs[i]?, xs[i]!, and xs[i]'p.

Both classes are indexed by types coll, idx, and elem which are the collection, the index, and the element types. A single collection may support lookups with multiple index types. The relation valid determines when the index is guaranteed to be valid; lookups of valid indices are guaranteed not to fail.

For example, an instance for arrays looks like GetElem (Array α) Nat α (fun xs i => i < xs.size). In other words, given an array xs and a natural number i, xs[i] will return an α when valid xs i holds, which is true when i is less than the size of the array. Array additionally supports indexing with USize instead of Nat. In either case, because the bounds are checked at compile time, no runtime check is required.

Given xs[i] with xs : coll and i : idx, Lean looks for an instance of GetElem coll idx elem valid and uses this to infer the type of the return value elem and side condition valid required to ensure xs[i] yields a valid value of type elem. The tactic get_elem_tactic is invoked to prove validity automatically. The xs[i]'p notation uses the proof p to satisfy the validity condition. If the proof p is long, it is often easier to place the proof in the context using have, because get_elem_tactic tries assumption.

The proof side-condition valid xs i is automatically dispatched by the get_elem_tactic tactic; this tactic can be extended by adding more clauses to get_elem_tactic_trivial using macro_rules.

xs[i]? and xs[i]! do not impose a proof obligation; the former returns an Option elem, with none signalling that the value isn't present, and the latter returns elem but panics if the value isn't there, returning default : elem based on the Inhabited elem instance. These are provided by the GetElem? class, for which there is a default instance generated from a GetElem class as long as valid xs i is always decidable.

Important instances include:

  • arr[i] : α where arr : Array α and i : Nat or i : USize: does array indexing with no runtime bounds check and a proof side goal i < arr.size.

  • l[i] : α where l : List α and i : Nat: index into a list, with proof side goal i < l.length.

Instance Constructor

GetElem?.mk.{u, v, w}

Extends

Methods

getElem : (xs : coll) → (i : idx) → valid xs ielem
Inherited from
  1. GetElem coll idx elem valid
getElem? : collidxOption elem

The syntax arr[i]? gets the i'th element of the collection arr, if it is present (and wraps it in some), and otherwise returns none.

Conventions for notations in identifiers:

  • The recommended spelling of xs[i]? in identifiers is getElem?.

getElem! : [inst : Inhabited elem] → collidxelem

The syntax arr[i]! gets the i'th element of the collection arr, if it is present, and otherwise panics at runtime and returns the default term from Inhabited elem.

Conventions for notations in identifiers:

  • The recommended spelling of xs[i]! in identifiers is getElem!.

🔗type class
LawfulGetElem.{u, v, w} (cont : Type u)
  (idx : Type v) (elem : outParam (Type w))
  (dom : outParam (contidxProp))
  [ge : GetElem? cont idx elem dom] : Prop

Lawful GetElem? instances (which extend GetElem) are those for which the potentially-failing GetElem?.getElem? and GetElem?.getElem! operators succeed when the validity predicate is satisfied, and fail when it is not.

Instance Constructor

LawfulGetElem.mk.{u, v, w}

Methods

getElem?_def : ∀ (c : cont) (i : idx) [inst : Decidable (dom c i)], c[i]? = if h : dom c i then some c[i] else none

GetElem?.getElem? succeeds when the validity predicate is satisfied and fails otherwise.

getElem!_def : ∀ [inst : Inhabited elem] (c : cont) (i : idx),
  c[i]! =
    match c[i]? with
    | some e => e
    | none => default

GetElem?.getElem! succeeds and fails when GetElem.getElem? succeeds and fails.