Intro Lean (archived)
Posted on August 2, 2019
Tags: lean
1 Notation
1.1 Type Parameters vs Arguments
def bleh (PARAMETER1 : Type) (PARAMETER2 : Type) : ARGUMENT1 -> ARGUMENT2 := ...
- PARAMETER: Before the main semicolon
- ARGUMENT: After the main semicolon
- Example
def Bigger (x : Nat) (y : Nat): Bool := ...
- Parameter:
(x : Nat) (y : Nat)
- Argument:
Bool
- Parameter:
- PARAMETER and ARGUMENTS do not behave in the same way in Function vs Inductive Type definitons
2 Forall, Pi
- Π and ∀ are interchangable.
: Πa : Type u , a -> list a -> list a
constant consA : ∀a : Type u , a -> list a -> list a
constant consB : ∀(a : Type u), a -> list a -> list a
constant consC : Π(a : Type u) , a -> list a -> list a
constant consD : Type u) : a -> list a -> list a constant consE (a
A B} (f: A -> B) :=
def injective {: A, f x = f y -> x = y
Π x y A B} (f: A -> B) :=
def injective {: A, f x = f y -> x = y
∀ x y A B} (f: A -> B) :=
def injective {: A, f x = f y -> x = y λ x y
3 Inductive type
- An inductive type aka inductive datatype aka algebraic datatype is a type that consists all the values that can be built using a finite number of applications of its constructors and only those.
Inductive
keyword bundles together Type formation and Term introduction
: Type --type formation
inductive nat | zero : nat --term introduction
| succ : nat → nat --term introduction
: Type --type formation
constant nat .zero : nat --term introduction
constant nat.succ : nat → nat --term introduction constant nat
3.1 Inductive Type parameters
- By adding parameters, we can have Inductive dependent types meaning the constructors are dependent typed functions.
- Notice the last Type of the constructor
mk :..-> prod
is the inductive type itselfprod
- Constructors must always refer back to the inductive type
(A B : Type) : Type
inductive prod | mk : A -> B -> prod
#check prod.mk 2 4
> mk 2 4 :: prod nat nat OUTPUT
Inductive prod (A B:Type) : Type :=
| pair (x:A) (y:B) : A -> B -> prod A B.
Check mk nat nat 2 4. --notice how this diff from Lean's mk
3.2 dependently typed constructors
- Instead of having typed parameters like
prod (A B : Type) : Type
we use dependently typed constructors likemk : Π ( A B : Type )...
: Type -> Type -> Type 1
inductive prod | mk : Π (A B : Type), A -> B -> prod A B
#check mk nat nat 2 4
> mk nat nat 2 4 :: prod ℕ ℕ
OUTPUT#check mk
> mk :: Π (A B : Type), A -> B -> prod A B OUTPUT
: Type -> Type -> Type :=
Inductive prod | mk : forall A B :Type , A -> B -> prod A B .
2 4.
Check pair nat nat > pair nat nat 2 4 :: prod nat nat
OUTPUT.
Check mk> mk :: forall A B : Type, A -> B -> prod A B OUTPUT
3.3 Parameter Behavior in functions
- Observe how
(m : ℕ)
as a parameter behaves- argument m of
powerB m
is fixed inside the definition
but outside the definition, like ineval powerB 2 5
, m is not fixed
- argument m of
: ℕ → ℕ → ℕ
def power | _ nat.zero := 1
| m (nat.succ n) := m * power m n
#eval power 2 5
: ℕ) : ℕ → ℕ
def powerB (m | nat.zero := 1
| (nat.succ n) := m * powerB n --notice we can omit argument m here
#eval powerB 2 5
3.4 Structures
Structures are non-recursive inductive data types
In other langs, they are called records
4 Implicit vs Explicit parameters
: Type u } : a -> list a -> list a
constant consImplicit {a : Π {a : Type u}, list a
constant nilImplicit #check consImplicit
OUTPUT> ?M_1 → list ?M_1 → list ?M_1
--using @ fills in the metavar with types
#check @consImplicit
5 Recursion
- If a function uses a recursive call to itself lean must also provide a proof of well-foundedness
- Contrary to Coq which does not require a proof