Module docstring
{"# Coercion
Lean uses a somewhat elaborate system of typeclasses to drive the coercion system.
Here a coercion means an invisible function that is automatically inserted
to fix what would otherwise be a type error. For example, if we have:
def f (x : Nat) : Int := x
then this is clearly not type correct as is, because x has type Nat but
type Int is expected, and normally you will get an error message saying exactly that.
But before it shows that message, it will attempt to synthesize an instance of
CoeT Nat x Int, which will end up going through all the other typeclasses defined
below, to discover that there is an instance of Coe Nat Int defined.
This instance is defined as:
instance : Coe Nat Int := ⟨Int.ofNat⟩
so Lean will elaborate the original function f as if it said:
def f (x : Nat) : Int := Int.ofNat x
which is not a type error anymore.
You can also use the ↑ operator to explicitly indicate a coercion. Using ↑x
instead of x in the example will result in the same output.
Because there are many polymorphic functions in Lean, it is often ambiguous where
the coercion can go. For example:
def f (x y : Nat) : Int := x + y
This could be either ↑x + ↑y where + is the addition on Int, or ↑(x + y)
where + is addition on Nat, or even x + y using a heterogeneous addition
with the type Nat → Nat → Int. You can use the ↑ operator to disambiguate
between these possibilities, but generally Lean will elaborate working from the
\"outside in\", meaning that it will first look at the expression _ + _ : Int
and assign the + to be the one for Int, and then need to insert coercions
for the subterms ↑x : Int and ↑y : Int, resulting in the ↑x + ↑y version.
Note that unlike most operators like +, ↑ is always eagerly unfolded at
parse time into its definition. So if we look at the definition of f from
before, we see no trace of the CoeT.coe function:
```
def f (x : Nat) : Int := x
print f
-- def f : Nat → Int := -- fun (x : Nat) => Int.ofNat x ```
Important typeclasses
Lean resolves a coercion by either inserting a CoeDep instance
or chaining CoeHead? CoeOut* Coe* CoeTail? instances.
(That is, zero or one CoeHead instances, an arbitrary number of CoeOut
instances, etc.)
The CoeHead? CoeOut* instances are chained from the \"left\" side.
So if Lean looks for a coercion from Nat to Int, it starts by trying coerce
Nat using CoeHead by looking for a CoeHead Nat ?α instance, and then
continuing with CoeOut. Similarly Coe* CoeTail? are chained from the \"right\".
These classes should be implemented for coercions:
Coe α βis the most basic class, and the usual one you will want to use when implementing a coercion for your own types. The variables in the typeαmust be a subset of the variables inβ(or out-params of type class parameters), becauseCoeis chained right-to-left.CoeOut α βis likeCoe α βbut chained left-to-right. Use this if the variables in the typeαare a superset of the variables inβ.CoeTail α βis likeCoe α β, but only applied once. Use this for coercions that would cause loops, like[Ring R] → CoeTail Nat R.CoeHead α βis similar toCoeOut α β, but only applied once. Use this for coercions that would cause loops, like[SetLike S α] → CoeHead S (Set α).CoeDep α (x : α) βallowsβto depend not only onαbut on the valuex : αitself. This is useful when the coercion function is dependent. An example of a dependent coercion is the instance forProp → Bool, because it only holds forDecidablepropositions. It is defined as:instance (p : Prop) [Decidable p] : CoeDep Prop p Bool := ...CoeFun α (γ : α → Sort v)is a coercion to a function.γ ashould be a (coercion-to-)function type, and this is triggered whenever an elementf : αappears in an application likef xwhich would not make sense sincefdoes not have a function type.CoeFuninstances apply toCoeOutas well.CoeSort α βis a coercion to a sort.βmust be a universe, and this is triggered whena : αappears in a place where a type is expected, like(x : a)ora → a.CoeSortinstances apply toCoeOutas well.
On top of these instances this file defines several auxiliary type classes:
* CoeTC := Coe*
* CoeOTC := CoeOut* Coe*
* CoeHTC := CoeHead? CoeOut* Coe*
* CoeHTCT := CoeHead? CoeOut* Coe* CoeTail?
* CoeDep := CoeHead? CoeOut* Coe* CoeTail? | CoeDep
","# Basic instances ","# Coe bridge "}