Tipos inductivos Lean

Índice

1 Tipos enumerados

inductive weekday : Type
| sunday : weekday
| monday : weekday
| tuesday : weekday
| wednesday : weekday
| thursday : weekday
| friday : weekday
| saturday : weekday

#check weekday.sunday   -- weekday
#check weekday.monday   -- weekday

open weekday

#check sunday   -- weekday
#check monday   -- weekday
inductive weekday : Type
| sunday : weekday
| monday : weekday
| tuesday : weekday
| wednesday : weekday
| thursday : weekday
| friday : weekday
| saturday : weekday

def number_of_day (d : weekday) :  :=
weekday.rec_on d 1 2 3 4 5 6 7

#reduce number_of_day weekday.sunday   -- 1
#reduce number_of_day weekday.monday   -- 2
#reduce number_of_day weekday.tuesday  -- 3

-- 2ª forma (con cases_on)
def number_of_day2 (d : weekday) :  :=
weekday.cases_on d 1 2 3 4 5 6 7

#reduce number_of_day2 weekday.sunday   -- 1
#reduce number_of_day2 weekday.monday   -- 2
#reduce number_of_day2 weekday.tuesday  -- 3
inductive weekday : Type
| sunday : weekday
| monday : weekday
| tuesday : weekday
| wednesday : weekday
| thursday : weekday
| friday : weekday
| saturday : weekday

namespace weekday
  @[reducible]
  private def cases_on := @weekday.cases_on

  def number_of_day (d : weekday) : nat :=
  cases_on d 1 2 3 4 5 6 7
end weekday

#reduce weekday.number_of_day weekday.sunday  -- 1

open weekday (renaming cases_on  cases_on)

#reduce number_of_day sunday   -- 1
#check cases_on
inductive weekday : Type
| sunday : weekday
| monday : weekday
| tuesday : weekday
| wednesday : weekday
| thursday : weekday
| friday : weekday
| saturday : weekday

namespace weekday
  def next (d : weekday) : weekday :=
  weekday.cases_on d monday tuesday wednesday thursday friday
    saturday sunday

  def previous (d : weekday) : weekday :=
  weekday.cases_on d saturday sunday monday tuesday wednesday
    thursday friday

  #reduce next (next tuesday)
  #reduce next (previous tuesday)

  example : next (previous tuesday) = tuesday := rfl

  theorem next_previous (d: weekday) :
    next (previous d) = d :=
  weekday.cases_on d
    (show next (previous sunday) = sunday, from rfl)
    (show next (previous monday) = monday, from rfl)
    (show next (previous tuesday) = tuesday, from rfl)
    (show next (previous wednesday) = wednesday, from rfl)
    (show next (previous thursday) = thursday, from rfl)
    (show next (previous friday) = friday, from rfl)
    (show next (previous saturday) = saturday, from rfl)

  -- 2ª demostración
  theorem next_previous2 (d: weekday) :
    next (previous d) = d :=
  weekday.cases_on d rfl rfl rfl rfl rfl rfl rfl

  -- 3ª demostración
  theorem next_previous3 (d: weekday) :
    next (previous d) = d :=
  by apply weekday.cases_on d; refl

  -- 4ª demostración
  theorem next_previous4 (d: weekday) :
    next (previous d) = d :=
  by apply weekday.rec_on d; refl

end weekday
namespace hidden
inductive empty : Type

inductive unit : Type
| star : unit

inductive bool : Type
| ff : bool
| tt : bool

end hidden
namespace hidden

def band (b1 b2 : bool) : bool :=
bool.cases_on b1 ff b2

#reduce band tt tt -- tt
#reduce band tt ff -- ff
#reduce band ff tt -- ff
#reduce band ff ff -- ff

end hidden

2 Constructores con argumentos

namespace hidden

universes u v

inductive prod (α : Type u) (β : Type v)
| mk : α  β  prod

inductive sum (α : Type u) (β : Type v)
| inl {} : α  sum
| inr {} : β  sum

end hidden
universes u v

def fst {α : Type u} {β : Type v} (p : α × β) : α :=
prod.rec_on p (λ a b, a)

def snd {α : Type u} {β : Type v} (p : α × β) : β :=
prod.rec_on p (λ a b, b)
def prod_example (p : bool × ) :  :=
prod.rec_on p (λ b n, cond b (2 * n) (2 * n + 1))

#reduce prod_example (tt, 3)  -- 6
#reduce prod_example (ff, 3)  -- 7
def sum_example (s : ) :  :=
sum.cases_on s (λ n, 2 * n) (λ n, 2 * n + 1)

#reduce sum_example (sum.inl 3)  -- 6
#reduce sum_example (sum.inr 3)  -- 7
namespace hidden

universes u v

inductive prod (α : Type u) (β : Type v)
| mk (fst : α) (snd : β) : prod

