lean4-htt/library/init/data/list/basic.lean

383 lines
12 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.core init.data.nat.basic
open Decidable List
universes u v w
instance (α : Type u) : Inhabited (List α) :=
⟨List.nil⟩
variables {α : Type u} {β : Type v} {γ : Type w}
namespace List
protected def hasDecEq [DecidableEq α] : Π a b : List α, Decidable (a = b)
| [] [] := isTrue rfl
| (a::as) [] := isFalse (λ h, List.noConfusion h)
| [] (b::bs) := isFalse (λ h, List.noConfusion h)
| (a::as) (b::bs) :=
match decEq a b with
| isTrue hab :=
(match hasDecEq as bs with
| isTrue habs := isTrue (Eq.subst hab (Eq.subst habs rfl))
| isFalse nabs := isFalse (λ h, List.noConfusion h (λ _ habs, absurd habs nabs)))
| isFalse nab := isFalse (λ h, List.noConfusion h (λ hab _, absurd hab nab))
instance [DecidableEq α] : DecidableEq (List α) :=
{decEq := List.hasDecEq}
def reverseCore : List α → List α → List α
| [] r := r
| (a::l) r := reverseCore l (a::r)
local infix `**`:66 := reverseCore
def reverse : List α → List α :=
λ l, reverseCore l []
protected def append (as bs : List α) : List α :=
reverseCore as.reverse bs
instance : HasAppend (List α) :=
⟨List.append⟩
theorem reverseCoreReverseCoreNil : ∀ (as bs : List α), (as ** bs) ** [] = bs ** as
| [] bs := rfl
| (a::as) bs :=
show reverseCore (reverseCore as (a::bs)) [] = reverseCore bs (a::as), from
reverseCoreReverseCoreNil as (a::bs)
theorem nilAppend (as : List α) : [] ++ as = as :=
rfl
theorem appendNil (as : List α) : as ++ [] = as :=
show (as ** []) ** [] = as, from
reverseCoreReverseCoreNil as []
theorem reverseCoreReverseCore : ∀ (as bs cs : List α), (as ** bs) ** cs = bs ** ((as ** []) ** cs)
| [] bs cs := rfl
| (a::as) bs cs :=
show (as ** a::bs) ** cs = bs ** ((as ** [a]) ** cs), from
have h₁ : (as ** a::bs) ** cs = bs ** a::((as ** []) ** cs), from reverseCoreReverseCore as (a::bs) cs,
have h₂ : ((as ** [a]) ** cs) = a::((as ** []) ** cs), from reverseCoreReverseCore as [a] cs,
have h₃ : bs ** a::((as ** []) ** cs) = bs ** ((as ** [a]) ** cs), from congrArg (λ b, bs ** b) h₂.symm,
Eq.trans h₁ h₃
theorem consAppend (a : α) (as bs : List α) : (a::as) ++ bs = a::(as ++ bs) :=
reverseCoreReverseCore as [a] bs
theorem appendAssoc : ∀ (as bs cs : List α), (as ++ bs) ++ cs = as ++ (bs ++ cs)
| [] bs cs := rfl
| (a::as) bs cs :=
show ((a::as) ++ bs) ++ cs = (a::as) ++ (bs ++ cs), from
have h₁ : ((a::as) ++ bs) ++ cs = a::(as++bs) ++ cs, from congrArg (++ cs) (consAppend a as bs),
have h₂ : a::(as++bs) ++ cs = a::((as++bs) ++ cs), from consAppend a (as++bs) cs,
have h₃ : a::((as++bs) ++ cs) = a::(as ++ (bs ++ cs)), from congrArg (λ as, a::as) (appendAssoc as bs cs),
have h₄ : a::(as ++ (bs ++ cs)) = (a::as ++ (bs ++ cs)), from (consAppend a as (bs++cs)).symm,
Eq.trans (Eq.trans (Eq.trans h₁ h₂) h₃) h₄
inductive Mem : α → List α → Prop
| eqHead (a : α) (as : List α) : Mem a (a::as)
| inTail {a : α} (b : α) {bs : List α} (h : Mem a bs) : Mem a (b::bs)
instance : HasMem α (List α) :=
⟨Mem⟩
theorem notMem : ∀ {a b : α} {bs : List α}, a ≠ b → ¬ a ∈ bs → ¬ a ∈ b :: bs
| _ _ _ h _ (Mem.eqHead _ _) := absurd rfl h
| _ _ _ _ h₁ (Mem.inTail _ h₂) := absurd h₂ h₁
instance decidableMem [DecidableEq α] (a : α) : ∀ (l : List α), Decidable (a ∈ l)
| [] := isFalse (λ h, match h with end)
| (b::bs) :=
if h₁ : a = b then isTrue (h₁.symm ▸ Mem.eqHead b bs)
else match decidableMem bs with
| isTrue h₂ := isTrue (Mem.inTail _ h₂)
| isFalse h₂ := isFalse (notMem h₁ h₂)
instance : HasEmptyc (List α) :=
⟨List.nil⟩
protected def erase {α} [DecidableEq α] : List αα → List α
| [] b := []
| (a::l) b := if a = b then l else a :: erase l b
protected def bagInter {α} [DecidableEq α] : List α → List α → List α
| [] _ := []
| _ [] := []
| (a::l₁) l₂ := if a ∈ l₂ then a :: bagInter l₁ (l₂.erase a) else bagInter l₁ l₂
protected def diff {α} [DecidableEq α] : List α → List α → List α
| l [] := l
| l₁ (a::l₂) := if a ∈ l₁ then diff (l₁.erase a) l₂ else diff l₁ l₂
def lengthAux : List α → Nat → Nat
| [] n := n
| (a::as) n := lengthAux as (n+1)
def length (as : List α) : Nat :=
lengthAux as 0
def empty : List α → Bool
| [] := true
| (_ :: _) := false
open Option Nat
def nth : List α → Nat → Option α
| [] n := none
| (a :: l) 0 := some a
| (a :: l) (n+1) := nth l n
def head [Inhabited α] : List αα
| [] := default α
| (a :: l) := a
def tail : List α → List α
| [] := []
| (a :: l) := l
@[specialize] def map (f : α → β) : List α → List β
| [] := []
| (a :: l) := f a :: map l
@[specialize] def map₂ (f : α → β → γ) : List α → List β → List γ
| [] _ := []
| _ [] := []
| (x::xs) (y::ys) := f x y :: map₂ xs ys
def join : List (List α) → List α
| [] := []
| (l :: ls) := l ++ join ls
def filterMap (f : α → Option β) : List α → List β
| [] := []
| (a::l) :=
match f a with
| none := filterMap l
| some b := b :: filterMap l
def filter (p : α → Bool) : List α → List α
| [] := []
| (a::l) := match p a with
| true := a :: filter l
| false := filter l
def partition (p : α → Bool) : List α → List α × List α
| [] := ([], [])
| (a::l) := let (l₁, l₂) := partition l in
match p a with
| true := (a :: l₁, l₂)
| false := (l₁, a :: l₂)
def dropWhile (p : α → Bool) : List α → List α
| [] := []
| (a::l) := match p a with
| true := dropWhile l
| false := a::l
def span (p : α → Bool) : List α → List α × List α
| [] := ([], [])
| (a::xs) := match p a with
| true := let (l, r) := span xs in (a :: l, r)
| false := ([], a::xs)
def findIndex (p : α → Bool) : List α → Nat
| [] := 0
| (a::l) := match p a with
| true := 0
| false := succ (findIndex l)
def indexOf [DecidableEq α] (a : α) (l : List α) : Nat :=
findIndex (λ b, a = b) l
def assoc [DecidableEq α] : List (α × β) → α → Option β
| [] _ := none
| ((a,b)::l) a' := if a = a' then some b else assoc l a'
def removeAll [DecidableEq α] (xs ys : List α) : List α :=
filter (∉ ys) xs
def updateNth : List αα → List α
| (x::xs) 0 a := a :: xs
| (x::xs) (i+1) a := x :: updateNth xs i a
| [] _ _ := []
def removeNth : List α → List α
| [] _ := []
| (x::xs) 0 := xs
| (x::xs) (i+1) := x :: removeNth xs i
def drop : → List α → List α
| 0 a := a
| (succ n) [] := []
| (succ n) (x::r) := drop n r
def take : → List α → List α
| 0 a := []
| (succ n) [] := []
| (succ n) (x :: r) := x :: take n r
@[specialize] def foldl (f : α → β → α) : α → List β → α
| a [] := a
| a (b :: l) := foldl (f a b) l
@[specialize] def foldr (f : α → β → β) (b : β) : List α → β
| [] := b
| (a :: l) := f a (foldr l)
@[specialize] def foldr1 (f : ααα) : Π (xs : List α), xs ≠ [] → α
| [] nem := False.elim (nem rfl)
| [a] nem := a
| (a :: l@(_::_)) nem := f a (foldr1 l (λ Eq, List.noConfusion Eq))
@[specialize] def foldr1Opt (f : ααα) : List α → Option α
| [] := none
| (a :: l) := some $ foldr1 f (a :: l) (λ Eq, List.noConfusion Eq)
@[inline] def any (l : List α) (p : α → Bool) : Bool :=
foldr (λ a r, p a || r) false l
@[inline] def all (l : List α) (p : α → Bool) : Bool :=
foldr (λ 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 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)
protected def insert [DecidableEq α] (a : α) (l : List α) : List α :=
if a ∈ l then l else a :: l
instance [DecidableEq α] : HasInsert α (List α) :=
⟨List.insert⟩
protected def union [DecidableEq α] (l₁ l₂ : List α) : List α :=
foldr insert l₂ l₁
instance [DecidableEq α] : HasUnion (List α) :=
⟨List.union⟩
protected def inter [DecidableEq α] (l₁ l₂ : List α) : List α :=
filter (∈ l₂) l₁
instance [DecidableEq α] : HasInter (List α) :=
⟨List.inter⟩
def repeat (a : α) (n : ) : List α :=
n.repeat (λ _ xs, a :: xs) []
def rangeCore : → List → List
| 0 l := l
| (succ n) l := rangeCore n (n :: l)
def range (n : ) : List :=
rangeCore n []
def iota : → List
| 0 := []
| (succ n) := succ n :: iota n
def enumFrom : → List α → List ( × α)
| n [] := nil
| n (x :: xs) := (n, x) :: enumFrom (n + 1) xs
def enum : List α → List ( × α) := enumFrom 0
def last : Π l : List α, l ≠ [] → α
| [] h := absurd rfl h
| [a] h := a
| (a::b::l) h := last (b::l) (λ h, List.noConfusion h)
def ilast [Inhabited α] : List αα
| [] := arbitrary α
| [a] := a
| [a, b] := b
| (a::b::l) := ilast l
def init : List α → List α
| [] := []
| [a] := []
| (a::l) := a::init l
def intersperse (sep : α) : List α → List α
| [] := []
| [x] := [x]
| (x::xs) := x::sep::intersperse 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 ret {α : Type u} (a : α) : List α :=
[a]
protected def lt [HasLess α] : List α → List α → Prop
| [] [] := False
| [] (b::bs) := True
| (a::as) [] := False
| (a::as) (b::bs) := a < b (¬ b < a ∧ lt as bs)
instance [HasLess α] : HasLess (List α) :=
⟨List.lt⟩
instance hasDecidableLt [HasLess α] [h : DecidableRel ((<) : αα → Prop)] : Π l₁ l₂ : List α, Decidable (l₁ < l₂)
| [] [] := isFalse notFalse
| [] (b::bs) := isTrue trivial
| (a::as) [] := isFalse notFalse
| (a::as) (b::bs) :=
match h a b with
| isTrue h₁ := isTrue (Or.inl h₁)
| isFalse h₁ :=
match h b a with
| isTrue h₂ := isFalse (λ h, Or.elim h (λ h, absurd h h₁) (λ ⟨h, _⟩, absurd h₂ h))
| isFalse h₂ :=
match hasDecidableLt as bs with
| isTrue h₃ := isTrue (Or.inr ⟨h₂, h₃⟩)
| isFalse h₃ := isFalse (λ h, Or.elim h (λ h, absurd h h₁) (λ ⟨_, h⟩, absurd h h₃))
@[reducible] protected def le [HasLess α] (a b : List α) : Prop :=
¬ b < a
instance [HasLess α] : HasLessEq (List α) :=
⟨List.le⟩
instance hasDecidableLe [HasLess α] [h : DecidableRel ((<) : αα → Prop)] : Π l₁ l₂ : List α, Decidable (l₁ ≤ l₂) :=
λ a b, Not.Decidable
theorem leEqNotGt [HasLess α] : ∀ l₁ l₂ : List α, (l₁ ≤ l₂) = ¬ (l₂ < l₁) :=
λ l₁ l₂, rfl
theorem ltEqNotGe [HasLess α] [DecidableRel ((<) : αα → Prop)] : ∀ l₁ l₂ : List α, (l₁ < l₂) = ¬ (l₂ ≤ l₁) :=
λ l₁ l₂,
show (l₁ < l₂) = ¬ ¬ (l₁ < l₂), from
Eq.subst (propext (notNotIff (l₁ < l₂))).symm rfl
/-- `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`. -/
def isPrefixOf [DecidableEq α] : List α → List α → Bool
| [] _ := true
| _ [] := false
| (a::as) (b::bs) := toBool (a = b) && isPrefixOf as bs
/-- `isSuffixOf l₁ l₂` returns `true` Iff `l₁` is a suffix of `l₂`. -/
def isSuffixOf [DecidableEq α] (l₁ l₂ : List α) : Bool :=
isPrefixOf l₁.reverse l₂.reverse
end List