lean4-htt/src/Init/Data/List/Basic.lean
2022-06-24 06:40:38 -07:00

564 lines
18 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
prelude
import Init.SimpLemmas
import Init.Data.Nat.Basic
open Decidable List
universe u v w
variable {α : Type u} {β : Type v} {γ : Type w}
namespace List
theorem length_add_eq_lengthTRAux (as : List α) (n : Nat) : as.length + n = as.lengthTRAux n := by
induction as generalizing n with
| nil => simp [length, lengthTRAux]
| cons a as ih =>
simp [length, lengthTRAux, ← ih, Nat.succ_add]
rfl
@[csimp] theorem length_eq_lengthTR : @List.length = @List.lengthTR := by
apply funext; intro α; apply funext; intro as
simp [lengthTR, ← length_add_eq_lengthTRAux]
@[simp] theorem length_nil : length ([] : List α) = 0 :=
rfl
def reverseAux : List α → List α → List α
| [], r => r
| a::l, r => reverseAux l (a::r)
def reverse (as : List α) :List α :=
reverseAux as []
theorem reverseAux_reverseAux_nil (as bs : List α) : reverseAux (reverseAux as bs) [] = reverseAux bs as := by
induction as generalizing bs with
| nil => rfl
| cons a as ih => simp [reverseAux, ih]
theorem reverseAux_reverseAux (as bs cs : List α) : reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) := by
induction as generalizing bs cs with
| nil => rfl
| cons a as ih => simp [reverseAux, ih (a::bs), ih [a]]
@[simp] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
simp [reverse]; rw [reverseAux_reverseAux_nil]; rfl
protected def append : List α → List α → List α
| [], bs => bs
| a::as, bs => a :: List.append as bs
def appendTR (as bs : List α) : List α :=
reverseAux as.reverse bs
@[csimp] theorem append_eq_appendTR : @List.append = @appendTR := by
apply funext; intro α; apply funext; intro as; apply funext; intro bs
simp [appendTR, reverse]
induction as with
| nil => rfl
| cons a as ih =>
simp [reverseAux, List.append, ih, reverseAux_reverseAux]
instance : Append (List α) := ⟨List.append⟩
@[simp] theorem nil_append (as : List α) : [] ++ as = as := rfl
@[simp] theorem append_nil (as : List α) : as ++ [] = as := by
induction as with
| nil => rfl
| cons a as ih =>
simp_all [HAppend.hAppend, Append.append, List.append]
@[simp] theorem cons_append (a : α) (as bs : List α) : (a::as) ++ bs = a::(as ++ bs) := rfl
@[simp] theorem List.append_eq (as bs : List α) : List.append as bs = as ++ bs := rfl
theorem append_assoc (as bs cs : List α) : (as ++ bs) ++ cs = as ++ (bs ++ cs) := by
induction as with
| nil => rfl
| cons a as ih => simp [ih]
theorem append_cons (as : List α) (b : α) (bs : List α) : as ++ b :: bs = as ++ [b] ++ bs := by
induction as with
| nil => simp
| cons a as ih => simp [ih]
instance : EmptyCollection (List α) := ⟨List.nil⟩
protected def erase {α} [BEq α] : List αα → List α
| [], _ => []
| a::as, b => match a == b with
| true => as
| false => a :: List.erase as b
def eraseIdx : List α → Nat → List α
| [], _ => []
| _::as, 0 => as
| a::as, n+1 => a :: eraseIdx as n
def isEmpty : List α → Bool
| [] => true
| _ :: _ => false
@[specialize] def map (f : α → β) : List α → List β
| [] => []
| a::as => f a :: map f as
@[specialize] def mapTRAux (f : α → β) : List α → List β → List β
| [], bs => bs.reverse
| a::as, bs => mapTRAux f as (f a :: bs)
@[inline] def mapTR (f : α → β) (as : List α) : List β :=
mapTRAux f as []
theorem reverseAux_eq_append (as bs : List α) : reverseAux as bs = reverseAux as [] ++ bs := by
induction as generalizing bs with
| nil => simp [reverseAux]
| cons a as ih =>
simp [reverseAux]
rw [ih (a :: bs), ih [a], append_assoc]
rfl
@[simp] theorem reverse_nil : reverse ([] : List α) = [] :=
rfl
@[simp] theorem reverse_cons (a : α) (as : List α) : reverse (a :: as) = reverse as ++ [a] := by
simp [reverse, reverseAux]
rw [← reverseAux_eq_append]
@[simp] theorem reverse_append (as bs : List α) : (as ++ bs).reverse = bs.reverse ++ as.reverse := by
induction as generalizing bs with
| nil => simp
| cons a as ih => simp [ih]; rw [append_assoc]
theorem mapTRAux_eq (f : α → β) (as : List α) (bs : List β) : mapTRAux f as bs = bs.reverse ++ map f as := by
induction as generalizing bs with
| nil => simp [mapTRAux, map]
| cons a as ih =>
simp [mapTRAux, map]
rw [ih (f a :: bs), reverse_cons, append_assoc]
rfl
@[csimp] theorem map_eq_mapTR : @map = @mapTR := by
apply funext; intro α; apply funext; intro β; apply funext; intro f; apply funext; intro as
simp [mapTR, mapTRAux_eq]
@[specialize] def map₂ (f : α → β → γ) : List α → List β → List γ
| [], _ => []
| _, [] => []
| a::as, b::bs => f a b :: map₂ f as bs
def join : List (List α) → List α
| [] => []
| a :: as => a ++ join as
@[specialize] def filterMap (f : α → Option β) : List α → List β
| [] => []
| a::as =>
match f a with
| none => filterMap f as
| some b => b :: filterMap f as
def filter (p : α → Bool) : List α → List α
| [] => []
| a::as => match p a with
| true => a :: filter p as
| false => filter p as
@[specialize] def filterTRAux (p : α → Bool) : List α → List α → List α
| [], rs => rs.reverse
| a::as, rs => match p a with
| true => filterTRAux p as (a::rs)
| false => filterTRAux p as rs
@[inline] def filterTR (p : α → Bool) (as : List α) : List α :=
filterTRAux p as []
theorem filterTRAux_eq (p : α → Bool) (as bs : List α) : filterTRAux p as bs = bs.reverse ++ filter p as := by
induction as generalizing bs with
| nil => simp [filterTRAux, filter]
| cons a as ih =>
simp [filterTRAux, filter]
split
next => rw [ih, reverse_cons, append_assoc]; simp
next => rw [ih]
@[csimp] theorem filter_eq_filterTR : @filter = @filterTR := by
apply funext; intro α; apply funext; intro p; apply funext; intro as
simp [filterTR, filterTRAux_eq]
@[specialize] def partitionAux (p : α → Bool) : List α → List α × List α → List α × List α
| [], (bs, cs) => (bs.reverse, cs.reverse)
| a::as, (bs, cs) =>
match p a with
| true => partitionAux p as (a::bs, cs)
| false => partitionAux p as (bs, a::cs)
@[inline] def partition (p : α → Bool) (as : List α) : List α × List α :=
partitionAux p as ([], [])
def dropWhile (p : α → Bool) : List α → List α
| [] => []
| a::l => match p a with
| true => dropWhile p l
| false => a::l
def find? (p : α → Bool) : List α → Option α
| [] => none
| a::as => match p a with
| true => some a
| false => find? p as
def findSome? (f : α → Option β) : List α → Option β
| [] => none
| a::as => match f a with
| some b => some b
| none => findSome? f as
def replace [BEq α] : List ααα → List α
| [], _, _ => []
| a::as, b, c => match a == b with
| true => c::as
| false => a :: (replace as b c)
def elem [BEq α] (a : α) : List α → Bool
| [] => false
| b::bs => match a == b with
| true => true
| false => elem a bs
def notElem [BEq α] (a : α) (as : List α) : Bool :=
!(as.elem a)
abbrev contains [BEq α] (as : List α) (a : α) : Bool :=
elem a as
inductive Mem : α → List α → Prop
| head (a : α) (as : List α) : Mem a (a::as)
| tail (a : α) {b : α} {as : List α} : Mem b as → Mem b (a::as)
instance : Membership α (List α) where
mem := Mem
theorem mem_of_elem_eq_true [DecidableEq α] {a : α} {as : List α} : elem a as = true → a ∈ as := by
match as with
| [] => simp [elem]
| a'::as =>
simp [elem]
split
next h => intros; simp [BEq.beq] at h; subst h; apply Mem.head
next _ => intro h; exact Mem.tail _ (mem_of_elem_eq_true h)
theorem elem_eq_true_of_mem [DecidableEq α] {a : α} {as : List α} (h : a ∈ as) : elem a as = true := by
induction h with
| head _ => simp [elem]
| tail _ _ ih => simp [elem]; split; rfl; assumption
instance [DecidableEq α] (a : α) (as : List α) : Decidable (a ∈ as) :=
decidable_of_decidable_of_iff (Iff.intro mem_of_elem_eq_true elem_eq_true_of_mem)
theorem mem_append_of_mem_left {a : α} {as : List α} (bs : List α) : a ∈ as → a ∈ as ++ bs := by
intro h
induction h with
| head => apply Mem.head
| tail => apply Mem.tail; assumption
theorem mem_append_of_mem_right {b : α} {bs : List α} (as : List α) : b ∈ bs → b ∈ as ++ bs := by
intro h
induction as with
| nil => simp [h]
| cons => apply Mem.tail; assumption
def eraseDupsAux {α} [BEq α] : List α → List α → List α
| [], bs => bs.reverse
| a::as, bs => match bs.elem a with
| true => eraseDupsAux as bs
| false => eraseDupsAux as (a::bs)
def eraseDups {α} [BEq α] (as : List α) : List α :=
eraseDupsAux as []
def eraseRepsAux {α} [BEq α] : α → List α → List α → List α
| a, [], rs => (a::rs).reverse
| a, a'::as, rs => match a == a' with
| true => eraseRepsAux a as rs
| false => eraseRepsAux a' as (a::rs)
/-- Erase repeated adjacent elements. -/
def eraseReps {α} [BEq α] : List α → List α
| [] => []
| a::as => eraseRepsAux a as []
@[specialize] def spanAux (p : α → Bool) : List α → List α → List α × List α
| [], rs => (rs.reverse, [])
| a::as, rs => match p a with
| true => spanAux p as (a::rs)
| false => (rs.reverse, a::as)
@[inline] def span (p : α → Bool) (as : List α) : List α × List α :=
spanAux p as []
@[specialize] def groupByAux (eq : αα → Bool) : List α → List (List α) → List (List α)
| a::as, (ag::g)::gs => match eq a ag with
| true => groupByAux eq as ((a::ag::g)::gs)
| false => groupByAux eq as ([a]::(ag::g).reverse::gs)
| _, gs => gs.reverse
@[specialize] def groupBy (p : αα → Bool) : List α → List (List α)
| [] => []
| a::as => groupByAux p as [[a]]
def lookup [BEq α] : α → List (α × β) → Option β
| _, [] => none
| a, (k,b)::es => match a == k with
| true => some b
| false => lookup a es
def removeAll [BEq α] (xs ys : List α) : List α :=
xs.filter (fun x => ys.notElem x)
def drop : Nat → List α → List α
| 0, a => a
| _+1, [] => []
| n+1, _::as => drop n as
def take : Nat → List α → List α
| 0, _ => []
| _+1, [] => []
| n+1, a::as => a :: take n as
def takeWhile (p : α → Bool) : List α → List α
| [] => []
| hd :: tl => match p hd with
| true => hd :: takeWhile p tl
| false => []
@[specialize] def foldr (f : α → β → β) (init : β) : List α → β
| [] => init
| a :: l => f a (foldr f init l)
@[inline] def any (l : List α) (p : α → Bool) : Bool :=
foldr (fun a r => p a || r) false l
@[inline] def all (l : List α) (p : α → Bool) : Bool :=
foldr (fun a r => p a && r) true l
def or (bs : List Bool) : Bool := bs.any id
def and (bs : List Bool) : Bool := bs.all id
def zipWith (f : α → β → γ) : List α → List β → List γ
| x::xs, y::ys => f x y :: zipWith f xs ys
| _, _ => []
def zip : List α → List β → List (Prod α β) :=
zipWith Prod.mk
def unzip : List (α × β) → List α × List β
| [] => ([], [])
| (a, b) :: t => match unzip t with | (al, bl) => (a::al, b::bl)
def rangeAux : Nat → List Nat → List Nat
| 0, ns => ns
| n+1, ns => rangeAux n (n::ns)
def range (n : Nat) : List Nat :=
rangeAux n []
def iota : Nat → List Nat
| 0 => []
| m@(n+1) => m :: iota n
def iotaTR (n : Nat) : List Nat :=
let rec go : Nat → List Nat → List Nat
| 0, r => r.reverse
| m@(n+1), r => go n (m::r)
go n []
@[csimp]
theorem iota_eq_iotaTR : @iota = @iotaTR :=
have aux (n : Nat) (r : List Nat) : iotaTR.go n r = r.reverse ++ iota n := by
induction n generalizing r with
| zero => simp [iota, iotaTR.go]
| succ n ih => simp [iota, iotaTR.go, ih, append_assoc]
funext fun n => by simp [iotaTR, aux]
def enumFrom : Nat → List α → List (Nat × α)
| _, [] => nil
| n, x :: xs => (n, x) :: enumFrom (n + 1) xs
def enum : List α → List (Nat × α) := enumFrom 0
def init : List α → List α
| [] => []
| [_] => []
| a::l => a::init l
def intersperse (sep : α) : List α → List α
| [] => []
| [x] => [x]
| x::xs => x :: sep :: intersperse sep xs
def intercalate (sep : List α) (xs : List (List α)) : List α :=
join (intersperse sep xs)
@[inline] protected def bind {α : Type u} {β : Type v} (a : List α) (b : α → List β) : List β := join (map b a)
@[inline] protected def pure {α : Type u} (a : α) : List α := [a]
inductive lt [LT α] : List α → List α → Prop where
| nil (b : α) (bs : List α) : lt [] (b::bs)
| head {a : α} (as : List α) {b : α} (bs : List α) : a < b → lt (a::as) (b::bs)
| tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → lt as bs → lt (a::as) (b::bs)
instance [LT α] : LT (List α) := ⟨List.lt⟩
instance hasDecidableLt [LT α] [h : DecidableRel (α:=α) (·<·)] : (l₁ l₂ : List α) → Decidable (l₁ < l₂)
| [], [] => isFalse (fun h => nomatch h)
| [], _::_ => isTrue (List.lt.nil _ _)
| _::_, [] => isFalse (fun h => nomatch h)
| a::as, b::bs =>
match h a b with
| isTrue h₁ => isTrue (List.lt.head _ _ h₁)
| isFalse h₁ =>
match h b a with
| isTrue h₂ => isFalse (fun h => match h with
| List.lt.head _ _ h₁' => absurd h₁' h₁
| List.lt.tail _ h₂' _ => absurd h₂ h₂')
| isFalse h₂ =>
match hasDecidableLt as bs with
| isTrue h₃ => isTrue (List.lt.tail h₁ h₂ h₃)
| isFalse h₃ => isFalse (fun h => match h with
| List.lt.head _ _ h₁' => absurd h₁' h₁
| List.lt.tail _ _ h₃' => absurd h₃' h₃)
@[reducible] protected def le [LT α] (a b : List α) : Prop := ¬ b < a
instance [LT α] : LE (List α) := ⟨List.le⟩
instance [LT α] [DecidableRel ((· < ·) : αα → Prop)] : (l₁ l₂ : List α) → Decidable (l₁ ≤ l₂) :=
fun _ _ => inferInstanceAs (Decidable (Not _))
/-- `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`.
That is, there exists a `t` such that `l₂ == l₁ ++ t`. -/
def isPrefixOf [BEq α] : List α → List α → Bool
| [], _ => true
| _, [] => false
| a::as, b::bs => a == b && isPrefixOf as bs
/-- `isSuffixOf l₁ l₂` returns `true` Iff `l₁` is a suffix of `l₂`.
That is, there exists a `t` such that `l₂ == t ++ l₁`. -/
def isSuffixOf [BEq α] (l₁ l₂ : List α) : Bool :=
isPrefixOf l₁.reverse l₂.reverse
@[specialize] def isEqv : List α → List α → (αα → Bool) → Bool
| [], [], _ => true
| a::as, b::bs, eqv => eqv a b && isEqv as bs eqv
| _, _, _ => false
protected def beq [BEq α] : List α → List α → Bool
| [], [] => true
| a::as, b::bs => a == b && List.beq as bs
| _, _ => false
instance [BEq α] : BEq (List α) := ⟨List.beq⟩
@[simp] def replicate : (n : Nat) → (a : α) → List α
| 0, _ => []
| n+1, a => a :: replicate n a
def replicateTR {α : Type u} (n : Nat) (a : α) : List α :=
let rec loop : Nat → List α → List α
| 0, as => as
| n+1, as => loop n (a::as)
loop n []
theorem replicateTR_loop_replicate_eq (a : α) (m n : Nat) :
replicateTR.loop a n (replicate m a) = replicate (n + m) a := by
induction n generalizing m with simp [replicateTR.loop]
| succ n ih => simp [Nat.succ_add]; exact ih (m+1)
@[csimp] theorem replicate_eq_replicateTR : @List.replicate = @List.replicateTR := by
apply funext; intro α; apply funext; intro n; apply funext; intro a
exact (replicateTR_loop_replicate_eq _ 0 n).symm
def dropLast {α} : List α → List α
| [] => []
| [_] => []
| a::as => a :: dropLast as
@[simp] theorem length_replicate (n : Nat) (a : α) : (replicate n a).length = n := by
induction n <;> simp_all
@[simp] theorem length_concat (as : List α) (a : α) : (concat as a).length = as.length + 1 := by
induction as with
| nil => rfl
| cons _ xs ih => simp [concat, ih]
@[simp] theorem length_set (as : List α) (i : Nat) (a : α) : (as.set i a).length = as.length := by
induction as generalizing i with
| nil => rfl
| cons x xs ih =>
cases i with
| zero => rfl
| succ i => simp [set, ih]
@[simp] theorem length_dropLast_cons (a : α) (as : List α) : (a :: as).dropLast.length = as.length := by
match as with
| [] => rfl
| b::bs =>
have ih := length_dropLast_cons b bs
simp[dropLast, ih]
@[simp] theorem length_append (as bs : List α) : (as ++ bs).length = as.length + bs.length := by
induction as with
| nil => simp
| cons _ as ih => simp [ih, Nat.succ_add]
@[simp] theorem length_map (as : List α) (f : α → β) : (as.map f).length = as.length := by
induction as with
| nil => simp [List.map]
| cons _ as ih => simp [List.map, ih]
@[simp] theorem length_reverse (as : List α) : (as.reverse).length = as.length := by
induction as with
| nil => rfl
| cons a as ih => simp [ih]
def maximum? [LT α] [DecidableRel (@LT.lt α _)] : List α → Option α
| [] => none
| a::as => some <| as.foldl max a
def minimum? [LE α] [DecidableRel (@LE.le α _)] : List α → Option α
| [] => none
| a::as => some <| as.foldl min a
instance [BEq α] [LawfulBEq α] : LawfulBEq (List α) where
eq_of_beq {as bs} := by
induction as generalizing bs with
| nil => intro h; cases bs <;> first | rfl | contradiction
| cons a as ih =>
cases bs with
| nil => intro h; contradiction
| cons b bs =>
simp [BEq.beq, List.beq]
intro ⟨h₁, h₂⟩
exact ⟨eq_of_beq h₁, ih h₂⟩
rfl {as} := by
induction as with
| nil => rfl
| cons a as ih => simp [BEq.beq, List.beq, LawfulBEq.rfl]; exact ih
theorem of_concat_eq_concat {as bs : List α} {a b : α} (h : as.concat a = bs.concat b) : as = bs ∧ a = b := by
match as, bs with
| [], [] => simp [concat] at h; simp [h]
| [_], [] => simp [concat] at h
| _::_::_, [] => simp [concat] at h
| [], [_] => simp [concat] at h
| [], _::_::_ => simp [concat] at h
| _::_, _::_ => simp [concat] at h; simp [h]; apply of_concat_eq_concat h.2
end List