inductive sum (α : Type u) (β : Type v)
| inl {} (a : α) : sum
| inr {} (b : β) : sum

end hidden
namespace hidden

structure prod (α β : Type) :=
mk :: (fst : α) (snd : β)

end hidden
open nat

structure color := (red : nat) (green : nat) (blue : nat)

def yellow := color.mk 255 255 0

#reduce color.red   yellow   -- 255
#reduce color.green yellow   -- 255
#reduce color.blue  yellow   -- 0
universe u

structure Semigroup :=
(carrier : Type u)
(mul : carrier  carrier  carrier)
(mul_assoc :  a b c, mul (mul a b) c = mul a (mul b c))
universes u v

namespace hidden

inductive sigma {α : Type u} (β : α  Type v)
| dpair : Π a : α, β a  sigma

end hidden
universe u

namespace hidden

inductive option (α : Type u)
| none {} : option
| some    : α  option

inductive inhabited (α : Type u)
| mk : α  inhabited

end hidden

3 Proposiciones definidas inductivamente

namespace hidden

inductive false : Prop

inductive true : Prop
| intro : true

inductive and (a b : Prop) : Prop
| intro : a  b  and

inductive or (a b : Prop) : Prop
| intro_left  : a  or
| intro_right : b  or

end hidden
universe u

namespace hidden

inductive Exists {α : Type u} (p : α  Prop) : Prop
| intro :  (a : α), p a  Exists

def exists.intro := @Exists.intro

end hidden
universe u

namespace hidden

inductive subtype {α : Type u} (p : α  Prop)
| mk : Π x : α, p x  subtype

end hidden
universe u
namespace hidden

structure subtype {α : Sort u} (p : α  Prop) :=
(val : α) (property : p val)

section
variables {α : Type u} (p : α  Prop)

#check subtype p
#check { x : α // p x}
end

end hidden

4 Definición de los números naturales

namespace hidden

-- Definición de los naturales
-- ===========================

inductive nat : Type
| zero : nat
| succ : nat  nat

-- Tipo de nat.rec_on
-- ==================

#check @nat.rec_on

-- Da
--    Π {C : nat → Sort u_1} (n : nat), 
--    C nat.zero → (Π (a : nat), C a → C (nat.succ a)) → C n 

namespace nat

-- Definición de suma
def add (m n : nat) : nat :=
nat.rec_on n m (λ n add_m_n, succ add_m_n)

-- Cálculo de suma
#reduce add (succ zero) (succ (succ zero))   -- succ (succ (succ zero))

-- Notación para la suma
instance : has_zero nat := has_zero.mk zero
instance : has_add nat := has_add.mk add

-- Ecuaciones de la suma
theorem add_zero (m : nat) : m + 0 = m := rfl
theorem add_succ (m n : nat) : m + succ n = succ (m + n) := rfl

end nat

end hidden
namespace hidden
open nat

-- 1ª demostración
theorem zero_add (n : ) : 0 + n = n :=
nat.rec_on n
  (show 0 + 0 = 0, from rfl)
  (assume n,
    assume ih : 0 + n = n,
    show 0 + succ n = succ n, from
      calc
        0 + succ n = succ (0 + n) : rfl
               ... = succ n       : by rw ih)

-- 2ª demostración
theorem zero_add2 (n : ) : 0 + n = n :=
nat.rec_on n rfl (λ n ih, by rw [add_succ, ih])

-- 2ª demostración
theorem zero_add3 (n : ) : 0 + n = n :=
nat.rec_on n rfl (λ n ih, by simp only [add_succ, ih])

end hidden
namespace hidden
open nat

-- 1ª demostración
theorem add_assoc (m n k : ) : (m + n) + k = m + (n + k) :=
nat.rec_on k
  (show (m + n) + 0 = m + (n + 0), from rfl)
  (assume k,
    assume ih : (m + n) + k = m + (n + k),
    show (m + n) + succ k = m + (n + succ k), from
      calc
        (m + n) + succ k = succ ((m + n) + k) : rfl
          ... = succ (m + (n + k)) : by rw ih
          ... = m + succ (n + k) : rfl
          ... = m + (n + succ k) : rfl)

-- 2ª demostración
theorem add_assoc2 (m n k : ) : m + n + k = m + (n + k) :=
nat.rec_on k rfl (λ k ih, by simp only [add_succ, ih])

end hidden
namespace hidden
open nat

-- 1ª demostración
-- ===============

theorem add_assoc (m n k : ) : m + n + k = m + (n + k) :=
nat.rec_on k
  (show m + n + 0 = m + (n + 0), from rfl)
  (assume k,
    assume ih : m + n + k = m + (n + k),
    show m + n + succ k = m + (n + succ k), from
      calc
        m + n + succ k = succ (m + n + k) : rfl
          ... = succ (m + (n + k)) : by rw ih
          ... = m + succ (n + k) : rfl
          ... = m + (n + succ k) : rfl)

