Init.Prelude #
This is the first file in the Lean import hierarchy. It is responsible for setting
up basic definitions, most of which Lean already has "built in knowledge" about,
so it is important that they be set up in exactly this way. (For example, Lean will
use PUnit
in the desugaring of do
notation, or in the pattern match compiler.)
The identity function. id
takes an implicit argument α : Sort u
(a type in any universe), and an argument a : α
, and returns a
.
Although this may look like a useless function, one application of the identity
function is to explicitly put a type on an expression. If e
has type T
,
and T'
is definitionally equal to T
, then @id T' e
typechecks, and Lean
knows that this expression has type T'
rather than T
. This can make a
difference for typeclass inference, since T
and T'
may have different
typeclass instances on them. show T' from e
is sugar for an @id T' e
expression.
Instances For
Function composition is the act of pipelining the result of one function, to the input of another, creating an entirely new function. Example:
#eval Function.comp List.reverse (List.drop 2) [3, 2, 4, 1]
-- [1, 4]
You can use the notation f ∘ g
as shorthand for Function.comp f g
.
#eval (List.reverse ∘ List.drop 2) [3, 2, 4, 1]
-- [1, 4]
A simpler way of thinking about it, is that List.reverse ∘ List.drop 2
is equivalent to fun xs => List.reverse (List.drop 2 xs)
,
the benefit is that the meaning of composition is obvious,
and the representation is compact.
Instances For
The constant function. If a : α
, then Function.const β a : β → α
is the
"constant function with value a
", that is, Function.const β a b = a
.
example (b : Bool) : Function.const Bool 10 b = 10 :=
rfl
#check Function.const Bool 10
-- Bool → Nat
Equations
- Function.const β a x = a
Instances For
The encoding of let_fun x := v; b
is letFun v (fun x => b)
.
This is equal to (fun x => b) v
, so the value of x
is not accessible to b
.
This is in contrast to let x := v; b
, where the value of x
is accessible to b
.
There is special support for letFun
.
Both WHNF and simp
are aware of letFun
and can reduce it when zeta reduction is enabled,
despite the fact it is marked irreducible
.
For metaprogramming, the function Lean.Expr.letFun?
can be used to recognize a let_fun
expression
to extract its parts as if it were a let
expression.
Instances For
inferInstance
synthesizes a value of any target type by typeclass
inference. This function has the same type signature as the identity
function, but the square brackets on the [i : α]
argument means that it will
attempt to construct this argument by typeclass inference. (This will fail if
α
is not a class
.) Example:
#check (inferInstance : Inhabited Nat) -- Inhabited Nat
def foo : Inhabited (Nat × Nat) :=
inferInstance
example : foo.default = (default, default) :=
rfl
Equations
- inferInstance = i
Instances For
inferInstanceAs α
synthesizes a value of any target type by typeclass
inference. This is just like inferInstance
except that α
is given
explicitly instead of being inferred from the target type. It is especially
useful when the target type is some α'
which is definitionally equal to α
,
but the instance we are looking for is only registered for α
(because
typeclass search does not unfold most definitions, but definitional equality
does.) Example:
#check inferInstanceAs (Inhabited Nat) -- Inhabited Nat
Equations
- inferInstanceAs α = i
Instances For
The unit type, the canonical type with one element, named unit
or ()
.
This is the universe-polymorphic version of Unit
; it is preferred to use
Unit
instead where applicable.
For more information about universe levels: Types as objects
- unit: PUnit
PUnit.unit : PUnit
is the canonical element of the unit type.
Instances For
The unit type, the canonical type with one element, named unit
or ()
.
In other words, it describes only a single value, which consists of said constructor applied
to no arguments whatsoever.
The Unit
type is similar to void
in languages derived from C.
Unit
is actually defined as PUnit.{1}
where PUnit
is the universe
polymorphic version. The Unit
should be preferred over PUnit
where possible to avoid
unnecessary universe parameters.
In functional programming, Unit
is the return type of things that "return
nothing", since a type with one element conveys no additional information.
When programming with monads, the type m Unit
represents an action that has
some side effects but does not return a value, while m α
would be an action
that has side effects and returns a value of type α
.
Instances For
Auxiliary unsafe constant used by the Compiler when erasing proofs from code.
It may look strange to have an axiom that says "every proposition is true",
since this is obviously unsound, but the unsafe
marker ensures that the
kernel will not let this through into regular proofs. The lower levels of the
code generator don't need proofs in terms, so this is used to stub the proofs
out.
Auxiliary unsafe constant used by the Compiler to mark unreachable code.
Like lcProof
, this is an unsafe axiom
, which means that even though it is
not sound, the kernel will not let us use it for regular proofs.
Executing this expression to actually synthesize a value of type α
causes
immediate undefined behavior, and the compiler does take advantage of this
to optimize the code assuming that it is not called. If it is not optimized out,
it is likely to appear as a print message saying "unreachable code", but this
behavior is not guaranteed or stable in any way.
True
is a proposition and has only an introduction rule, True.intro : True
.
In other words, True
is simply true, and has a canonical proof, True.intro
For more information: Propositional Logic
- intro: True
True
is true, andTrue.intro
(or more commonly,trivial
) is the proof.
Instances For
False
is the empty proposition. Thus, it has no introduction rules.
It represents a contradiction. False
elimination rule, False.rec
,
expresses the fact that anything follows from a contradiction.
This rule is sometimes called ex falso (short for ex falso sequitur quodlibet),
or the principle of explosion.
For more information: Propositional Logic
Instances For
False.elim : False → C
says that from False
, any desired proposition
C
holds. Also known as ex falso quodlibet (EFQ) or the principle of explosion.
The target type is actually C : Sort u
which means it works for both
propositions and types. When executed, this acts like an "unreachable"
instruction: it is undefined behavior to run, but it will probably print
"unreachable code". (You would need to construct a proof of false to run it
anyway, which you can only do using sorry
or unsound axioms.)
Equations
- False.elim h = False.rec (fun (x : False) => C) h
Instances For
The equality relation. It has one introduction rule, Eq.refl
.
We use a = b
as notation for Eq a b
.
A fundamental property of equality is that it is an equivalence relation.
variable (α : Type) (a b c d : α)
variable (hab : a = b) (hcb : c = b) (hcd : c = d)
example : a = d :=
Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd
Equality is much more than an equivalence relation, however. It has the important property that every assertion
respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value.
That is, given h1 : a = b
and h2 : p a
, we can construct a proof for p b
using substitution: Eq.subst h1 h2
.
Example:
example (α : Type) (a b : α) (p : α → Prop)
(h1 : a = b) (h2 : p a) : p b :=
Eq.subst h1 h2
example (α : Type) (a b : α) (p : α → Prop)
(h1 : a = b) (h2 : p a) : p b :=
h1 ▸ h2
The triangle in the second presentation is a macro built on top of Eq.subst
and Eq.symm
, and you can enter it by typing \t
.
For more information: Equality
Instances For
rfl : a = a
is the unique constructor of the equality type. This is the
same as Eq.refl
except that it takes a
implicitly instead of explicitly.
This is a more powerful theorem than it may appear at first, because although
the statement of the theorem is a = a
, Lean will allow anything that is
definitionally equal to that type. So, for instance, 2 + 2 = 4
is proven in
Lean by rfl
, because both sides are the same up to definitional equality.
Equations
- ⋯ = ⋯
Instances For
The substitution principle for equality. If a = b
and P a
holds,
then P b
also holds. We conventionally use the name motive
for P
here,
so that you can specify it explicitly using e.g.
Eq.subst (motive := fun x => x < 5)
if it is not otherwise inferred correctly.
This theorem is the underlying mechanism behind the rw
tactic, which is
essentially a fancy algorithm for finding good motive
arguments to usefully
apply this theorem to replace occurrences of a
with b
in the goal or
hypotheses.
For more information: Equality
Cast across a type equality. If h : α = β
is an equality of types, and
a : α
, then a : β
will usually not typecheck directly, but this function
will allow you to work around this and embed a
in type β
as cast h a : β
.
It is best to avoid this function if you can, because it is more complicated to reason about terms containing casts, but if the types don't match up definitionally sometimes there isn't anything better you can do.
For more information: Equality
Instances For
Congruence in the function argument: if a₁ = a₂
then f a₁ = f a₂
for
any (nondependent) function f
. This is more powerful than it might look at first, because
you can also use a lambda expression for f
to prove that
<something containing a₁> = <something containing a₂>
. This function is used
internally by tactics like congr
and simp
to apply equalities inside
subterms.
For more information: Equality
Congruence in both function and argument. If f₁ = f₂
and a₁ = a₂
then
f₁ a₁ = f₂ a₂
. This only works for nondependent functions; the theorem
statement is more complex in the dependent case.
For more information: Equality
Initialize the Quotient Module, which effectively adds the following definitions:
opaque Quot {α : Sort u} (r : α → α → Prop) : Sort u
opaque Quot.mk {α : Sort u} (r : α → α → Prop) (a : α) : Quot r
opaque Quot.lift {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) :
(∀ a b : α, r a b → Eq (f a) (f b)) → Quot r → β
opaque Quot.ind {α : Sort u} {r : α → α → Prop} {β : Quot r → Prop} :
(∀ a : α, β (Quot.mk r a)) → ∀ q : Quot r, β q
Heterogeneous equality. HEq a b
asserts that a
and b
have the same
type, and casting a
across the equality yields b
, and vice versa.
You should avoid using this type if you can. Heterogeneous equality does not
have all the same properties as Eq
, because the assumption that the types of
a
and b
are equal is often too weak to prove theorems of interest. One
important non-theorem is the analogue of congr
: If HEq f g
and HEq x y
and f x
and g y
are well typed it does not follow that HEq (f x) (g y)
.
(This does follow if you have f = g
instead.) However if a
and b
have
the same type then a = b
and HEq a b
are equivalent.
Instances For
Product type (aka pair). You can use α × β
as notation for Prod α β
.
Given a : α
and b : β
, Prod.mk a b : Prod α β
. You can use (a, b)
as notation for Prod.mk a b
. Moreover, (a, b, c)
is notation for
Prod.mk a (Prod.mk b c)
.
Given p : Prod α β
, p.1 : α
and p.2 : β
. They are short for Prod.fst p
and Prod.snd p
respectively. You can also write p.fst
and p.snd
.
For more information: Constructors with Arguments
- fst : α
The first projection out of a pair. if
p : α × β
thenp.1 : α
. - snd : β
The second projection out of a pair. if
p : α × β
thenp.2 : β
.
Instances For
And a b
, or a ∧ b
, is the conjunction of propositions. It can be
constructed and destructed like a pair: if ha : a
and hb : b
then
⟨ha, hb⟩ : a ∧ b
, and if h : a ∧ b
then h.left : a
and h.right : b
.
- intro :: (
- left : a
Extract the left conjunct from a conjunction.
h : a ∧ b
thenh.left
, also notated ash.1
, is a proof ofa
. - right : b
Extract the right conjunct from a conjunction.
h : a ∧ b
thenh.right
, also notated ash.2
, is a proof ofb
. - )
Instances For
Bool
is the type of boolean values, true
and false
. Classically,
this is equivalent to Prop
(the type of propositions), but the distinction
is important for programming, because values of type Prop
are erased in the
code generator, while Bool
corresponds to the type called bool
or boolean
in most programming languages.
Instances For
Subtype p
, usually written as {x : α // p x}
, is a type which
represents all the elements x : α
for which p x
is true. It is structurally
a pair-like type, so if you have x : α
and h : p x
then
⟨x, h⟩ : {x // p x}
. An element s : {x // p x}
will coerce to α
but
you can also make it explicit using s.1
or s.val
.
- val : α
If
s : {x // p x}
thens.val : α
is the underlying element in the base type. You can also write this ass.1
, or simply ass
when the type is known from context. - property : p self.val
If
s : {x // p x}
thens.2
ors.property
is the assertion thatp s.1
, that is, thats
is in fact an element for whichp
holds.
Instances For
Gadget for marking output parameters in type classes.
For example, the Membership
class is defined as:
class Membership (α : outParam (Type u)) (γ : Type v)
This means that whenever a typeclass goal of the form Membership ?α ?γ
comes
up, Lean will wait to solve it until ?γ
is known, but then it will run
typeclass inference, and take the first solution it finds, for any value of ?α
,
which thereby determines what ?α
should be.
This expresses that in a term like a ∈ s
, s
might be a Set α
or
List α
or some other type with a membership operation, and in each case
the "member" type α
is determined by looking at the container type.
Instances For
Gadget for marking semi output parameters in type classes.
Semi-output parameters influence the order in which arguments to type class
instances are processed. Lean determines an order where all non-(semi-)output
parameters to the instance argument have to be figured out before attempting to
synthesize an argument (that is, they do not contain assignable metavariables
created during TC synthesis). This rules out instances such as [Mul β] : Add α
(because β
could be anything). Marking a parameter as semi-output is a
promise that instances of the type class will always fill in a value for that
parameter.
For example, the Coe
class is defined as:
class Coe (α : semiOutParam (Sort u)) (β : Sort v)
This means that all Coe
instances should provide a concrete value for α
(i.e., not an assignable metavariable). An instance like Coe Nat Int
or Coe α (Option α)
is fine, but Coe α Nat
is not since it does not provide a value
for α
.
Equations
- semiOutParam α = α
Instances For
Auxiliary declaration used to implement named patterns like x@h:p
.
Equations
- namedPattern x a h = a
Instances For
Auxiliary axiom used to implement sorry
.
The sorry
term/tactic expands to sorryAx _ (synthetic := false)
. This is a
proof of anything, which is intended for stubbing out incomplete parts of a
proof while still having a syntactically correct proof skeleton. Lean will give
a warning whenever a proof uses sorry
, so you aren't likely to miss it, but
you can double check if a theorem depends on sorry
by using
#print axioms my_thm
and looking for sorryAx
in the axiom list.
The synthetic
flag is false when written explicitly by the user, but it is
set to true
when a tactic fails to prove a goal, or if there is a type error
in the expression. A synthetic sorry
acts like a regular one, except that it
suppresses follow-up errors in order to prevent one error from causing a cascade
of other errors because the desired term was not constructed.
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
.
- default : α
Instances
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
.
Instances
The axiom of choice. Nonempty α
is a proof that α
has an element,
but the element itself is erased. The axiom choice
supplies a particular
element of α
given only this proof.
The textbook axiom of choice normally makes a family of choices all at once,
but that is implied from this formulation, because if α : ι → Type
is a
family of types and h : ∀ i, Nonempty (α i)
is a proof that they are all
nonempty, then fun i => Classical.choice (h i) : ∀ i, α i
is a family of
chosen elements. This is actually a bit stronger than the ZFC choice axiom;
this is sometimes called "global choice".
In Lean, we use the axiom of choice to derive the law of excluded middle
(see Classical.em
), so it will often show up in axiom listings where you
may not expect. You can use #print axioms my_thm
to find out if a given
theorem depends on this or other axioms.
This axiom can be used to construct "data", but obviously there is no algorithm
to compute it, so Lean will require you to mark any definition that would
involve executing Classical.choice
or other axioms as noncomputable
, and
will not produce any executable code for such definitions.
The elimination principle for Nonempty α
. If Nonempty α
, and we can
prove p
given any element x : α
, then p
holds. Note that it is essential
that p
is a Prop
here; the version with p
being a Sort u
is equivalent
to Classical.choice
.
Equations
- ⋯ = ⋯
Instances For
A variation on Classical.choice
that uses typeclass inference to
infer the proof of Nonempty α
.
Equations
- Classical.ofNonempty = Classical.choice ⋯
Instances For
Equations
- instInhabitedSort = { default := PUnit }
Equations
- instInhabitedForAll α = { default := fun (x : α) => default }
Equations
- instInhabitedForAll_1 α = { default := fun (x : α) => default }
Bijection between α
and PLift α
NonemptyType.{u}
is the type of nonempty types in universe u
.
It is mainly used in constant declarations where we wish to introduce a type
and simultaneously assert that it is nonempty, but otherwise make the type
opaque.
Equations
- NonemptyType = { α : Type u // Nonempty α }
Instances For
The underlying type of a NonemptyType
.
Equations
- NonemptyType.type type = type.val
Instances For
NonemptyType
is inhabited, because PUnit
is a nonempty type.
Equations
- instInhabitedNonemptyType = { default := { val := PUnit, property := ⋯ } }
Universe lifting operation from a lower Type
universe to a higher one.
To express this using level variables, the input is Type s
and the output is
Type (max s r)
, so if s ≤ r
then the latter is (definitionally) Type r
.
The universe variable r
is written first so that ULift.{r} α
can be used
when s
can be inferred from the type of α
.
- up :: (
- down : α
Extract a value from
ULift α
- )
Instances For
Bijection between α
and ULift.{v} α
Bijection between α
and ULift.{v} α
Decidable p
is a data-carrying class that supplies a proof that p
is
either true
or false
. It is equivalent to Bool
(and in fact it has the
same code generation as Bool
) together with a proof that the Bool
is
true iff p
is.
Decidable
instances are used to infer "computation strategies" for
propositions, so that you can have the convenience of writing propositions
inside if
statements and executing them (which actually executes the inferred
decidability instance instead of the proposition, which has no code).
If a proposition p
is Decidable
, then (by decide : p)
will prove it by
evaluating the decidability instance to isTrue h
and returning h
.
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
typeclass search.
- isFalse: {p : Prop} → ¬p → Decidable p
Prove that
p
is decidable by supplying a proof of¬p
- isTrue: {p : Prop} → p → Decidable p
Prove that
p
is decidable by supplying a proof ofp
Instances
A decidable predicate. See Decidable
.
Equations
- DecidablePred r = ((a : α) → Decidable (r a))
Instances For
A decidable relation. See Decidable
.
Equations
- DecidableRel r = ((a b : α) → Decidable (r a b))
Instances For
Asserts that α
has decidable equality, that is, a = b
is decidable
for all a b : α
. See Decidable
.
Equations
- DecidableEq α = ((a b : α) → Decidable (a = b))
Instances For
Proves that a = b
is decidable given DecidableEq α
.
Instances For
Equations
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.
- beq : α → α → Bool
Boolean equality, notated as
a == b
.
Instances
"Dependent" if-then-else, normally written via the notation if h : c then t(h) else e(h)
,
is sugar for dite c (fun h => t(h)) (fun h => e(h))
, and it is the same as
if c then t else e
except that t
is allowed to depend on a proof h : c
,
and e
can depend on h : ¬c
. (Both branches use the same name for the hypothesis,
even though it has different types in the two cases.)
We use this to be able to communicate the if-then-else condition to the branches.
For example, Array.get arr ⟨i, h⟩
expects a proof h : i < arr.size
in order to
avoid a bounds check, so you can write if h : i < arr.size then arr.get ⟨i, h⟩ else ...
to avoid the bounds check inside the if branch. (Of course in this case we have only
lifted the check into an explicit if
, but we could also use this proof multiple times
or derive i < arr.size
from some other proposition that we are checking in the if
.)
Equations
- dite c t e = Decidable.casesOn h e t
Instances For
if-then-else #
if c then t else e
is notation for ite c t e
, "if-then-else", which decides to
return t
or e
depending on whether c
is true or false. The explicit argument
c : Prop
does not have any actual computational content, but there is an additional
[Decidable c]
argument synthesized by typeclass inference which actually
determines how to evaluate c
to true or false. Write if h : c then t else e
instead for a "dependent if-then-else" dite
, which allows t
/e
to use the fact
that c
is true/false.
Equations
- (if c then t else e) = Decidable.casesOn h (fun (x : ¬c) => e) fun (x : c) => t
Instances For
Boolean operators #
The type of natural numbers, starting at zero. It is defined as an inductive type freely generated by "zero is a natural number" and "the successor of a natural number is a natural number".
You can prove a theorem P n
about n : Nat
by induction n
, which will
expect a proof of the theorem for P 0
, and a proof of P (succ i)
assuming
a proof of P i
. The same method also works to define functions by recursion
on natural numbers: induction and recursion are two expressions of the same
operation from Lean's point of view.
open Nat
example (n : Nat) : n < succ n := by
induction n with
| zero =>
show 0 < 1
decide
| succ i ih => -- ih : i < succ i
show succ i < succ (succ i)
exact Nat.succ_lt_succ ih
This type is special-cased by both the kernel and the compiler:
- The type of expressions contains "
Nat
literals" as a primitive constructor, and the kernel knows how to reduce zero/succ expressions to nat literals. - If implemented naively, this type would represent a numeral
n
in unary as a linked list withn
links, which is horribly inefficient. Instead, the runtime itself has a special representation forNat
which stores numbers up to 2^63 directly and larger numbers use an arbitrary precision "bignum" library (usually GMP).
Instances For
The class OfNat α n
powers the numeric literal parser. If you write
37 : α
, Lean will attempt to synthesize OfNat α 37
, and will generate
the term (OfNat.ofNat 37 : α)
.
There is a bit of infinite regress here since the desugaring apparently
still contains a literal 37
in it. The type of expressions contains a
primitive constructor for "raw natural number literals", which you can directly
access using the macro nat_lit 37
. Raw number literals are always of type Nat
.
So it would be more correct to say that Lean looks for an instance of
OfNat α (nat_lit 37)
, and it generates the term (OfNat.ofNat (nat_lit 37) : α)
.
- ofNat : α
The
OfNat.ofNat
function is automatically inserted by the parser when the user writes a numeric literal like1 : α
. Implementations of this typeclass can therefore customize the behavior ofn : α
based onn
andα
.
Instances
Equations
- instOfNatNat n = { ofNat := n }
Transitive chaining of proofs, used e.g. by calc
.
It takes two relations r
and s
as "input", and produces an "output"
relation t
, with the property that r a b
and s b c
implies t a c
.
The calc
tactic uses this so that when it sees a chain with a ≤ b
and b < c
it knows that this should be a proof of a < c
because there is an instance
Trans (·≤·) (·<·) (·<·)
.
- trans : {a : α} → {b : β} → {c : γ} → r a b → s b c → t a c
Compose two proofs by transitivity, generalized over the relations involved.
Instances
Equations
- instTransEq r = { trans := fun {a b : α} {c : γ} (heq : a = b) (h' : r b c) => ⋯ ▸ h' }
Equations
- instTransEq_1 r = { trans := fun {a : α} {b c : β} (h' : r a b) (heq : b = c) => heq ▸ h' }
The notation typeclass for heterogeneous addition.
This enables the notation a + b : γ
where a : α
, b : β
.
- hAdd : α → β → γ
a + b
computes the sum ofa
andb
. The meaning of this notation is type-dependent.
Instances
The notation typeclass for heterogeneous subtraction.
This enables the notation a - b : γ
where a : α
, b : β
.
- hSub : α → β → γ
a - b
computes the difference ofa
andb
. The meaning of this notation is type-dependent.- For natural numbers, this operator saturates at 0:
a - b = 0
whena ≤ b
.
- For natural numbers, this operator saturates at 0:
Instances
The notation typeclass for heterogeneous multiplication.
This enables the notation a * b : γ
where a : α
, b : β
.
- hMul : α → β → γ
a * b
computes the product ofa
andb
. The meaning of this notation is type-dependent.
Instances
The notation typeclass for heterogeneous division.
This enables the notation a / b : γ
where a : α
, b : β
.
- hDiv : α → β → γ
Instances
The notation typeclass for heterogeneous modulo / remainder.
This enables the notation a % b : γ
where a : α
, b : β
.
- hMod : α → β → γ
Instances
The notation typeclass for heterogeneous exponentiation.
This enables the notation a ^ b : γ
where a : α
, b : β
.
- hPow : α → β → γ
a ^ b
computesa
to the power ofb
. The meaning of this notation is type-dependent.
Instances
The notation typeclass for heterogeneous append.
This enables the notation a ++ b : γ
where a : α
, b : β
.
- hAppend : α → β → γ
a ++ b
is the result of concatenation ofa
andb
, usually read "append". The meaning of this notation is type-dependent.
Instances
The typeclass behind the notation a <|> b : γ
where a : α
, b : β
.
Because b
is "lazy" in this notation, it is passed as Unit → β
to the
implementation so it can decide when to evaluate it.
- hOrElse : α → (Unit → β) → γ
a <|> b
executesa
and returns the result, unless it fails in which case it executes and returnsb
. Becauseb
is not always executed, it is passed as a thunk so it can be forced only when needed. The meaning of this notation is type-dependent.
Instances
The typeclass behind the notation a >> b : γ
where a : α
, b : β
.
Because b
is "lazy" in this notation, it is passed as Unit → β
to the
implementation so it can decide when to evaluate it.
- hAndThen : α → (Unit → β) → γ
a >> b
executesa
, ignores the result, and then executesb
. Ifa
fails thenb
is not executed. Becauseb
is not always executed, it is passed as a thunk so it can be forced only when needed. The meaning of this notation is type-dependent.
Instances
The typeclass behind the notation a <<< b : γ
where a : α
, b : β
.
- hShiftLeft : α → β → γ
Instances
The typeclass behind the notation a >>> b : γ
where a : α
, b : β
.
- hShiftRight : α → β → γ
Instances
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 aNat
.HomogeneousPow
is for types whose base and exponent are preferentially the same.
- pow : α → β → α
a ^ b
computesa
to the power ofb
. SeeHPow
.
Instances
The homogenous 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.
- pow : α → Nat → α
Instances
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.
- pow : α → α → α
a ^ b
computesa
to the power ofb
wherea
andb
both have the same type.
Instances
The typeclass behind the notation ~~~a : α
where a : α
.
- complement : α → α
The implementation of
~~~a : α
.
Instances
The homogeneous version of HShiftLeft
: a <<< b : α
where a b : α
.
- shiftLeft : α → α → α
The implementation of
a <<< b : α
. SeeHShiftLeft
.
Instances
The homogeneous version of HShiftRight
: a >>> b : α
where a b : α
.
- shiftRight : α → α → α
The implementation of
a >>> b : α
. SeeHShiftRight
.
Instances
Equations
- instPowNat = { pow := fun (a : α) (n : Nat) => NatPow.pow a n }
Equations
- instPow = { pow := fun (a b : α) => HomogeneousPow.pow a b }
Equations
- instHAppend = { hAppend := fun (a b : α) => Append.append a b }
Equations
- instHOrElse = { hOrElse := fun (a : α) (b : Unit → α) => OrElse.orElse a b }
Equations
- instHAndThen = { hAndThen := fun (a : α) (b : Unit → α) => AndThen.andThen a b }
Equations
- instHShiftLeft = { hShiftLeft := fun (a b : α) => ShiftLeft.shiftLeft a b }
Equations
- instHShiftRight = { hShiftRight := fun (a b : α) => ShiftRight.shiftRight a b }
Addition of natural numbers.
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model (and it is soundness-critical that they coincide).
Instances For
Multiplication of natural numbers.
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model (and it is soundness-critical that they coincide).
Instances For
The power operation on natural numbers.
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model.
Instances For
(Boolean) equality of natural numbers.
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model (and it is soundness-critical that they coincide).
Equations
Instances For
A decision procedure for equality of natural numbers.
This definition is overridden in the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model.
Instances For
The (Boolean) less-equal relation on natural numbers.
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model (and it is soundness-critical that they coincide).
Equations
Instances For
(Truncated) subtraction of natural numbers. Because natural numbers are not
closed under subtraction, we define n - m
to be 0
when n < m
.
This definition is overridden in both the kernel and the compiler to efficiently
evaluate using the "bignum" representation (see Nat
). The definition provided
here is the logical model (and it is soundness-critical that they coincide).
Instances For
Gets the word size of the platform. That is, whether the platform is 64 or 32 bits.
This function is opaque because we cannot guarantee at compile time that the target will have the same size as the host, and also because we would like to avoid typechecking being architecture-dependent. Nevertheless, Lean only works on 64 and 32 bit systems so we can encode this as a fact available for proof purposes.
Gets the word size of the platform. That is, whether the platform is 64 or 32 bits.
Equations
Instances For
Fin n
is a natural number i
with the constraint that 0 ≤ i < n
.
It is the "canonical type with n
elements".
Instances For
The size of type UInt8
, that is, 2^8 = 256
.
Equations
- UInt8.size = 256
Instances For
Pack a Nat
less than 2^8
into a UInt8
.
This function is overridden with a native implementation.
Equations
- UInt8.ofNatCore n h = { val := { val := n, isLt := h } }
Instances For
Equations
- instInhabitedUInt8 = { default := UInt8.ofNatCore 0 instInhabitedUInt8.proof_1 }
The size of type UInt16
, that is, 2^16 = 65536
.
Equations
- UInt16.size = 65536
Instances For
Pack a Nat
less than 2^16
into a UInt16
.
This function is overridden with a native implementation.
Equations
- UInt16.ofNatCore n h = { val := { val := n, isLt := h } }
Instances For
Equations
Equations
- instInhabitedUInt16 = { default := UInt16.ofNatCore 0 instInhabitedUInt16.proof_1 }
The size of type UInt32
, that is, 2^32 = 4294967296
.
Equations
- UInt32.size = 4294967296
Instances For
Pack a Nat
less than 2^32
into a UInt32
.
This function is overridden with a native implementation.
Equations
- UInt32.ofNatCore n h = { val := { val := n, isLt := h } }
Instances For
Unpack a UInt32
as a Nat
.
This function is overridden with a native implementation.
Equations
- UInt32.toNat n = ↑n.val
Instances For
Equations
Equations
- instInhabitedUInt32 = { default := UInt32.ofNatCore 0 instInhabitedUInt32.proof_1 }
Equations
- instLTUInt32 = { lt := fun (a b : UInt32) => a.val < b.val }
Equations
- instLEUInt32 = { le := fun (a b : UInt32) => a.val ≤ b.val }
Decides less-equal on UInt32
.
This function is overridden with a native implementation.
Equations
- UInt32.decLt a b = match a, b with | { val := n }, { val := m } => inferInstanceAs (Decidable (n < m))
Instances For
Decides less-than on UInt32
.
This function is overridden with a native implementation.
Equations
- UInt32.decLe a b = match a, b with | { val := n }, { val := m } => inferInstanceAs (Decidable (n ≤ m))
Instances For
Equations
Equations
The size of type UInt64
, that is, 2^64 = 18446744073709551616
.
Equations
- UInt64.size = 18446744073709551616
Instances For
Pack a Nat
less than 2^64
into a UInt64
.
This function is overridden with a native implementation.
Equations
- UInt64.ofNatCore n h = { val := { val := n, isLt := h } }
Instances For
Equations
Equations
- instInhabitedUInt64 = { default := UInt64.ofNatCore 0 instInhabitedUInt64.proof_1 }
The size of type UInt16
, that is, 2^System.Platform.numBits
, which may
be either 2^32
or 2^64
depending on the platform's architecture.
Remark: we define USize.size
using (2^numBits - 1) + 1
to ensure the
Lean unifier can solve contraints such as ?m + 1 = USize.size
. Recall that
numBits
does not reduce to a numeral in the Lean kernel since it is platform
specific. Without this trick, the following definition would be rejected by the
Lean type checker.
def one: Fin USize.size := 1
Because Lean would fail to synthesize instance OfNat (Fin USize.size) 1
.
Recall that the OfNat
instance for Fin
is
instance : OfNat (Fin (n+1)) i where
ofNat := Fin.ofNat i
Equations
- USize.size = Nat.succ (Nat.sub (2 ^ System.Platform.numBits) 1)
Instances For
A USize
is an unsigned integer with the size of a word
for the platform's architecture.
For example, if running on a 32-bit machine, USize is equivalent to UInt32. Or on a 64-bit machine, UInt64.
- val : Fin USize.size
Unpack a
USize
as aNat
less thanUSize.size
. This function is overridden with a native implementation.
Instances For
Pack a Nat
less than USize.size
into a USize
.
This function is overridden with a native implementation.
Equations
- USize.ofNatCore n h = { val := { val := n, isLt := h } }
Instances For
Equations
- instInhabitedUSize = { default := USize.ofNatCore 0 instInhabitedUSize.proof_1 }
Upcast a Nat
less than 2^32
to a USize
.
This is lossless because USize.size
is either 2^32
or 2^64
.
This function is overridden with a native implementation.
Equations
- USize.ofNat32 n h = { val := { val := n, isLt := ⋯ } }
Instances For
A UInt32
denotes a valid unicode codepoint if it is less than 0x110000
, and
it is also not a "surrogate" character (the range 0xd800
to 0xdfff
inclusive).
Equations
Instances For
Pack a Nat
encoding a valid codepoint into a Char
.
This function is overridden with a native implementation.
Equations
- Char.ofNatAux n h = { val := { val := { val := n, isLt := ⋯ } }, valid := h }
Instances For
Convert a Nat
into a Char
. If the Nat
does not encode a valid unicode scalar value,
'\0'
is returned instead.
Equations
- Char.ofNat n = if h : Nat.isValidChar n then Char.ofNatAux n h else { val := { val := { val := 0, isLt := Char.ofNat.proof_1 } }, valid := Char.ofNat.proof_2 }
Instances For
Returns the number of bytes required to encode this Char
in UTF-8.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Option α
is the type of values which are either some a
for some a : α
,
or none
. In functional programming languages, this type is used to represent
the possibility of failure, or sometimes nullability.
For example, the function HashMap.find? : HashMap α β → α → Option β
looks up
a specified key a : α
inside the map. Because we do not know in advance
whether the key is actually in the map, the return type is Option β
, where
none
means the value was not in the map, and some b
means that the value
was found and b
is the value retrieved.
To extract a value from an Option α
, we use pattern matching:
def map (f : α → β) (x : Option α) : Option β :=
match x with
| some a => some (f a)
| none => none
We can also use if let
to pattern match on Option
and get the value
in the branch:
def map (f : α → β) (x : Option α) : Option β :=
if let some a := x then
some (f a)
else
none
Instances For
Get with default. If opt : Option α
and dflt : α
, then opt.getD dflt
returns a
if opt = some a
and dflt
otherwise.
This function is @[macro_inline]
, so dflt
will not be evaluated unless
opt
turns out to be none
.
Equations
- Option.getD opt dflt = match opt with | some x => x | none => dflt
Instances For
List α
is the type of ordered lists with elements of type α
.
It is implemented as a linked list.
List α
is isomorphic to Array α
, but they are useful for different things:
List α
is easier for reasoning, andArray α
is modeled as a wrapper aroundList α
List α
works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared,Array α
will have better performance because it can do destructive updates.
Instances For
Implements decidable equality for List α
, assuming α
has decidable equality.
Equations
- One or more equations did not get rendered due to their size.
- List.hasDecEq [] [] = isTrue ⋯
- List.hasDecEq (head :: tail) [] = isFalse ⋯
- List.hasDecEq [] (head :: tail) = isFalse ⋯
Instances For
Equations
- instDecidableEqList = List.hasDecEq
Folds a function over a list from the left:
foldl f z [a, b, c] = f (f (f z a) b) c
Equations
- List.foldl f x [] = x
- List.foldl f x (b :: l) = List.foldl f (f x b) l
Instances For
The length of a list: [].length = 0
and (a :: l).length = l.length + 1
.
This function is overridden in the compiler to lengthTR
, which uses constant
stack space, while leaving this function to use the "naive" recursion which is
easier for reasoning.
Equations
- List.length [] = 0
- List.length (head :: as) = List.length as + 1
Instances For
Auxiliary function for List.lengthTR
.
Equations
- List.lengthTRAux [] x = x
- List.lengthTRAux (head :: as) x = List.lengthTRAux as (Nat.succ x)
Instances For
A tail-recursive version of List.length
, used to implement List.length
without running out of stack space.
Equations
- List.lengthTR as = List.lengthTRAux as 0
Instances For
l.concat a
appends a
at the end of l
, that is, l ++ [a]
.
Equations
- List.concat [] x = [x]
- List.concat (a :: as) x = a :: List.concat as x
Instances For
String
is the type of (UTF-8 encoded) strings.
The compiler overrides the data representation of this type to a byte sequence,
and both String.utf8ByteSize
and String.length
are cached and O(1).
Instances For
Equations
A byte position in a String
. Internally, String
s are UTF-8 encoded.
Codepoint positions (counting the Unicode codepoints rather than bytes)
are represented by plain Nat
s instead.
Indexing a String
by a byte position is constant-time, while codepoint
positions need to be translated internally to byte positions in linear-time.
A byte position p
is valid for a string s
if 0 ≤ p ≤ s.endPos
and p
lies on a UTF8 byte boundary.
- byteIdx : Nat
Get the underlying byte index of a
String.Pos
Instances For
Equations
- instInhabitedPos = { default := { byteIdx := 0 } }
Equations
- One or more equations did not get rendered due to their size.
A Substring
is a view into some subslice of a String
.
The actual string slicing is deferred because this would require copying the
string; here we only store a reference to the original string for
garbage collection purposes.
- str : String
The underlying string to slice.
- startPos : String.Pos
The byte position of the start of the string slice.
- stopPos : String.Pos
The byte position of the end of the string slice.
Instances For
Equations
- instInhabitedSubstring = { default := { str := "", startPos := { byteIdx := 0 }, stopPos := { byteIdx := 0 } } }
The byte length of the substring.
Equations
- Substring.bsize x = match x with | { str := str, startPos := b, stopPos := e } => Nat.sub e.byteIdx b.byteIdx
Instances For
The UTF-8 byte length of this string. This is overridden by the compiler to be cached and O(1).
Equations
- String.utf8ByteSize x = match x with | { data := s } => String.utf8ByteSize.go s
Instances For
Equations
- String.utf8ByteSize.go [] = 0
- String.utf8ByteSize.go (c :: cs) = String.utf8ByteSize.go cs + String.csize c
Instances For
Equations
- instHAddPos = { hAdd := fun (p₁ p₂ : String.Pos) => { byteIdx := p₁.byteIdx + p₂.byteIdx } }
Equations
- instHSubPos = { hSub := fun (p₁ p₂ : String.Pos) => { byteIdx := p₁.byteIdx - p₂.byteIdx } }
Equations
- instHAddPosChar = { hAdd := fun (p : String.Pos) (c : Char) => { byteIdx := p.byteIdx + String.csize c } }
Equations
- instHAddPosString = { hAdd := fun (p : String.Pos) (s : String) => { byteIdx := p.byteIdx + String.utf8ByteSize s } }
Equations
- instLEPos = { le := fun (p₁ p₂ : String.Pos) => p₁.byteIdx ≤ p₂.byteIdx }
Equations
- instLTPos = { lt := fun (p₁ p₂ : String.Pos) => p₁.byteIdx < p₂.byteIdx }
Equations
- instDecidableLePosInstLEPos p₁ p₂ = inferInstanceAs (Decidable (p₁.byteIdx ≤ p₂.byteIdx))
Equations
- instDecidableLtPosInstLTPos p₁ p₂ = inferInstanceAs (Decidable (p₁.byteIdx < p₂.byteIdx))
A String.Pos
pointing at the end of this string.
Equations
- String.endPos s = { byteIdx := String.utf8ByteSize s }
Instances For
Convert a String
into a Substring
denoting the entire string.
Equations
- String.toSubstring s = { str := s, startPos := { byteIdx := 0 }, stopPos := String.endPos s }
Instances For
This function will cast a value of type α
to type β
, and is a no-op in the
compiler. This function is extremely dangerous because there is no guarantee
that types α
and β
have the same data representation, and this can lead to
memory unsafety. It is also logically unsound, since you could just cast
True
to False
. For all those reasons this function is marked as unsafe
.
It is implemented by lifting both α
and β
into a common universe, and then
using cast (lcProof : ULift (PLift α) = ULift (PLift β))
to actually perform
the cast. All these operations are no-ops in the compiler.
Using this function correctly requires some knowledge of the data representation of the source and target types. Some general classes of casts which are safe in the current runtime:
Array α
toArray β
whereα
andβ
have compatible representations, or more generally for other inductive types.Quot α r
andα
.@Subtype α p
andα
, or generally any structure containing only one non-Prop
field of typeα
.- Casting
α
to/fromNonScalar
whenα
is a boxed generic type (i.e. a function that accepts an arbitrary typeα
and is not specialized to a scalar type likeUInt8
).
Equations
- unsafeCast a = (cast ⋯ { down := { down := a } }).down.down
Instances For
(panic "msg" : α)
has a built-in implementation which prints msg
to
the error buffer. It does not terminate execution, and because it is a safe
function, it still has to return an element of α
, so it takes [Inhabited α]
and returns default
. It is primarily intended for debugging in pure contexts,
and assertion failures.
Because this is a pure function with side effects, it is marked as
@[never_extract]
so that the compiler will not perform common sub-expression
elimination and other optimizations that assume that the expression is pure.
Instances For
The class GetElem cont idx elem dom
implements the xs[i]
notation.
When you write this, given xs : cont
and i : idx
, Lean looks for an instance
of GetElem cont idx elem dom
. Here elem
is the type of xs[i]
, while
dom
is whatever proof side conditions are required to make this applicable.
For example, the instance for arrays looks like
GetElem (Array α) Nat α (fun xs i => i < xs.size)
.
The proof side-condition dom xs i
is automatically dispatched by the
get_elem_tactic
tactic, which can be extended by adding more clauses to
get_elem_tactic_trivial
.
- getElem : (xs : cont) → (i : idx) → dom xs i → elem
The syntax
arr[i]
gets thei
'th element of the collectionarr
. If there are proof side conditions to the application, they will be automatically inferred by theget_elem_tactic
tactic.The actual behavior of this class is type-dependent, but here are some important implementations:
arr[i] : α
wherearr : Array α
andi : Nat
ori : USize
: does array indexing with no bounds check and a proof side goali < arr.size
.l[i] : α
wherel : List α
andi : Nat
: index into a list, with proof side goali < l.length
.stx[i] : Syntax
wherestx : Syntax
andi : Nat
: get a syntax argument, no side goal (returns.missing
out of range)
There are other variations on this syntax:
arr[i]
: proves the proof side goal byget_elem_tactic
arr[i]!
: panics if the side goal is falsearr[i]?
: returnsnone
if the side goal is falsearr[i]'h
: usesh
to prove the side goal
Instances
Array α
is the type of dynamic arrays
with elements from α
. This type has special support in the runtime.
An array has a size and a capacity; the size is Array.size
but the capacity
is not observable from Lean code. Arrays perform best when unshared; as long
as they are used "linearly" all updates will be performed destructively on the
array, so it has comparable performance to mutable arrays in imperative
programming languages.
From the point of view of proofs Array α
is just a wrapper around List α
.
- data : List α
Converts a
Array α
into anList α
.At runtime, this projection is implemented by
Array.toList
and is O(n) in the length of the array.
Instances For
Construct a new empty array with initial capacity c
.
Equations
- Array.mkEmpty c = { data := [] }
Instances For
Get the size of an array. This is a cached value, so it is O(1) to access.
Equations
- Array.size a = List.length a.data
Instances For
Access an element from an array, or return v₀
if the index is out of bounds.
Equations
- Array.getD a i v₀ = if h : i < Array.size a then Array.get a { val := i, isLt := h } else v₀
Instances For
Access an element from an array, or panic if the index is out of bounds.
Equations
- Array.get! a i = Array.getD a i default
Instances For
Push an element onto the end of an array. This is amortized O(1) because
Array α
is internally a dynamic array.
Equations
- Array.push a v = { data := List.concat a.data v }
Instances For
Create array #[a₁, a₂]
Equations
- #[a₁, a₂] = Array.push (Array.push (Array.mkEmpty 2) a₁) a₂
Instances For
Create array #[a₁, a₂, a₃]
Equations
- #[a₁, a₂, a₃] = Array.push (Array.push (Array.push (Array.mkEmpty 3) a₁) a₂) a₃
Instances For
Create array #[a₁, a₂, a₃, a₄]
Equations
- #[a₁, a₂, a₃, a₄] = Array.push (Array.push (Array.push (Array.push (Array.mkEmpty 4) a₁) a₂) a₃) a₄
Instances For
Create array #[a₁, a₂, a₃, a₄, a₅]
Equations
- #[a₁, a₂, a₃, a₄, a₅] = Array.push (Array.push (Array.push (Array.push (Array.push (Array.mkEmpty 5) a₁) a₂) a₃) a₄) a₅
Instances For
Create array #[a₁, a₂, a₃, a₄, a₅, a₆]
Equations
- #[a₁, a₂, a₃, a₄, a₅, a₆] = Array.push (Array.push (Array.push (Array.push (Array.push (Array.push (Array.mkEmpty 6) a₁) a₂) a₃) a₄) a₅) a₆
Instances For
Create array #[a₁, a₂, a₃, a₄, a₅, a₆, a₇]
Equations
- #[a₁, a₂, a₃, a₄, a₅, a₆, a₇] = Array.push (Array.push (Array.push (Array.push (Array.push (Array.push (Array.push (Array.mkEmpty 7) a₁) a₂) a₃) a₄) a₅) a₆) a₇
Instances For
Create array #[a₁, a₂, a₃, a₄, a₅, a₆, a₇, a₈]
Equations
- One or more equations did not get rendered due to their size.
Instances For
Set an element in an array without bounds checks, using a Fin
index.
This will perform the update destructively provided that a
has a reference
count of 1 when called.
Instances For
Set an element in an array, or do nothing if the index is out of bounds.
This will perform the update destructively provided that a
has a reference
count of 1 when called.
Equations
- Array.setD a i v = if h : i < Array.size a then Array.set a { val := i, isLt := h } v else a
Instances For
Set an element in an array, or panic if the index is out of bounds.
This will perform the update destructively provided that a
has a reference
count of 1 when called.
Equations
- Array.set! a i v = Array.setD a i v
Instances For
Slower Array.append
used in quotations.
Equations
- Array.appendCore as bs = Array.appendCore.loop bs (Array.size bs) 0 as
Instances For
Returns the slice of as
from indices start
to stop
(exclusive).
If start
is greater or equal to stop
, the result is empty.
If stop
is greater than the length of as
, the length is used instead.
Equations
- Array.extract as start stop = let sz' := Nat.sub (min stop (Array.size as)) start; Array.extract.loop as sz' start (Array.mkEmpty sz')
Instances For
Auxiliary definition for List.toArray
.
Equations
- List.toArrayAux [] x = x
- List.toArrayAux (a :: as) x = List.toArrayAux as (Array.push x a)
Instances For
A non-tail-recursive version of List.length
, used for List.toArray
.
Equations
- List.redLength [] = 0
- List.redLength (head :: as) = Nat.succ (List.redLength as)
Instances For
Convert a List α
into an Array α
. This is O(n) in the length of the list.
Equations
- List.toArray as = List.toArrayAux as (Array.mkEmpty (List.redLength as))
Instances For
In functional programming, a "functor" is a function on types F : Type u → Type v
equipped with an operator called map
or <$>
such that if f : α → β
then
map f : F α → F β
, so f <$> x : F β
if x : F α
. This corresponds to the
category-theory notion of functor in
the special case where the category is the category of types and functions
between them, except that this class supplies only the operations and not the
laws (see LawfulFunctor
).
- map : {α β : Type u} → (α → β) → f α → f β
If
f : α → β
andx : F α
thenf <$> x : F β
. - mapConst : {α β : Type u} → α → f β → f α
The special case
const a <$> x
, which can sometimes be implemented more efficiently.
Instances
The typeclass which supplies the <*
"seqLeft" function. See Applicative
.
If
x : F α
andy : F β
, thenx <* y
evaluatesx
, theny
, and returns the result ofx
.To avoid surprising evaluation semantics,
y
is taken "lazily", using aUnit → f β
function.
Instances
The typeclass which supplies the *>
"seqRight" function. See Applicative
.
If
x : F α
andy : F β
, thenx *> y
evaluatesx
, theny
, and returns the result ofy
.To avoid surprising evaluation semantics,
y
is taken "lazily", using aUnit → f β
function.
Instances
An applicative functor is
an intermediate structure between Functor
and Monad
. It mainly consists of
two operations:
The seq
operator gives a notion of evaluation order to the effects, where
the first argument is executed before the second, but unlike a monad the results
of earlier computations cannot be used to define later actions.
Instances
A monad is a structure which abstracts the concept of sequential control flow. It mainly consists of two operations:
Like many functional programming languages, Lean makes extensive use of monads
for structuring programs. In particular, the do
notation is a very powerful
syntax over monad operations, and it depends on a Monad
instance.
See the do
notation
chapter of the manual for details.
Instances
A fusion of Haskell's sequence
and map
. Used in syntax quotations.
Equations
- Array.sequenceMap as f = Array.sequenceMap.loop as f (Array.size as) 0 (Array.mkEmpty (Array.size as))
Instances For
A function for lifting a computation from an inner Monad
to an outer Monad
.
Like Haskell's MonadTrans
, but n
does not have to be a monad transformer.
Alternatively, an implementation of MonadLayer
without layerInvmap
(so far).
- monadLift : {α : Type u} → m α → n α
Lifts a value from monad
m
into monadn
.
Instances
The reflexive-transitive closure of MonadLift
. monadLift
is used to
transitively lift monadic computations such as StateT.get
or StateT.put s
.
Corresponds to Haskell's MonadLift
.
- monadLift : {α : Type u} → m α → n α
Lifts a value from monad
m
into monadn
.
Instances
Equations
- instMonadLiftT m n o = { monadLift := fun {α : Type u_1} (x : m α) => MonadLift.monadLift (monadLift x) }
Equations
- instMonadLiftT_1 m = { monadLift := fun {α : Type u_1} (x : m α) => x }
A functor in the category of monads. Can be used to lift monad-transforming functions.
Based on MFunctor
from the pipes
Haskell package, but not restricted to
monad transformers. Alternatively, an implementation of MonadTransFunctor
.
Lifts a monad morphism
f : {β : Type u} → m β → m β
tomonadMap f : {α : Type u} → n α → n α
.
Instances
The reflexive-transitive closure of MonadFunctor
.
monadMap
is used to transitively lift Monad
morphisms.
Lifts a monad morphism
f : {β : Type u} → m β → m β
tomonadMap f : {α : Type u} → n α → n α
.
Instances
Equations
- instMonadFunctorT m n o = { monadMap := fun {α : Type u_1} (f : {β : Type u_1} → m β → m β) => MonadFunctor.monadMap fun {β : Type u_1} => monadMap fun {β : Type u_1} => f }
Equations
- monadFunctorRefl m = { monadMap := fun {α : Type u_1} (f : {β : Type u_1} → m β → m β) => f }
Except ε α
is a type which represents either an error of type ε
, or an "ok"
value of type α
. The error type is listed first because
Except ε : Type → Type
is a Monad
: the pure operation is ok
and the bind
operation returns the first encountered error
.
- error: {ε : Type u} → {α : Type v} → ε → Except ε α
A failure value of type
ε
- ok: {ε : Type u} → {α : Type v} → α → Except ε α
A success value of type
α
Instances For
Equations
- instInhabitedExcept = { default := Except.error default }
An implementation of Haskell's MonadError
class. A MonadError ε m
is a
monad m
with two operations:
throw : ε → m α
"throws an error" of typeε
to the nearest enclosing catch blocktryCatch (body : m α) (handler : ε → m α) : m α
will catch any errors inbody
and pass the resulting error tohandler
. Errors inhandler
will not be caught.
The try ... catch e => ...
syntax inside do
blocks is sugar for the
tryCatch
operation.
- throw : {α : Type v} → ε → m α
throw : ε → m α
"throws an error" of typeε
to the nearest enclosing catch block. - tryCatch : {α : Type v} → m α → (ε → m α) → m α
tryCatch (body : m α) (handler : ε → m α) : m α
will catch any errors inbody
and pass the resulting error tohandler
. Errors inhandler
will not be caught.
Instances
This is the same as throw
, but allows specifying the particular error type
in case the monad supports throwing more than one type of error.
Equations
- throwThe ε e = MonadExceptOf.throw e
Instances For
This is the same as tryCatch
, but allows specifying the particular error type
in case the monad supports throwing more than one type of error.
Equations
- tryCatchThe ε x handle = MonadExceptOf.tryCatch x handle
Instances For
Similar to MonadExceptOf
, but ε
is an outParam
for convenience.
- throw : {α : Type v} → ε → m α
throw : ε → m α
"throws an error" of typeε
to the nearest enclosing catch block. - tryCatch : {α : Type v} → m α → (ε → m α) → m α
tryCatch (body : m α) (handler : ε → m α) : m α
will catch any errors inbody
and pass the resulting error tohandler
. Errors inhandler
will not be caught.
Instances
"Unwraps" an Except ε α
to get the α
, or throws the exception otherwise.
Instances For
Equations
- instMonadExcept ε m = { throw := fun {α : Type v} => throwThe ε, tryCatch := fun {α : Type v} => tryCatchThe ε }
A MonadExcept
can implement t₁ <|> t₂
as try t₁ catch _ => t₂
.
Equations
- MonadExcept.orElse t₁ t₂ = tryCatch t₁ fun (x : ε) => t₂ ()
Instances For
Equations
- MonadExcept.instOrElse = { orElse := MonadExcept.orElse }
Equations
- One or more equations did not get rendered due to their size.
Equations
- ReaderT.instApplicativeReaderT = Applicative.mk
Equations
- ReaderT.instMonadFunctorReaderT ρ m = { monadMap := fun {α : Type u_1} (f : {β : Type u_1} → m β → m β) (x : ReaderT ρ m α) (ctx : ρ) => f (x ctx) }
An implementation of Haskell's MonadReader
(sans functional dependency; see also MonadReader
in this module). It does not contain local
because this
function cannot be lifted using monadLift
. local
is instead provided by
the MonadWithReader
class as withReader
.
Note: This class can be seen as a simplification of the more "principled" definition
class MonadReaderOf (ρ : Type u) (n : Type u → Type u) where
lift {α : Type u} : ({m : Type u → Type u} → [Monad m] → ReaderT ρ m α) → n α
- read : m ρ
(← read) : ρ
reads the state out of monadm
.
Instances
Like read
, but with ρ
explicit. This is useful if a monad supports
MonadReaderOf
for multiple different types ρ
.
Instances For
Similar to MonadReaderOf
, but ρ
is an outParam
for convenience.
- read : m ρ
(← read) : ρ
reads the state out of monadm
.
Instances
Equations
- instMonadReader ρ m = { read := readThe ρ }
Equations
- instMonadReaderOfReaderT = { read := ReaderT.read }
MonadWithReaderOf ρ
adds the operation withReader : (ρ → ρ) → m α → m α
.
This runs the inner x : m α
inside a modified context after applying the
function f : ρ → ρ
. In addition to ReaderT
itself, this operation lifts
over most monad transformers, so it allows us to apply withReader
to monads
deeper in the stack.
- withReader : {α : Type u} → (ρ → ρ) → m α → m α
withReader (f : ρ → ρ) (x : m α) : m α
runs the innerx : m α
inside a modified context after applying the functionf : ρ → ρ
.
Instances
Like withReader
, but with ρ
explicit. This is useful if a monad supports
MonadWithReaderOf
for multiple different types ρ
.
Equations
- withTheReader ρ f x = MonadWithReaderOf.withReader f x
Instances For
Similar to MonadWithReaderOf
, but ρ
is an outParam
for convenience.
- withReader : {α : Type u} → (ρ → ρ) → m α → m α
withReader (f : ρ → ρ) (x : m α) : m α
runs the innerx : m α
inside a modified context after applying the functionf : ρ → ρ
.
Instances
Equations
- instMonadWithReader ρ m = { withReader := fun {α : Type u} => withTheReader ρ }
Equations
- instMonadWithReaderOf = { withReader := fun {α : Type u} (f : ρ → ρ) => monadMap fun {β : Type u} => withTheReader ρ f }
An implementation of MonadState
. In contrast to the Haskell implementation,
we use overlapping instances to derive instances automatically from monadLift
.
- get : m σ
(← get) : σ
gets the state out of a monadm
. - set : σ → m PUnit
set (s : σ)
replaces the state with values
. modifyGet (f : σ → α × σ)
appliesf
to the current state, replaces the state with the return value, and returns a computed value.It is equivalent to
do let (a, s) := f (← get); put s; pure a
, butmodifyGet f
may be preferable because the former does not use the state linearly (without sufficient inlining).
Instances
Like withReader
, but with ρ
explicit. This is useful if a monad supports
MonadWithReaderOf
for multiple different types ρ
.
Instances For
Like modify
, but with σ
explicit. This is useful if a monad supports
MonadStateOf
for multiple different types σ
.
Equations
- modifyThe σ f = MonadStateOf.modifyGet fun (s : σ) => (PUnit.unit, f s)
Instances For
Like modifyGet
, but with σ
explicit. This is useful if a monad supports
MonadStateOf
for multiple different types σ
.
Equations
Instances For
Similar to MonadStateOf
, but σ
is an outParam
for convenience.
- get : m σ
(← get) : σ
gets the state out of a monadm
. - set : σ → m PUnit
set (s : σ)
replaces the state with values
. modifyGet (f : σ → α × σ)
appliesf
to the current state, replaces the state with the return value, and returns a computed value.It is equivalent to
do let (a, s) := f (← get); put s; pure a
, butmodifyGet f
may be preferable because the former does not use the state linearly (without sufficient inlining).
Instances
Equations
- instMonadState σ m = { get := getThe σ, set := set, modifyGet := fun {α : Type u} (f : σ → α × σ) => MonadStateOf.modifyGet f }
Result ε σ α
is equivalent to Except ε α × σ
, but using a single
combined inductive yields a more efficient data representation.
- ok: {ε σ α : Type u} → α → σ → EStateM.Result ε σ α
A success value of type
α
, and a new stateσ
. - error: {ε σ α : Type u} → ε → σ → EStateM.Result ε σ α
A failure value of type
ε
, and a new stateσ
.
Instances For
Equations
- EStateM.instInhabitedResult = { default := EStateM.Result.error default default }
Equations
- EStateM.instInhabitedEStateM = { default := fun (s : σ) => EStateM.Result.error default s }
The pure
operation of the EStateM
monad.
Equations
- EStateM.pure a s = EStateM.Result.ok a s
Instances For
The get
operation of the EStateM
monad.
Equations
- EStateM.get s = EStateM.Result.ok s s
Instances For
The modifyGet
operation of the EStateM
monad.
Equations
- EStateM.modifyGet f s = match f s with | (a, s) => EStateM.Result.ok a s
Instances For
The throw
operation of the EStateM
monad.
Equations
- EStateM.throw e s = EStateM.Result.error e s
Instances For
Auxiliary instance for saving/restoring the "backtrackable" part of the state.
Here σ
is the state, and δ
is some subpart of it, and we have a
getter and setter for it (a "lens" in the Haskell terminology).
- save : σ → δ
save s : δ
retrieves a copy of the backtracking state out of the state. - restore : σ → δ → σ
restore (s : σ) (x : δ) : σ
applies the old backtracking statex
to the states
to get a backtracked states'
.
Instances
Implementation of tryCatch
for EStateM
where the state is Backtrackable
.
Equations
- EStateM.tryCatch x handle s = let d := EStateM.Backtrackable.save s; match x s with | EStateM.Result.error e s => handle e (EStateM.Backtrackable.restore s d) | ok => ok
Instances For
Implementation of orElse
for EStateM
where the state is Backtrackable
.
Equations
- EStateM.orElse x₁ x₂ s = let d := EStateM.Backtrackable.save s; match x₁ s with | EStateM.Result.error a s => x₂ () (EStateM.Backtrackable.restore s d) | ok => ok
Instances For
Map the exception type of a EStateM ε σ α
by a function f : ε → ε'
.
Equations
- EStateM.adaptExcept f x s = match x s with | EStateM.Result.error e s => EStateM.Result.error (f e) s | EStateM.Result.ok a s => EStateM.Result.ok a s
Instances For
The bind
operation of the EStateM
monad.
Equations
- EStateM.bind x f s = match x s with | EStateM.Result.ok a s => f a s | EStateM.Result.error e s => EStateM.Result.error e s
Instances For
The map
operation of the EStateM
monad.
Equations
- EStateM.map f x s = match x s with | EStateM.Result.ok a s => EStateM.Result.ok (f a) s | EStateM.Result.error e s => EStateM.Result.error e s
Instances For
The seqRight
operation of the EStateM
monad.
Equations
- EStateM.seqRight x y s = match x s with | EStateM.Result.ok a s => y () s | EStateM.Result.error e s => EStateM.Result.error e s
Instances For
Equations
- EStateM.instOrElseEStateM = { orElse := EStateM.orElse }
Execute an EStateM
on initial state s
to get a Result
.
Equations
- EStateM.run x s = x s
Instances For
Execute an EStateM
on initial state s
for the returned value α
.
If the monadic action throws an exception, returns none
instead.
Equations
- EStateM.run' x s = match EStateM.run x s with | EStateM.Result.ok v a => some v | EStateM.Result.error a a_1 => none
Instances For
The restore
implementation for Backtrackable PUnit σ
.
Equations
- EStateM.dummyRestore s x = s
Instances For
Dummy default instance. This makes every σ
trivially "backtrackable"
by doing nothing on backtrack. Because this is the first declared instance
of Backtrackable _ σ
, it will be picked only if there are no other
Backtrackable _ σ
instances registered.
Equations
- EStateM.nonBacktrackable = { save := EStateM.dummySave, restore := EStateM.dummyRestore }
Converts a UInt64
to a USize
by reducing modulo USize.size
.
Upcast a USize
to a UInt64
.
This is lossless because USize.size
is either 2^32
or 2^64
.
This function is overridden with a native implementation.
Equations
- USize.toUInt64 u = { val := { val := ↑u.val, isLt := ⋯ } }
Instances For
An opaque string hash function.
Equations
- instHashableString = { hash := String.hash }
A hash function for names, which is stored inside the name itself as a computed field.
Equations
- Lean.Name.hash Lean.Name.anonymous = UInt64.ofNatCore 1723 Lean.Name.hash.proof_3
- Lean.Name.hash (Lean.Name.str p s) = mixHash (Lean.Name.hash p) (String.hash s)
- Lean.Name.hash (Lean.Name.num p v) = mixHash (Lean.Name.hash p) (if h : v < UInt64.size then UInt64.ofNatCore v h else UInt64.ofNatCore 17 Lean.Name.hash.proof_4)
Instances For
Hierarchical names. We use hierarchical names to name declarations and for creating unique identifiers for free variables and metavariables.
You can create hierarchical names using the following quotation notation.
`Lean.Meta.whnf
It is short for .str (.str (.str .anonymous "Lean") "Meta") "whnf"
You can use double quotes to request Lean to statically check whether the name
corresponds to a Lean declaration in scope.
``Lean.Meta.whnf
If the name is not in scope, Lean will report an error.
- anonymous: Lake.Name
The "anonymous" name.
- str: Lake.Name → String → Lake.Name
- num: Lake.Name → Nat → Lake.Name
Instances For
Equations
- Lean.instInhabitedName = { default := Lean.Name.anonymous }
Equations
- Lean.instHashableName = { hash := Lean.Name.hash }
.str p s
is now the preferred form.
Equations
- Lean.Name.mkStr p s = Lean.Name.str p s
Instances For
.num p v
is now the preferred form.
Equations
- Lean.Name.mkNum p v = Lean.Name.num p v
Instances For
Equations
Instances For
Make name s₁
Equations
Instances For
Make name s₁.s₂
Equations
- Lean.Name.mkStr2 s₁ s₂ = Lean.Name.str (Lean.Name.str Lean.Name.anonymous s₁) s₂
Instances For
Make name s₁.s₂.s₃
Equations
- Lean.Name.mkStr3 s₁ s₂ s₃ = Lean.Name.str (Lean.Name.str (Lean.Name.str Lean.Name.anonymous s₁) s₂) s₃
Instances For
Make name s₁.s₂.s₃.s₄
Equations
- Lean.Name.mkStr4 s₁ s₂ s₃ s₄ = Lean.Name.str (Lean.Name.str (Lean.Name.str (Lean.Name.str Lean.Name.anonymous s₁) s₂) s₃) s₄
Instances For
Make name s₁.s₂.s₃.s₄.s₅
Equations
- Lean.Name.mkStr5 s₁ s₂ s₃ s₄ s₅ = Lean.Name.str (Lean.Name.str (Lean.Name.str (Lean.Name.str (Lean.Name.str Lean.Name.anonymous s₁) s₂) s₃) s₄) s₅
Instances For
Make name s₁.s₂.s₃.s₄.s₅.s₆
Equations
- Lean.Name.mkStr6 s₁ s₂ s₃ s₄ s₅ s₆ = Lean.Name.str (Lean.Name.str (Lean.Name.str (Lean.Name.str (Lean.Name.str (Lean.Name.str Lean.Name.anonymous s₁) s₂) s₃) s₄) s₅) s₆
Instances For
(Boolean) equality comparator for names.
Equations
- Lean.Name.beq Lean.Name.anonymous Lean.Name.anonymous = true
- Lean.Name.beq (Lean.Name.str p₁ s₁) (Lean.Name.str p₂ s₂) = (s₁ == s₂ && Lean.Name.beq p₁ p₂)
- Lean.Name.beq (Lean.Name.num p₁ n₁) (Lean.Name.num p₂ n₂) = (n₁ == n₂ && Lean.Name.beq p₁ p₂)
- Lean.Name.beq x✝ x = false
Instances For
Equations
- Lean.Name.instBEqName = { beq := Lean.Name.beq }
This function does not have special support for macro scopes.
See Name.append
.
Equations
- Lean.Name.appendCore x Lean.Name.anonymous = x
- Lean.Name.appendCore x (Lean.Name.str p s) = Lean.Name.str (Lean.Name.appendCore x p) s
- Lean.Name.appendCore x (Lean.Name.num p d) = Lean.Name.num (Lean.Name.appendCore x p) d
Instances For
Syntax #
Source information of tokens.
- original: Substring → String.Pos → Substring → String.Pos → Lean.SourceInfo
Token from original input with whitespace and position information.
leading
will be inferred after parsing bySyntax.updateLeading
. During parsing, it is not at all clear what the preceding token was, especially with backtracking. - synthetic: String.Pos → String.Pos → optParam Bool false → Lean.SourceInfo
Synthesized syntax (e.g. from a quotation) annotated with a span from the original source. In the delaborator, we "misuse" this constructor to store synthetic positions identifying subterms.
The
canonical
flag on synthetic syntax is enabled for syntax that is not literally part of the original input syntax but should be treated "as if" the user really wrote it for the purpose of hovers and error messages. This is usually used on identifiers, to connect the binding site to the user's original syntax even if the name of the identifier changes during expansion, as well as on tokens where we will attach targeted messages.The syntax
token%$stx
in a syntax quotation will annotate the tokentoken
with the span fromstx
and also mark it as canonical.As a rough guide, a macro expansion should only use a given piece of input syntax in a single canonical token, although this is sometimes violated when the same identifier is used to declare two binders, as in the macro expansion for dependent if:
`(if $h : $cond then $t else $e) ~> `(dite $cond (fun $h => $t) (fun $h => $t))
In these cases if the user hovers over
h
they will see information about both binding sites. - none: Lean.SourceInfo
Synthesized token without position information.
Instances For
Equations
- Lean.instInhabitedSourceInfo = { default := Lean.SourceInfo.none }
Gets the position information from a SourceInfo
, if available.
If originalOnly
is true, then .synthetic
syntax will also return none
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
A SyntaxNodeKind
classifies Syntax.node
values. It is an abbreviation for
Name
, and you can use name literals to construct SyntaxNodeKind
s, but
they need not refer to declarations in the environment. Conventionally, a
SyntaxNodeKind
will correspond to the Parser
or ParserDesc
declaration
that parses it.
Equations
Instances For
Syntax AST #
Binding information resolved and stored at compile time of a syntax quotation.
Note: We do not statically know whether a syntax expects a namespace or term name,
so a Syntax.ident
may contain both preresolution kinds.
- namespace: Lake.Name → Lean.Syntax.Preresolved
A potential namespace reference
- decl: Lake.Name → List String → Lean.Syntax.Preresolved
A potential global constant or section variable reference, with additional field accesses
Instances For
Syntax objects used by the parser, macro expander, delaborator, etc.
- missing: Lean.Syntax
- node: Lean.SourceInfo → Lean.SyntaxNodeKind → Array Lean.Syntax → Lean.Syntax
Node in the syntax tree.
The
info
field is used by the delaborator to store the position of the subexpression corresponding to this node. The parser sets theinfo
field tonone
. The parser sets theinfo
field tonone
, with position retrieval continuing recursively. Nodes created by quotations use the result fromSourceInfo.fromRef
so that they are marked as synthetic even when the leading/trailing token is not. The delaborator uses theinfo
field to store the position of the subexpression corresponding to this node.(Remark: the
node
constructor did not have aninfo
field in previous versions. This caused a bug in the interactive widgets, where the popup fora + b
was the same as fora
. The delaborator used to associate subexpressions with pretty-printed syntax by setting the (string) position of the first atom/identifier to the (expression) position of the subexpression. For example, botha
anda + b
have the same first identifier, and so their infos got mixed up.) - atom: Lean.SourceInfo → String → Lean.Syntax
- ident: Lean.SourceInfo → Substring → Lake.Name → List Lean.Syntax.Preresolved → Lean.Syntax
Instances For
Create syntax node with 1 child
Equations
- Lean.Syntax.node1 info kind a₁ = Lean.Syntax.node info kind #[a₁]
Instances For
Create syntax node with 2 children
Equations
- Lean.Syntax.node2 info kind a₁ a₂ = Lean.Syntax.node info kind #[a₁, a₂]
Instances For
Create syntax node with 3 children
Equations
- Lean.Syntax.node3 info kind a₁ a₂ a₃ = Lean.Syntax.node info kind #[a₁, a₂, a₃]
Instances For
Create syntax node with 4 children
Equations
- Lean.Syntax.node4 info kind a₁ a₂ a₃ a₄ = Lean.Syntax.node info kind #[a₁, a₂, a₃, a₄]
Instances For
Create syntax node with 5 children
Equations
- Lean.Syntax.node5 info kind a₁ a₂ a₃ a₄ a₅ = Lean.Syntax.node info kind #[a₁, a₂, a₃, a₄, a₅]
Instances For
Create syntax node with 6 children
Equations
- Lean.Syntax.node6 info kind a₁ a₂ a₃ a₄ a₅ a₆ = Lean.Syntax.node info kind #[a₁, a₂, a₃, a₄, a₅, a₆]
Instances For
Create syntax node with 7 children
Equations
- Lean.Syntax.node7 info kind a₁ a₂ a₃ a₄ a₅ a₆ a₇ = Lean.Syntax.node info kind #[a₁, a₂, a₃, a₄, a₅, a₆, a₇]
Instances For
Create syntax node with 8 children
Equations
- Lean.Syntax.node8 info kind a₁ a₂ a₃ a₄ a₅ a₆ a₇ a₈ = Lean.Syntax.node info kind #[a₁, a₂, a₃, a₄, a₅, a₆, a₇, a₈]
Instances For
A Syntax
value of one of the given syntax kinds.
Note that while syntax quotations produce/expect TSyntax
values of the correct kinds,
this is not otherwise enforced and can easily be circumvented by direct use of the constructor.
The namespace TSyntax.Compat
can be opened to expose a general coercion from Syntax
to any
TSyntax ks
for porting older code.
- raw : Lean.Syntax
The underlying
Syntax
value.
Instances For
Equations
- Lean.instInhabitedSyntax = { default := Lean.Syntax.missing }
Equations
- Lean.instInhabitedTSyntax = { default := { raw := default } }
Builtin kinds #
The choice
kind is used when a piece of syntax has multiple parses, and the
determination of which to use is deferred until typing information is available.
Equations
- Lean.choiceKind = `choice
Instances For
The null kind is used for raw list parsers like many
.
Equations
- Lean.nullKind = `null
Instances For
The group
kind is by the group
parser, to avoid confusing with the null
kind when used inside optional
.
Equations
- Lean.groupKind = `group
Instances For
str
is the node kind of string literals like "foo"
.
Equations
- Lean.strLitKind = `str
Instances For
char
is the node kind of character literals like 'A'
.
Equations
- Lean.charLitKind = `char
Instances For
num
is the node kind of number literals like 42
.
Equations
- Lean.numLitKind = `num
Instances For
scientific
is the node kind of floating point literals like 1.23e-3
.
Equations
- Lean.scientificLitKind = `scientific
Instances For
name
is the node kind of name literals like `foo
.
Equations
- Lean.nameLitKind = `name
Instances For
fieldIdx
is the node kind of projection indices like the 2
in x.2
.
Equations
- Lean.fieldIdxKind = `fieldIdx
Instances For
hygieneInfo
is the node kind of the hygieneInfo
parser, which is an
"invisible token" which captures the hygiene information at the current point
without parsing anything.
They can be used to generate identifiers (with Lean.HygieneInfo.mkIdent
)
as if they were introduced by the calling context, not the called macro.
Equations
- Lean.hygieneInfoKind = `hygieneInfo
Instances For
interpolatedStrLitKind
is the node kind of interpolated string literal
fragments like "value = {
and }"
in s!"value = {x}"
.
Equations
- Lean.interpolatedStrLitKind = `interpolatedStrLitKind
Instances For
interpolatedStrKind
is the node kind of an interpolated string literal
like "value = {x}"
in s!"value = {x}"
.
Equations
- Lean.interpolatedStrKind = `interpolatedStrKind
Instances For
Creates an info-less node of the given kind and children.
Equations
- Lean.mkNode k args = { raw := Lean.Syntax.node Lean.SourceInfo.none k args }
Instances For
Creates an info-less nullKind
node with the given children, if any.
Equations
- Lean.mkNullNode args = (Lean.mkNode Lean.nullKind args).raw
Instances For
Changes the kind at the root of a Syntax
node to k
.
Does nothing for non-node
nodes.
Equations
- Lean.Syntax.setKind stx k = match stx with | Lean.Syntax.node info kind args => Lean.Syntax.node info k args | x => stx
Instances For
Is this a syntax with node kind k
?
Equations
- Lean.Syntax.isOfKind stx k = (Lean.Syntax.getKind stx == k)
Instances For
Gets the i
'th argument of the syntax node. This can also be written stx[i]
.
Returns missing
if i
is out of range.
Equations
- Lean.Syntax.getArg stx i = match stx with | Lean.Syntax.node info kind args => Array.getD args i Lean.Syntax.missing | x => Lean.Syntax.missing
Instances For
Equations
- Lean.Syntax.instGetElemSyntaxNatTrue = { getElem := fun (stx : Lean.Syntax) (i : Nat) (x : True) => Lean.Syntax.getArg stx i }
Gets the list of arguments of the syntax node, or #[]
if it's not a node
.
Equations
- Lean.Syntax.getArgs stx = match stx with | Lean.Syntax.node info kind args => args | x => #[]
Instances For
Gets the number of arguments of the syntax node, or 0
if it's not a node
.
Equations
- Lean.Syntax.getNumArgs stx = match stx with | Lean.Syntax.node info kind args => Array.size args | x => 0
Instances For
Is this syntax .missing
?
Equations
- Lean.Syntax.isMissing x = match x with | Lean.Syntax.missing => true | x => false
Instances For
Is this syntax a node
with kind k
?
Equations
- Lean.Syntax.isNodeOf stx k n = (Lean.Syntax.isOfKind stx k && Lean.Syntax.getNumArgs stx == n)
Instances For
stx.isIdent
is true
iff stx
is an identifier.
Equations
- Lean.Syntax.isIdent x = match x with | Lean.Syntax.ident info rawVal val preresolved => true | x => false
Instances For
If this is an ident
, return the parsed value, else .anonymous
.
Equations
- Lean.Syntax.getId x = match x with | Lean.Syntax.ident info rawVal val preresolved => val | x => Lean.Name.anonymous
Instances For
Updates the argument list without changing the node kind.
Does nothing for non-node
nodes.
Equations
- Lean.Syntax.setArgs stx args = match stx with | Lean.Syntax.node info k args_1 => Lean.Syntax.node info k args | stx => stx
Instances For
Updates the i
'th argument of the syntax.
Does nothing for non-node
nodes, or if i
is out of bounds of the node list.
Equations
- Lean.Syntax.setArg stx i arg = match stx with | Lean.Syntax.node info k args => Lean.Syntax.node info k (Array.setD args i arg) | stx => stx
Instances For
Retrieve the left-most node or leaf's info in the Syntax tree.
Retrieve the left-most leaf's info in the Syntax tree, or none
if there is no token.
Equations
- Lean.Syntax.getHeadInfo stx = match Lean.Syntax.getHeadInfo? stx with | some info => info | none => Lean.SourceInfo.none
Instances For
Get the starting position of the syntax, if possible.
If canonicalOnly
is true, non-canonical synthetic
nodes are treated as not carrying
position information.
Equations
- Lean.Syntax.getPos? stx canonicalOnly = Lean.SourceInfo.getPos? (Lean.Syntax.getHeadInfo stx) canonicalOnly
Instances For
Get the ending position of the syntax, if possible.
If canonicalOnly
is true, non-canonical synthetic
nodes are treated as not carrying
position information.
An array of syntax elements interspersed with separators. Can be coerced
to/from Array Syntax
to automatically remove/insert the separators.
- elemsAndSeps : Array Lean.Syntax
The array of elements and separators, ordered like
#[el1, sep1, el2, sep2, el3]
.
Instances For
A typed version of SepArray
.
- elemsAndSeps : Array Lean.Syntax
The array of elements and separators, ordered like
#[el1, sep1, el2, sep2, el3]
.
Instances For
An array of syntaxes of kind ks
.
Equations
- Lean.TSyntaxArray ks = Array (Lean.TSyntax ks)
Instances For
Implementation of TSyntaxArray.raw
.
Equations
- Lean.TSyntaxArray.rawImpl = unsafeCast
Instances For
Converts a TSyntaxArray
to an Array Syntax
, without reallocation.
Implementation of TSyntaxArray.mk
.
Equations
- Lean.TSyntaxArray.mkImpl = unsafeCast
Instances For
Converts an Array Syntax
to a TSyntaxArray
, without reallocation.
Constructs a synthetic SourceInfo
using a ref : Syntax
for the span.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Constructs a synthetic atom
with source info coming from src
.
Equations
- Lean.mkAtomFrom src val canonical = Lean.Syntax.atom (Lean.SourceInfo.fromRef src canonical) val
Instances For
Parser descriptions #
A ParserDescr
is a grammar for parsers. This is used by the syntax
command
to produce parsers without having to import Lean
.
- const: Lake.Name → Lean.ParserDescr
A (named) nullary parser, like
ppSpace
- unary: Lake.Name → Lean.ParserDescr → Lean.ParserDescr
A (named) unary parser, like
group(p)
- binary: Lake.Name → Lean.ParserDescr → Lean.ParserDescr → Lean.ParserDescr
A (named) binary parser, like
orelse
orandthen
(written asp1 <|> p2
andp1 p2
respectively insyntax
) - node: Lean.SyntaxNodeKind → Nat → Lean.ParserDescr → Lean.ParserDescr
Parses using
p
, then pops the stack to create a new node with kindkind
. The precedenceprec
is used to determine whether the parser should apply given the current precedence level. - trailingNode: Lean.SyntaxNodeKind → Nat → Nat → Lean.ParserDescr → Lean.ParserDescr
Like
node
but for trailing parsers (which start with a nonterminal). Assumes the lhs is already on the stack, and parses usingp
, then pops the stack including the lhs to create a new node with kindkind
. The precedenceprec
andlhsPrec
are used to determine whether the parser should apply. - symbol: String → Lean.ParserDescr
- nonReservedSymbol: String → Bool → Lean.ParserDescr
- cat: Lake.Name → Nat → Lean.ParserDescr
Parses using the category parser
catName
with right binding power (i.e. precedence)rbp
. - parser: Lake.Name → Lean.ParserDescr
Parses using another parser
declName
, which can be either aParser
orParserDescr
. - nodeWithAntiquot: String → Lean.SyntaxNodeKind → Lean.ParserDescr → Lean.ParserDescr
- sepBy: Lean.ParserDescr → String → Lean.ParserDescr → optParam Bool false → Lean.ParserDescr
A
sepBy(p, sep)
parses 0 or more occurrences ofp
separated bysep
.psep
is usually the same assymbol sep
, but it can be overridden.sep
is only used in the antiquot syntax:$x;*
would match ifsep
is";"
.allowTrailingSep
is true if e.g.a, b,
is also allowed to match. - sepBy1: Lean.ParserDescr → String → Lean.ParserDescr → optParam Bool false → Lean.ParserDescr
Instances For
Equations
- Lean.instInhabitedParserDescr = { default := Lean.ParserDescr.symbol "" }
Although TrailingParserDescr
is an abbreviation for ParserDescr
, Lean will
look at the declared type in order to determine whether to add the parser to
the leading or trailing parser table. The determination is done automatically
by the syntax
command.
Equations
Instances For
Runtime support for making quotation terms auto-hygienic, by mangling identifiers introduced by them with a "macro scope" supplied by the context. Details to appear in a paper soon.
A macro scope identifier is just a Nat
that gets bumped every time we
enter a new macro scope. Within a macro scope, all occurrences of identifier x
parse to the same thing, but x
parsed from different macro scopes will
produce different identifiers.
Equations
Instances For
Macro scope used internally. It is not available for our frontend.
Equations
Instances For
First macro scope available for our frontend
Equations
Instances For
A MonadRef
is a monad that has a ref : Syntax
in the read-only state.
This is used to keep track of the location where we are working; if an exception
is thrown, the ref
gives the location where the error will be reported,
assuming no more specific location is provided.
- getRef : m Lean.Syntax
Get the current value of the
ref
- withRef : {α : Type} → Lean.Syntax → m α → m α
Run
x : m α
with a modified value for theref
Instances
Equations
- Lean.instMonadRef m n = { getRef := liftM Lean.getRef, withRef := fun {α : Type} (ref : Lean.Syntax) (x : n α) => monadMap (fun {β : Type} => Lean.MonadRef.withRef ref) x }
Replaces oldRef
with ref
, unless ref
has no position info.
This biases us to having a valid span to report an error on.
Equations
- Lean.replaceRef ref oldRef = match Lean.Syntax.getPos? ref with | some val => ref | x => oldRef
Instances For
Run x : m α
with a modified value for the ref
. This is not exactly
the same as MonadRef.withRef
, because it uses replaceRef
to avoid putting
syntax with bad spans in the state.
Equations
- Lean.withRef ref x = do let oldRef ← Lean.getRef let ref : Lean.Syntax := Lean.replaceRef ref oldRef Lean.MonadRef.withRef ref x
Instances For
A monad that supports syntax quotations. Syntax quotations (in term
position) are monadic values that when executed retrieve the current "macro
scope" from the monad and apply it to every identifier they introduce
(independent of whether this identifier turns out to be a reference to an
existing declaration, or an actually fresh binding during further
elaboration). We also apply the position of the result of getRef
to each
introduced symbol, which results in better error positions than not applying
any position.
- getRef : m Lean.Syntax
- withRef : {α : Type} → Lean.Syntax → m α → m α
- getCurrMacroScope : m Lean.MacroScope
Get the fresh scope of the current macro invocation
- getMainModule : m Lake.Name
Get the module name of the current file. This is used to ensure that hygienic names don't clash across multiple files.
- withFreshMacroScope : {α : Type} → m α → m α
Execute action in a new macro invocation context. This transformer should be used at all places that morally qualify as the beginning of a "macro call", e.g.
elabCommand
andelabTerm
in the case of the elaborator. However, it can also be used internally inside a "macro" if identifiers introduced by e.g. different recursive calls should be independent and not collide. While returning an intermediate syntax tree that will recursively be expanded by the elaborator can be used for the same effect, doing direct recursion inside the macro guarded by this transformer is often easier because one is not restricted to passing a single syntax tree. Modelling this helper as a transformer and not just a monadic action ensures that the current macro scope before the recursive call is restored after it, as expected.
Instances
Construct a synthetic SourceInfo
from the ref
in the monad state.
Equations
- Lean.MonadRef.mkInfoFromRefPos = do let __do_lift ← Lean.getRef pure (Lean.SourceInfo.fromRef __do_lift)
Instances For
We represent a name with macro scopes as
<actual name>._@.(<module_name>.<scopes>)*.<module_name>._hyg.<scopes>
Example: suppose the module name is Init.Data.List.Basic
, and name is foo.bla
, and macroscopes [2, 5]
foo.bla._@.Init.Data.List.Basic._hyg.2.5
We may have to combine scopes from different files/modules. The main modules being processed is always the right-most one. This situation may happen when we execute a macro generated in an imported file in the current file.
foo.bla._@.Init.Data.List.Basic.2.1.Init.Lean.Expr._hyg.4
The delimiter _hyg
is used just to improve the hasMacroScopes
performance.
Does this name have hygienic macro scopes?
Equations
- Lean.Name.hasMacroScopes (Lean.Name.str pre s) = (s == "_hyg")
- Lean.Name.hasMacroScopes (Lean.Name.num p i) = Lean.Name.hasMacroScopes p
- Lean.Name.hasMacroScopes x = false
Instances For
Remove the macro scopes from the name.
Equations
- Lean.Name.eraseMacroScopes n = match Lean.Name.hasMacroScopes n with | true => Lean.eraseMacroScopesAux n | false => n
Instances For
Helper function we use to create binder names that do not need to be unique.
Equations
- Lean.Name.simpMacroScopes n = match Lean.Name.hasMacroScopes n with | true => Lean.simpMacroScopesAux n | false => n
Instances For
A MacroScopesView
represents a parsed hygienic name. extractMacroScopes
will decode it from a Name
, and .review
will re-encode it. The grammar of a
hygienic name is:
<name>._@.(<module_name>.<scopes>)*.<mainModule>._hyg.<scopes>
- name : Lake.Name
The original (unhygienic) name.
- imported : Lake.Name
All the name components
(<module_name>.<scopes>)*
from the imports concatenated together. - mainModule : Lake.Name
The main module in which this identifier was parsed.
- scopes : List Lean.MacroScope
The list of macro scopes.
Instances For
Equations
- Lean.instInhabitedMacroScopesView = { default := { name := default, imported := default, mainModule := default, scopes := default } }
Encode a hygienic name from the parsed pieces.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Revert all addMacroScope
calls. v = extractMacroScopes n → n = v.review
.
This operation is useful for analyzing/transforming the original identifiers, then adding back
the scopes (via MacroScopesView.review
).
Equations
- One or more equations did not get rendered due to their size.
Instances For
Add a new macro scope onto the name n
, in the given mainModule
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Append two names that may have macro scopes. The macro scopes in b
are always erased.
If a
has macro scopes, then they are propagated to the result of append a b
.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- Lean.instAppendName = { append := Lean.Name.append }
Add a new macro scope onto the name n
, using the monad state to supply the
main module and current macro scope.
Equations
- Lean.MonadQuotation.addMacroScope n = do let mainModule ← Lean.getMainModule let scp ← Lean.getCurrMacroScope pure (Lean.addMacroScope mainModule n scp)
Instances For
The default maximum recursion depth. This is adjustable using the maxRecDepth
option.
Equations
Instances For
The message to display on stack overflow.
Equations
- Lean.maxRecDepthErrorMessage = "maximum recursion depth has been reached (use `set_option maxRecDepth <num>` to increase limit)"
Instances For
Is this syntax a null node
?
Equations
- Lean.Syntax.matchesNull stx n = Lean.Syntax.isNodeOf stx Lean.nullKind n
Instances For
Function used for determining whether a syntax pattern `(id)
is matched.
There are various conceivable notions of when two syntactic identifiers should be regarded as identical,
but semantic definitions like whether they refer to the same global name cannot be implemented without
context information (i.e. MonadResolveName
). Thus in patterns we default to the structural solution
of comparing the identifiers' Name
values, though we at least do so modulo macro scopes so that
identifiers that "look" the same match. This is particularly useful when dealing with identifiers that
do not actually refer to Lean bindings, e.g. in the stx
pattern `(many($p))
.
Equations
Instances For
The read-only context for the MacroM
monad.
- methods : Lean.Macro.MethodsRef
- mainModule : Lake.Name
The currently parsing module.
- currMacroScope : Lean.MacroScope
The current macro scope.
- currRecDepth : Nat
The current recursion depth.
- maxRecDepth : Nat
The maximum recursion depth.
- ref : Lean.Syntax
The syntax which supplies the position of error messages.
Instances For
An exception in the MacroM
monad.
- error: Lean.Syntax → String → Lean.Macro.Exception
A general error, given a message and a span (expressed as a
Syntax
). - unsupportedSyntax: Lean.Macro.Exception
An unsupported syntax exception. We keep this separate because it is used for control flow: if one macro does not support a syntax then we try the next one.
Instances For
The mutable state for the MacroM
monad.
- macroScope : Lean.MacroScope
The global macro scope counter, used for producing fresh scope names.
The list of trace messages that have been produced, each with a trace class and a message.
Instances For
Equations
- Lean.Macro.instInhabitedState = { default := { macroScope := default, traceMsgs := default } }
The MacroM
monad is the main monad for macro expansion. It has the
information needed to handle hygienic name generation, and is the monad that
macro
definitions live in.
Notably, this is a (relatively) pure monad: there is no IO
and no access to
the Environment
. That means that things like declaration lookup are
impossible here, as well as IO.Ref
or other side-effecting operations.
For more capabilities, macros can instead be written as elab
using adaptExpander
.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Add a new macro scope to the name n
.
Equations
- Lean.Macro.addMacroScope n = do let ctx ← read pure (Lean.addMacroScope ctx.mainModule n ctx.currMacroScope)
Instances For
Throw an unsupportedSyntax
exception.
Equations
- Lean.Macro.throwUnsupported = throw Lean.Macro.Exception.unsupportedSyntax
Instances For
Throw an error with the given message,
using the ref
for the location information.
Equations
- Lean.Macro.throwError msg = do let ref ← Lean.getRef throw (Lean.Macro.Exception.error ref msg)
Instances For
Throw an error with the given message and location information.
Equations
- Lean.Macro.throwErrorAt ref msg = Lean.withRef ref (Lean.Macro.throwError msg)
Instances For
Increments the macro scope counter so that inside the body of x
the macro
scope is fresh.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Run x
with an incremented recursion depth counter.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
- One or more equations did not get rendered due to their size.
The opaque methods that are available to MacroM
.
- expandMacro? : Lean.Syntax → Lean.MacroM (Option Lean.Syntax)
Expands macros in the given syntax. A return value of
none
means there was nothing to expand. - getCurrNamespace : Lean.MacroM Lake.Name
Get the current namespace in the file.
- hasDecl : Lake.Name → Lean.MacroM Bool
Check if a given name refers to a declaration.
- resolveNamespace : Lake.Name → Lean.MacroM (List Lake.Name)
Resolves the given name to an overload list of namespaces.
Instances For
Equations
- One or more equations did not get rendered due to their size.
Implementation of mkMethods
.
Equations
- Lean.Macro.mkMethodsImp methods = unsafeCast methods
Instances For
Make an opaque reference to a Methods
.
Equations
- Lean.Macro.instInhabitedMethodsRef = { default := Lean.Macro.mkMethods default }
Implementation of getMethods
.
Equations
- Lean.Macro.getMethodsImp = do let ctx ← read pure (unsafeCast ctx.methods)
Instances For
Extract the methods list from the MacroM
state.
expandMacro? stx
returns some stxNew
if stx
is a macro,
and stxNew
is its expansion.
Equations
- Lean.expandMacro? stx = do let __do_lift ← Lean.Macro.getMethods __do_lift.expandMacro? stx
Instances For
Returns true
if the environment contains a declaration with name declName
Equations
- Lean.Macro.hasDecl declName = do let __do_lift ← Lean.Macro.getMethods __do_lift.hasDecl declName
Instances For
Gets the current namespace given the position in the file.
Equations
- Lean.Macro.getCurrNamespace = do let __do_lift ← Lean.Macro.getMethods __do_lift.getCurrNamespace
Instances For
Resolves the given name to an overload list of namespaces.
Equations
- Lean.Macro.resolveNamespace n = do let __do_lift ← Lean.Macro.getMethods __do_lift.resolveNamespace n
Instances For
Resolves the given name to an overload list of global definitions.
The List String
in each alternative is the deduced list of projections
(which are ambiguous with name components).
Equations
- Lean.Macro.resolveGlobalName n = do let __do_lift ← Lean.Macro.getMethods __do_lift.resolveGlobalName n
Instances For
Add a new trace message, with the given trace class and message.
Equations
- Lean.Macro.trace clsName msg = modify fun (s : Lean.Macro.State) => { macroScope := s.macroScope, traceMsgs := (clsName, msg) :: s.traceMsgs }
Instances For
Function that tries to reverse macro expansions as a post-processing step of delaboration.
While less general than an arbitrary delaborator, it can be declared without importing Lean
.
Used by the [app_unexpander]
attribute.
Instances For
Equations
- Lean.PrettyPrinter.instMonadQuotationUnexpandM = Lean.MonadQuotation.mk (pure 0) (pure `_fakeMod) fun {α : Type} => id