Motivation: use same separator used in lambda expressions as in other programming languages.
370 lines
12 KiB
Text
370 lines
12 KiB
Text
/-
|
||
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 (fun h => List.noConfusion h)
|
||
| [] (b::bs) := isFalse (fun 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 (fun h => List.noConfusion h (fun _ habs => absurd habs nabs))
|
||
| isFalse nab => isFalse (fun h => List.noConfusion h (fun hab _ => absurd hab nab))
|
||
|
||
instance [DecidableEq α] : DecidableEq (List α) :=
|
||
{decEq := List.hasDecEq}
|
||
|
||
def reverseAux : List α → List α → List α
|
||
| [] r := r
|
||
| (a::l) r := reverseAux l (a::r)
|
||
|
||
def reverse : List α → List α :=
|
||
fun l => reverseAux l []
|
||
|
||
protected def append (as bs : List α) : List α :=
|
||
reverseAux as.reverse bs
|
||
|
||
instance : HasAppend (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 :=
|
||
Eq.trans
|
||
(reverseAuxReverseAux as (a::bs) cs)
|
||
(congrArg (fun b => reverseAux bs b) (reverseAuxReverseAux as [a] cs).symm)
|
||
|
||
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 :=
|
||
show ((a::as) ++ bs) ++ cs = (a::as) ++ (bs ++ cs) from
|
||
have h₁ : ((a::as) ++ bs) ++ cs = a::(as++bs) ++ cs from congrArg (fun ds => ds ++ 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 (fun 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 (fun 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
|
||
|
||
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 get [Inhabited α] : Nat → List α → α
|
||
| 0 (a::as) := a
|
||
| (n+1) (a::as) := get n as
|
||
| _ _ := default α
|
||
|
||
def getOpt : Nat → List α → Option α
|
||
| 0 (a::as) := some a
|
||
| (n+1) (a::as) := getOpt n as
|
||
| _ _ := none
|
||
|
||
def set : List α → Nat → α → List α
|
||
| (a::as) 0 b := b::as
|
||
| (a::as) (n+1) b := a::(set as n b)
|
||
| [] _ _ := []
|
||
|
||
def head [Inhabited α] : List α → α
|
||
| [] := default α
|
||
| (a::_) := a
|
||
|
||
def tail : List α → List α
|
||
| [] := []
|
||
| (a::as) := as
|
||
|
||
@[specialize] def map (f : α → β) : List α → List β
|
||
| [] := []
|
||
| (a::as) := f a :: map as
|
||
|
||
@[specialize] def map₂ (f : α → β → γ) : List α → List β → List γ
|
||
| [] _ := []
|
||
| _ [] := []
|
||
| (a::as) (b::bs) := f a b :: map₂ 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 as
|
||
| some b => b :: filterMap as
|
||
|
||
@[specialize] def filterAux (p : α → Bool) : List α → List α → List α
|
||
| [] rs := rs.reverse
|
||
| (a::as) rs := match p a with
|
||
| true => filterAux as (a::rs)
|
||
| false => filterAux 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 as (a::bs, cs)
|
||
| false => partitionAux 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 l
|
||
| false => a::l
|
||
|
||
def find (p : α → Bool) : List α → Option α
|
||
| [] := none
|
||
| (a::as) := match p a with
|
||
| true => some a
|
||
| false => find as
|
||
|
||
def elem [HasBeq α] (a : α) : List α → Bool
|
||
| [] := false
|
||
| (b::bs) := match a == b with
|
||
| true => true
|
||
| false => elem bs
|
||
|
||
def notElem [HasBeq α] (a : α) (as : List α) : Bool :=
|
||
!(as.elem a)
|
||
|
||
@[specialize] def spanAux (p : α → Bool) : List α → List α → List α × List α
|
||
| [] rs := (rs.reverse, [])
|
||
| (a::as) rs := match p a with
|
||
| true => spanAux as (a::rs)
|
||
| false => (rs.reverse, a::as)
|
||
|
||
@[inline] def span (p : α → Bool) (as : List α) : List α × List α :=
|
||
spanAux p as []
|
||
|
||
def lookup [HasBeq α] : α → List (α × β) → Option β
|
||
| _ [] := none
|
||
| a ((k,b)::es) := match a == k with
|
||
| true => some b
|
||
| false => lookup a es
|
||
|
||
def removeAll [HasBeq α] (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 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 ≠ [] → α
|
||
| [] h := absurd rfl h
|
||
| [a] _ := a
|
||
| (a :: as@(_::_)) _ := f a (foldr1 as (fun h => List.noConfusion h))
|
||
|
||
@[specialize] def foldr1Opt (f : α → α → α) : List α → Option α
|
||
| [] := none
|
||
| (a :: as) := some $ foldr1 f (a :: as) (fun h => List.noConfusion h)
|
||
|
||
@[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 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⟩
|
||
|
||
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 getLastOfNonNil : ∀ (as : List α), as ≠ [] → α
|
||
| [] h := absurd rfl h
|
||
| [a] h := a
|
||
| (a::b::as) h := getLastOfNonNil (b::as) (fun h => List.noConfusion h)
|
||
|
||
def getLast [Inhabited α] : List α → α
|
||
| [] := arbitrary α
|
||
| (a::as) := getLastOfNonNil (a::as) (fun h => List.noConfusion h)
|
||
|
||
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 pure {α : Type u} (a : α) : List α :=
|
||
[a]
|
||
|
||
inductive 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 [HasLess α] : HasLess (List α) :=
|
||
⟨List.Less⟩
|
||
|
||
instance hasDecidableLt [HasLess α] [h : DecidableRel HasLess.Less] : ∀ l₁ l₂ : List α, Decidable (l₁ < l₂)
|
||
| [] [] := isFalse (fun h => match h with end)
|
||
| [] (b::bs) := isTrue (Less.nil _ _)
|
||
| (a::as) [] := isFalse (fun h => match h with end)
|
||
| (a::as) (b::bs) :=
|
||
match h a b with
|
||
| isTrue h₁ => isTrue (Less.head _ _ h₁)
|
||
| isFalse h₁ =>
|
||
match h b a with
|
||
| isTrue h₂ => isFalse (fun h => match h with
|
||
| Less.head _ _ h₁' => absurd h₁' h₁
|
||
| Less.tail _ h₂' _ => absurd h₂ h₂')
|
||
| isFalse h₂ =>
|
||
match hasDecidableLt as bs with
|
||
| isTrue h₃ => isTrue (Less.tail h₁ h₂ h₃)
|
||
| isFalse h₃ => isFalse (fun h => match h with
|
||
| Less.head _ _ h₁' => absurd h₁' h₁
|
||
| Less.tail _ _ h₃' => absurd h₃' h₃)
|
||
|
||
@[reducible] protected def LessEq [HasLess α] (a b : List α) : Prop :=
|
||
¬ b < a
|
||
|
||
instance [HasLess α] : HasLessEq (List α) :=
|
||
⟨List.LessEq⟩
|
||
|
||
instance hasDecidableLe [HasLess α] [h : DecidableRel (HasLess.Less : α → α → Prop)] : ∀ l₁ l₂ : List α, Decidable (l₁ ≤ l₂) :=
|
||
fun a b => Not.Decidable
|
||
|
||
/-- `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`. -/
|
||
def isPrefixOf [HasBeq α] : 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 [HasBeq α] (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
|
||
end List
|