mathlib documentation

core / init.coe

Coercions and lifts #

The elaborator tries to insert coercions automatically. Only instances of has_coe type class are considered in the process.

Lean also provides a "lifting" operator: ↑a. It uses all instances of has_lift type class. Every has_coe instance is also a has_lift instance.

We recommend users only use has_coe for coercions that do not produce a lot of ambiguity.

All coercions and lifts can be identified with the constant coe.

We use the has_coe_to_fun type class for encoding coercions from a type to a function space.

We use the has_coe_to_sort type class for encoding coercions from a type to a sort.

@[class]
structure has_lift (a : Sort u) (b : Sort v) :
Sort (max 1 (imax u v))
  • lift : a → b

Can perform a lifting operation ↑a.

Instances
@[class]
structure has_lift_t (a : Sort u) (b : Sort v) :
Sort (max 1 (imax u v))
  • lift : a → b

Auxiliary class that contains the transitive closure of has_lift.

Instances

We specify the universes in has_coe, has_coe_to_fun, and has_coe_to_sort explicitly in order to match exactly what appears in Lean4.

@[class]
structure has_coe (a : Sort u) (b : Sort v) :
Sort (max (max 1 u) v)
  • coe : a → b
Instances
@[class]
structure has_coe_to_sort (a : Sort u) (S : out_param (Sort v)) :
Sort (max (max 1 u) v)
  • coe : a → S
Instances
def lift {a : Sort u} {b : Sort v} [has_lift a b] :
a → b
Equations
def lift_t {a : Sort u} {b : Sort v} [has_lift_t a b] :
a → b
Equations
def coe_b {a : Sort u} {b : Sort v} [has_coe a b] :
a → b
Equations
def coe_t {a : Sort u} {b : Sort v} [has_coe_t a b] :
a → b
Equations
def coe_fn_b {a : Sort u} {b : a → Sort v} [has_coe_to_fun a b] (x : a) :
b x
Equations

User level coercion operators #

def coe {a : Sort u} {b : Sort v} [has_lift_t a b] :
a → b
Equations
def coe_fn {a : Sort u} {b : a → Sort v} [has_coe_to_fun a b] (x : a) :
b x
Equations
def coe_sort {a : Sort u} {b : Sort v} [has_coe_to_sort a b] :
a → b
Equations

Notation #

Transitive closure for has_lift, has_coe, has_coe_to_fun #

@[protected, instance]
def lift_trans {a : Sort u₁} {b : Sort u₂} {c : Sort u₃} [has_lift_t b c] [has_lift a b] :
Equations
@[protected, instance]
def lift_base {a : Sort u} {b : Sort v} [has_lift a b] :
Equations
@[protected, instance]
def coe_trans {a : Sort u₁} {b : Sort u₂} {c : Sort u₃} [has_coe_t b c] [has_coe a b] :
Equations
@[protected, instance]
def coe_base {a : Sort u} {b : Sort v} [has_coe a b] :
Equations
@[protected, instance]
def coe_option {a : Type u} :

We add this instance directly into has_coe_t to avoid non-termination.

Suppose coe_option had type (has_coe a (option a)). Then, we can loop when searching a coercion from α to β (has_coe_t α β) 1- coe_trans at (has_coe_t α β) (has_coe α ?b₁) and (has_coe_t ?b₁ c) 2- coe_option at (has_coe α ?b₁) ?b₁ := option α 3- coe_trans at (has_coe_t (option α) β) (has_coe (option α) ?b₂) and (has_coe_t ?b₂ β) 4- coe_option at (has_coe (option α) ?b₂) ?b₂ := option (option α)) ...

Equations
@[class]
structure has_coe_t_aux (a : Sort u) (b : Sort v) :
Sort (max 1 (imax u v))
  • coe : a → b

Auxiliary transitive closure for has_coe which does not contain instances such as coe_option.

They would produce non-termination when combined with coe_fn_trans and coe_sort_trans.

Instances
@[protected, instance]
def coe_trans_aux {a : Sort u₁} {b : Sort u₂} {c : Sort u₃} [has_coe_t_aux b c] [has_coe a b] :
Equations
@[protected, instance]
def coe_base_aux {a : Sort u} {b : Sort v} [has_coe a b] :
Equations
@[protected, instance]
def coe_fn_trans {a : Sort u₁} {b : Sort u₂} {c : b → Sort v} [has_coe_to_fun b c] [has_coe_t_aux a b] :
has_coe_to_fun a (λ (x : a), c (has_coe_t_aux.coe x))
Equations
@[protected, instance]
def coe_sort_trans {a : Sort u₁} {b : Sort u₂} {c : Sort v} [has_coe_to_sort b c] [has_coe_t_aux a b] :
Equations
@[protected, instance]
def coe_to_lift {a : Sort u} {b : Sort v} [has_coe_t a b] :

Every coercion is also a lift

Equations

Basic coercions #

@[protected, instance]
Equations
@[protected, instance]

Tactics such as the simplifier only unfold reducible constants when checking whether two terms are definitionally equal or a term is a proposition. The motivation is performance. In particular, when simplifying p -> q, the tactic simp only visits p if it can establish that it is a proposition. Thus, we mark the following instance as @[reducible], otherwise simp will not visit ↑p when simplifying ↑p -> q.

Equations
@[protected, instance]
Equations
@[protected, instance]
def coe_subtype {a : Sort u} {p : a → Prop} :
has_coe {x // p x} a
Equations

Basic lifts #

@[protected, instance]
def lift_fn {a₁ : Sort ua₁} {a₂ : Sort ua₂} {b₁ : Sort ub₁} {b₂ : Sort ub₂} [has_lift a₂ a₁] [has_lift_t b₁ b₂] :
has_lift (a₁ → b₁) (a₂ → b₂)

Remark: we can't use [has_lift_t a₂ a₁] since it will produce non-termination whenever a type class resolution problem does not have a solution.

Equations
@[protected, instance]
def lift_fn_range {a : Sort ua} {b₁ : Sort ub₁} {b₂ : Sort ub₂} [has_lift_t b₁ b₂] :
has_lift (a → b₁) (a → b₂)
Equations
@[protected, instance]
def lift_pi_range {α : Sort u} {A : α → Sort ua} {B : α → Sort ub} [Π (i : α), has_lift_t (A i) (B i)] :
has_lift (Π (i : α), A i) (Π (i : α), B i)

A dependent version of lift_fn_range.

Equations
@[protected, instance]
def lift_fn_dom {a₁ : Sort ua₁} {a₂ : Sort ua₂} {b : Sort ub} [has_lift a₂ a₁] :
has_lift (a₁ → b) (a₂ → b)
Equations
@[protected, instance]
def lift_pair {a₁ : Type ua₁} {a₂ : Type ub₂} {b₁ : Type ub₁} {b₂ : Type ub₂} [has_lift_t a₁ a₂] [has_lift_t b₁ b₂] :
has_lift (a₁ × b₁) (a₂ × b₂)
Equations
@[protected, instance]
def lift_pair₁ {a₁ : Type ua₁} {a₂ : Type ua₂} {b : Type ub} [has_lift_t a₁ a₂] :
has_lift (a₁ × b) (a₂ × b)
Equations
@[protected, instance]
def lift_pair₂ {a : Type ua} {b₁ : Type ub₁} {b₂ : Type ub₂} [has_lift_t b₁ b₂] :
has_lift (a × b₁) (a × b₂)
Equations
@[protected, instance]
def lift_list {a : Type u} {b : Type v} [has_lift a b] :
Equations