Built with doc-gen4, running Lean4. Bubbles () indicate interactive fragments: hover for details, tap to reveal contents. Use Ctrl+↑Ctrl+↓to navigate, Ctrl+🖱️to focus. On Mac, use Cmdinstead of Ctrl.
import Mathlib
import PnP2023.Lec_02_01.Foundations
import PnP2023.Lec_01_13.NatRec


/-!
# Inductive Types

We see more precisely what are valid (and not valid) definitions for inductive types. We will also see the weak and strong generalizations: 
_parametric inductive types_ and  _indexed inductive types_.

We have constructed a few examples. We first see some more from Lean core.-/

Bool : Type
Bool: Type
Bool
/-! Simplest ones are enumerations ```lean inductive Bool : Type where | false : Bool | true : Bool ``` -/
Nat : Type
Nat: Type
Nat
/-! In general, the construtors let us construct terms of the inductive type being introduced using terms of that type. ```lean inductive Nat where | zero : Nat | succ (n : Nat) : Nat ``` #check Nat.zero -- ℕ #check Nat.succ -- ℕ → ℕ -/
Nat.zero : ℕ
Nat.zero:
Nat.zero
-- ℕ
Nat.succ (n : ℕ) : ℕ
Nat.succ:
Nat.succ
-- ℕ → ℕ
Unit : Type
Unit: Type
Unit
Empty : Type
Empty: Type
Empty
/-! Two more inductive types: ```lean abbrev Unit : Type := PUnit inductive PUnit : Sort u where | unit : PUnit inductive Empty : Type ``` -/ /-! ## Disallowed types - constructors should have resulting type the inductive type being introduced. -/ -- inductive Silly where -- | what_is_this: ℕ /- unexpected constructor resulting type -- ℕ -/ -- inductive Cantor where -- | mk : (Cantor → Bool) → Cantor -- /-(kernel) arg #1 of 'Cantor.mk' has a non positive occurrence of the datatypes being declared -/ /-! The above is disallowed because with a construction of the above form, we would have an injection (in this case a biection) from the power set on the Cantor set to itself. If we had such an inductive type, we could define ```lean diag (x :Cantor): Bool := match x with | Cantor.mk f => ¬ f x ``` Apply this to `x:= Cantor.mk diag` to get ```lean diag (Cantor.mk diag) = ¬ diag (Cantor.mk diag) ``` -/ /-! A non-trivial __positive__ occurence, which is hence allowed, is in the following binary tree. -/ inductive
NatBinTree: Sort ?u.1
NatBinTree
where |
leaf: NatBinTree
leaf
:
: Type
NatBinTree: Sort ?u.1
NatBinTree
|
node: (BoolNatBinTree) → NatBinTree
node
: (
Bool: Type
Bool
NatBinTree: Sort ?u.1
NatBinTree
) →
NatBinTree: Sort ?u.1
NatBinTree
/-! ## Parametrized inductive types Here we define a family of inductive types. However each member of the family is "separately defined", i.e., all constructors only involve that parameter. -/ universe u inductive
InfiniteTree: Type u → Sort ?u.360
InfiniteTree
(
α: Type u
α
:
Type u: Type (u+1)
Type u
) where |
leaf: {α : Type u} → αInfiniteTree α
leaf
(
label: α
label
:
α: Type u
α
) :
InfiniteTree: Type u → Sort ?u.360
InfiniteTree
α: Type u
α
|
node: {α : Type u} → (InfiniteTree α) → InfiniteTree α
node
: (
: Type
InfiniteTree: Type u → Sort ?u.360
InfiniteTree
α: Type u
α
) →
InfiniteTree: Type u → Sort ?u.360
InfiniteTree
α: Type u
α
inductive
FiniteTree: Type u → Sort ?u.808
FiniteTree
(
α: Type u
α
:
Type u: Type (u+1)
Type u
) where |
leaf: {α : Type u} → αFiniteTree α
leaf
(
label: α
label
:
α: Type u
α
) :
FiniteTree: Type u → Sort ?u.808
FiniteTree
α: Type u
α
|
node: {α : Type u} → List (FiniteTree α)FiniteTree α
node
: (
List: Type ?u.817 → Type ?u.817
List
<|
FiniteTree: Type u → Sort ?u.808
FiniteTree
α: Type u
α
) →
FiniteTree: Type u → Sort ?u.808
FiniteTree
α: Type u
α
-- Does terminate, but Lean does not have enough support yet partial def
FiniteTree.flatten: {α : Type u} → FiniteTree αList α
FiniteTree.flatten
{
α: Type u
α
:
Type u: Type (u+1)
Type u
} :
FiniteTree: Type ?u.1395 → Type ?u.1395
FiniteTree
α: Type u
α
List: Type ?u.1397 → Type ?u.1397
List
α: Type u
α
|
FiniteTree.leaf: {α : Type ?u.1403} → αFiniteTree α
FiniteTree.leaf
label: α
label
=> [
label: α
label
] |
FiniteTree.node: {α : Type ?u.1423} → List (FiniteTree α)FiniteTree α
FiniteTree.node
children: List (FiniteTree α)
children
=>
children: List (FiniteTree α)
children
.
foldl: {α : Type ?u.1438} → {β : Type ?u.1437} → (αβα) → αList βα
foldl
(fun
acc: ?m.1447
acc
child: ?m.1450
child
=>
acc: ?m.1447
acc
++
FiniteTree.flatten: {α : Type u} → FiniteTree αList α
FiniteTree.flatten
child: ?m.1450
child
) (
[]: List ?m.1497
[]
) /-! # Indexed inductive type We define types `Vec α n` for `α : Type u` and `n: ℕ` with terms of `Vec α n` n-tuples in `α`. * `α` will be a parameter. * `n` will be an index. -/ inductive
Vec: Type u → Type (u+1)
Vec
(
α: Type u
α
:
Type u: Type (u+1)
Type u
) :
: Type
Type (u + 1): Type (u+2)
Type (u + 1)
where |
nil: {α : Type u} → Vec α 0
nil
:
Vec: Type u → Type (u+1)
Vec
α: Type u
α
0: ?m.1762
0
|
cons: {α : Type u} → {n : } → αVec α nVec α (n + 1)
cons
: {
n:
n
:
: Type
} → (
head: α
head
:
α: Type u
α
) → (
tail: Vec α n
tail
:
Vec: Type u → Type (u+1)
Vec
α: Type u
α
n:
n
) →
Vec: Type u → Type (u+1)
Vec
α: Type u
α
(
n:
n
+
1: ?m.1786
1
)
example: Vec 0
example
:
Vec: Type ?u.2349 → Type (?u.2349+1)
Vec
: Type
0: ?m.2351
0
:=
Vec.nil: {α : Type ?u.2362} → Vec α 0
Vec.nil
example: Vec 1
example
:
Vec: Type ?u.2371 → Type (?u.2371+1)
Vec
: Type
1: ?m.2373
1
:=
Vec.cons: {α : Type ?u.2384} → {n : } → αVec α nVec α (n + 1)
Vec.cons
3: ?m.2390
3
(
Vec.nil: {α : Type ?u.2395} → Vec α 0
Vec.nil
)
List.{u} (α : Type u) : Type u
List: Type u → Type u
List
def
Vec.to_list: {α : Type u} → {n : } → Vec α nList α
Vec.to_list
{
α: Type u
α
:
Type u: Type (u+1)
Type u
} {
n:
n
:
: Type
} :
Vec: Type ?u.2423 → Type (?u.2423+1)
Vec
α: Type u
α
n:
n
List: Type ?u.2425 → Type ?u.2425
List
α: Type u
α
|
Vec.nil: {α : Type ?u.28110} → Vec α 0
Vec.nil
=>
[]: List ?m.28124
[]
|
Vec.cons: {α : Type ?u.28126} → {n : } → αVec α nVec α (n + 1)
Vec.cons
head: α
head
tail: Vec α n✝
tail
=>
head: α
head
::
tail: Vec α n✝
tail
.
to_list: {α : Type u} → {n : } → Vec α nList α
to_list
/-! ## `List` is a parametrized inductive type ```lean inductive List (α : Type u) where /-- `[]` is the empty list. -/ | nil : List α /-- If `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. -/ | cons (head : α) (tail : List α) : List α ``` -/
Fin (n : ℕ) : Type
Fin: Type
Fin
/-! Sometimes types include conditions ```lean structure Fin (n : Nat) where /-- If `i : Fin n`, then `i.val : ℕ` is the described number. It can also be written as `i.1` or just `i` when the target type is known. -/ val : Nat /-- If `i : Fin n`, then `i.2` is a proof that `i.1 < n`. -/ isLt : LT.lt val n ``` -/
Vector.{u} (α : Type u) (n : ℕ) : Type u
Vector: Type u → Type u
Vector
/-! Conditions can be given by a *subtype* of the type. ```lean def Vector (α : Type u) (n : ℕ) := { l : List α // l.length = n } ``` -/
Subtype.property.{u} {α : Sort u} {p : α → Prop} (self : Subtype p) : p ↑self
Subtype.property: ∀ {α : Sort u} {p : αProp} (self : Subtype p), p self
Subtype.property
Subtype.val.{u} {α : Sort u} {p : α → Prop} (self : Subtype p) : α
Subtype.val: {α : Sort u} → {p : αProp} → Subtype pα
Subtype.val
Subtype.mk.{u} {α : Sort u} {p : α → Prop} (val : α) (property : p val) : Subtype p
Subtype.mk: {α : Sort u} → {p : αProp} → (val : α) → p valSubtype p
Subtype.mk
/-! When an (indexed) inductive type is introduced, * the type (or family of types) is defined. * the constructors are defined. * a *recursor* is defined. * a rule for simplification of applications of the recursor is introduced. The recursor can be conveniently used by pattern matching. -/ def
Bool.disagree: BoolBool
Bool.disagree
(
b: Bool
b
:
Bool: Type
Bool
) :
Bool: Type
Bool
:= match
b: Bool
b
with |
Bool.false: Bool
Bool.false
=>
Bool.true: Bool
Bool.true
|
Bool.true: Bool
Bool.true
=>
Bool.false: Bool
Bool.false
Bool.rec.{u} {motive : Bool → Sort u} (false : motive false) (true : motive true) (t : Bool) : motive t
Bool.rec: {motive : BoolSort u} → motive falsemotive true(t : Bool) → motive t
Bool.rec
-- {motive : Bool → Sort u} → motive false → motive true → (t : Bool) → motive t def
egFamily: BoolType
egFamily
(
b: Bool
b
:
Bool: Type
Bool
) :
Type: Type 1
Type
:= match
b: Bool
b
with |
Bool.false: Bool
Bool.false
=>
Unit: Type
Unit
|
Bool.true: Bool
Bool.true
=>
: Type
def
egDepFunction: (b : Bool) → egFamily b
egDepFunction
(
b: Bool
b
:
Bool: Type
Bool
) :
egFamily: BoolType
egFamily
b: Bool
b
:= match
b: Bool
b
with |
Bool.false: Bool
Bool.false
=>
(): Unit
()
|
Bool.true: Bool
Bool.true
=>

Goals accomplished! 🐙

Goals accomplished! 🐙
set_option pp.motives.all true in
fun b => Bool.rec (motive := fun x => (fun b => egFamily b) x) PUnit.unit 3 b
egDepFunction: (b : Bool) → egFamily b
egDepFunction
set_option pp.motives.all true in
fun b => Bool.rec (motive := fun x => (fun b => Bool) x) true false b
Bool.disagree: BoolBool
Bool.disagree