theorem succ_add (m n : nat) : succ m + n = succ (m + n) :=
nat.rec_on n
  (show succ m + 0 = succ (m + 0), from rfl)
  (assume n,
    assume ih : succ m + n = succ (m + n),
    show succ m + succ n = succ (m + succ n), from
      calc
        succ m + succ n = succ (succ m + n) : rfl
          ... = succ (succ (m + n)) : by rw ih
          ... = succ (m + succ n) : rfl)

-- 2ª demostración
-- ===============

theorem add_assoc2 (m n k : ) : m + n + k = m + (n + k) :=
nat.rec_on k rfl (λ k ih, by simp only [add_succ, ih])

theorem succ_add2 (m n : nat) : succ m + n = succ (m + n) :=
nat.rec_on n rfl (λ n ih, by simp only [succ_add, ih])

-- Conmutativa
-- ===========

theorem add_comm (m n : nat) : m + n = n + m :=
nat.rec_on n
  (by simp only [zero_add, add_zero])
  (λ n ih, by simp only [add_succ, ih, succ_add])

end hidden

5 Otros tipos de dato recursivos

universe u

namespace hidden

inductive list (α : Type u)
| nil {} : list
| cons : α  list  list

namespace list

variable {α : Type}

notation h :: t  := cons h t

def append (s t : list α) : list α :=
list.rec t (λ x l u, x::u) s

notation s ++ t := append s t

theorem nil_append (t : list α) : nil ++ t = t := rfl

theorem cons_append (x : α) (s t : list α) :
  (x::s) ++ t = x::(s ++ t) := rfl

end list

end hidden
universe u

namespace hidden

inductive list (α : Type u)
| nil {} : list
| cons : α  list  list

namespace list

notation `[` l:(foldr `,` (h t, cons h t) nil) `]` := l

section
  open nat
  #check [1, 2, 3, 4, 5]
  #check ([1, 2, 3, 4, 5] : list int)
end

end list

end hidden
inductive binary_tree
| leaf : binary_tree
| node : binary_tree  binary_tree  binary_tree
inductive cbtree
| leaf : cbtree
| sup : (  cbtree)  cbtree

namespace cbtree

def succ (t : cbtree) : cbtree :=
sup (λ n, t)

def omega : cbtree :=
sup (λ n, nat.rec_on n leaf (λ n t, succ t))

end cbtree

6 Tácticas para tipos inductivos

open nat
variable p :   Prop

example (hz : p 0) (hs :  n, p (succ n)) :  n, p n :=
begin
  intro n,
  cases n,
  { exact hz },  
  apply hs       
end
open nat

example (n : ) (h : n  0) : succ (pred n) = n :=
begin
  cases n with m,
    { apply (absurd rfl h) },
  reflexivity
end
def f (n : ) :  :=
begin
  cases n, exact 3, exact 7
end

example : f 0 = 3 := rfl
example : f 5 = 7 := rfl
universe u

