lean4-htt/src/Init/Data/List/Basic.lean
Leonardo de Moura cca3bad0bb feat: add Prelude.lean
`Prelude.lean` has no dependencies, and
at the end of `Prelude`, the `syntax` and `macro` commands are operational.
2020-11-10 18:08:18 -08:00

338 lines
10 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
import 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
def reverseAux : List α → List α → List α
| [], r => r
| a::l, r => reverseAux l (a::r)
def reverse (as : List α) :List α :=
reverseAux as []
protected def append (as bs : List α) : List α :=
reverseAux as.reverse bs
instance : Append (List α) := ⟨List.append⟩
theorem reverseAuxReverseAuxNil : ∀ (as bs : List α), reverseAux (reverseAux as bs) [] = reverseAux bs as
| [], bs => rfl
| a::as, bs =>
show reverseAux (reverseAux as (a::bs)) [] = reverseAux bs (a::as) from
reverseAuxReverseAuxNil as (a::bs)
theorem nilAppend (as : List α) : [] ++ as = as := rfl
theorem appendNil (as : List α) : as ++ [] = as :=
show reverseAux (reverseAux as []) [] = as from
reverseAuxReverseAuxNil as []
theorem reverseAuxReverseAux : ∀ (as bs cs : List α), reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs)
| [], bs, cs => rfl
| a::as, bs, cs => by
rw [reverseAuxReverseAux as (a::bs) cs, reverseAuxReverseAux as [a] cs]
exact rfl
theorem consAppend (a : α) (as bs : List α) : (a::as) ++ bs = a::(as ++ bs) :=
reverseAuxReverseAux as [a] bs
theorem appendAssoc : ∀ (as bs cs : List α), (as ++ bs) ++ cs = as ++ (bs ++ cs)
| [], bs, cs => rfl
| a::as, bs, cs => by
show ((a::as) ++ bs) ++ cs = (a::as) ++ (bs ++ cs)
rw [consAppend, consAppend, appendAssoc, consAppend]
exact rfl
instance : EmptyCollection (List α) := ⟨List.nil⟩
protected def erase {α} [BEq α] : List αα → List α
| [], b => []
| a::as, b => match a == b with
| true => as
| false => a :: List.erase as b
def eraseIdx : List α → Nat → List α
| [], _ => []
| a::as, 0 => as
| a::as, n+1 => a :: eraseIdx as n
def lengthAux : List α → Nat → Nat
| [], n => n
| a::as, n => lengthAux as (n+1)
def length (as : List α) : Nat :=
lengthAux as 0
def isEmpty : List α → Bool
| [] => true
| _ :: _ => false
def set : List α → Nat → α → List α
| a::as, 0, b => b::as
| a::as, n+1, b => a::(set as n b)
| [], _, _ => []
@[specialize] def map (f : α → β) : List α → List β
| [] => []
| a::as => f a :: map f as
@[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
@[specialize] def filterAux (p : α → Bool) : List α → List α → List α
| [], rs => rs.reverse
| a::as, rs => match p a with
| true => filterAux p as (a::rs)
| false => filterAux p as rs
@[inline] def filter (p : α → Bool) (as : List α) : List α :=
filterAux p as []
@[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
| flase => 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
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
| n+1, [] => []
| n+1, a::as => drop n as
def take : Nat → List α → List α
| 0, a => []
| n+1, [] => []
| n+1, a::as => a :: take n as
@[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 replicate (n : Nat) (a : α) : List α :=
n.repeat (fun xs => a :: xs) []
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 enumFrom : Nat → List α → List (Nat × α)
| n, [] => nil
| n, x :: xs => (n, x) :: enumFrom (n + 1) xs
def enum : List α → List (Nat × α) := enumFrom 0
def init : List α → List α
| [] => []
| [a] => []
| 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 List.Less [HasLess α] : List α → List α → Prop
| nil (b : α) (bs : List α) : Less [] (b::bs)
| head {a : α} (as : List α) {b : α} (bs : List α) : a < b → Less (a::as) (b::bs)
| tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → Less as bs → Less (a::as) (b::bs)
instance less [HasLess α] : HasLess (List α) := ⟨List.Less⟩
instance hasDecidableLt [HasLess α] [h : DecidableRel (α:=α) (·<·)] : (l₁ l₂ : List α) → Decidable (l₁ < l₂)
| [], [] => isFalse (fun h => nomatch h)
| [], b::bs => isTrue (List.Less.nil _ _)
| a::as, [] => isFalse (fun h => nomatch h)
| a::as, b::bs =>
match h a b with
| isTrue h₁ => isTrue (List.Less.head _ _ h₁)
| isFalse h₁ =>
match h b a with
| isTrue h₂ => isFalse (fun h => match h with
| List.Less.head _ _ h₁' => absurd h₁' h₁
| List.Less.tail _ h₂' _ => absurd h₂ h₂')
| isFalse h₂ =>
match hasDecidableLt as bs with
| isTrue h₃ => isTrue (List.Less.tail h₁ h₂ h₃)
| isFalse h₃ => isFalse (fun h => match h with
| List.Less.head _ _ h₁' => absurd h₁' h₁
| List.Less.tail _ _ h₃' => absurd h₃' h₃)
@[reducible] protected def LessEq [HasLess α] (a b : List α) : Prop := ¬ b < a
instance lessEq [HasLess α] : HasLessEq (List α) := ⟨List.LessEq⟩
instance [HasLess α] [h : DecidableRel ((· < ·) : αα → Prop)] : (l₁ l₂ : List α) → Decidable (l₁ ≤ l₂) :=
fun a b => inferInstanceAs (Decidable (Not _))
/-- `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`. -/
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₂`. -/
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
| _, _, 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⟩
end List