def tuple (α : Type u) (n : ) :=
  { l : list α // list.length l = n }

variables {α : Type u} {n : }

def f {n : } (t : tuple α n) :  :=
begin
  cases n, exact 3, exact 7
end

def my_tuple : tuple  3 :=  [0, 1, 2], rfl

example : f my_tuple = 7 := rfl
inductive foo : Type
| bar1 :     foo
| bar2 :       foo

def silly (x : foo) :  :=
begin
  cases x with a b c d e,
  exact b,    -- a, b    are in the context
  exact e     -- c, d, e are in the context
end

#reduce silly (foo.bar1 5 7)   -- 7
#reduce silly (foo.bar2 5 7 9) -- 9
inductive foo : Type
| bar1 :     foo
| bar2 :       foo

open foo

def silly (x : foo) :  :=
begin
  cases x,
    case bar1 : a b
      { exact b },
    case bar2 : c d e
      { exact e }
end
open nat
variable p :   Prop

example (hz : p 0) (hs :  n, p (succ n)) (m k : ) :
  p (m + 3 * k) :=
begin
  cases (m + 3 * k),
  { exact hz },  
  apply hs       
end
open nat
variable p :   Prop

example (hz : p 0) (hs :  n, p (succ n)) (m k : ) :
  p (m + 3 * k) :=
begin
  generalize : m + 3 * k = n,
  cases n,
  { exact hz },  
  apply hs       
end
example (p : Prop) (m n : )
  (h₁ : m < n  p) (h₂ : m  n  p) : p :=
begin
  cases lt_or_ge m n with hlt hge,
  { exact h₁ hlt },
  exact h₂ hge
end

-- 2ª demostración
example (p : Prop) (m n : )
  (h₁ : m < n  p) (h₂ : m  n  p) : p :=
begin
  have h : m < n  m  n,
  { exact lt_or_ge m n },
  cases h with hlt hge,
  { exact h₁ hlt },
  exact h₂ hge
end
#check nat.sub_self

example (m n : ) : m - n = 0  m  n :=
begin
  cases decidable.em (m = n) with heq hne,
  { rw heq,
    left, exact nat.sub_self n },
  right, exact hne
end
def f (m k : ) :  :=
begin
  cases m - k, exact 3, exact 7
end

example : f 5 7 = 3 := rfl
example : f 10 2 = 7 := rfl
namespace hidden
open nat

theorem zero_add (n : ) : 0 + n = n :=
begin
  induction n with n ih,
    refl,
  rw [add_succ, ih]
end

theorem zero_add (n : ) : 0 + n = n :=
begin
  induction n,
  case zero : { refl },
  case succ : n ih { rw [add_succ, ih]}
end

theorem succ_add (m n : ) : succ m + n = succ (m + n) :=
begin
  induction n,
  case zero : { refl },
  case succ : n ih { rw [add_succ, ih] }
end

theorem add_comm (m n : ) : m + n = n + m :=
begin
  induction n,
  case zero : { rw zero_add, refl },
  case succ : n ih { rw [add_succ, ih, succ_add] }
end

end hidden
namespace hidden
open nat

theorem zero_add (n : ) : 0 + n = n :=
by induction n; simp only [*, add_zero, add_succ]

theorem succ_add (m n : ) : succ m + n = succ (m + n) :=
by induction n; simp only [*, add_zero, add_succ]

theorem add_comm (m n : ) : m + n = n + m :=
by induction n;
     simp only [*, add_zero, add_succ, succ_add, zero_add]

theorem add_assoc (m n k : ) : m + n + k = m + (n + k) :=
by induction k; simp only [*, add_zero, add_succ]

end hidden
open nat

example (m n k : ) (h : succ (succ m) = succ (succ n)) :
  n + k = m + k :=
begin
  injection h with h',
  injection h' with h'',
  rw h''
end
open nat

example (m n k : ) (h : succ (succ m) = succ (succ n)) :
  n + k = m + k :=
begin
  injections with h' h'',
  rw h''
end

example (m n k : ) (h : succ (succ m) = succ (succ n)) :
  n + k = m + k :=
by injections; simp *
open nat

example (m n : ) (h : succ m = 0) : n = n + 7 :=
by injections

example (m n : ) (h : succ m = 0) : n = n + 7 :=
by contradiction

example (h : 7 = 4) : false :=
by injections

7 Familias inductivas

open nat
universe u
namespace hidden

inductive vector (α : Type u) : nat  Type u
| nil {}                              : vector zero
| cons {n : } (a : α) (v : vector n) : vector (succ n)

end hidden
universe u
namespace hidden

inductive eq {α : Sort u} (a : α) : α  Prop
| refl : eq a

end hidden
universes u v

#check (@eq.rec_on :
  Π {α : Sort u} {a : α} {C : α  Sort v} {b : α},
    a = b  C a  C b)
namespace hidden
universe u

inductive eq {α : Type u} (a : α) : α  Prop
| refl : eq a

@[elab_as_eliminator]
theorem subst {α : Type u} {a b : α} {p : α  Prop}
  (h₁ : eq a b) (h₂ : p a) : p b :=
eq.rec h₂ h₁

end hidden
namespace hidden
universe u

inductive eq {α : Type u} (a : α) : α  Prop
| refl : eq a

@[elab_as_eliminator]
theorem subst {α : Type u} {a b : α} {P : α  Prop}
  (h₁ : eq a b) (h₂ : P a) : P b :=
eq.rec h₂ h₁


theorem symm {α : Type u} {a b : α} (h : eq a b) : eq b a :=
subst h (eq.refl a)

theorem trans {α : Type u} {a b c : α}
  (h₁ : eq a b) (h₂ : eq b c) : eq a c :=
subst h₂ h₁

theorem congr {α β : Type u} {a b : α} (f : α  β)
  (h : eq a b) : eq (f a) (f b) :=
subst h (eq.refl (f a))

end hidden

8 Detalles axiomáticos

9 Tipos mutuamente inductivos

mutual inductive even, odd
with even :   Prop
| even_zero : even 0
| even_succ :  n, odd n  even (n + 1)
with odd :   Prop
| odd_succ :  n, even n  odd (n + 1)
universe u

mutual inductive tree, list_tree (α : Type u)
with tree : Type u
| node : α  list_tree  tree
with list_tree : Type u
| nil {}  : list_tree
| cons    : tree  list_tree  list_tree

inductive tree2 (α : Type u)
| mk : α  list tree2  tree2

10 Referencias

José A. Alonso

2019-10-15 mar 10:44