Documentation

Init.Data.List.BasicAux

The following functions can't be defined at Init.Data.List.Basic, because they depend on Init.Util, and Init.Util depends on Init.Data.List.Basic.

Alternative getters #

get! #

def List.get! {α : Type u_1} [Inhabited α] (as : List α) (i : Nat) :
α

Returns the i-th element in the list (zero-based).

If the index is out of bounds (i ≥ as.length), this function panics when executed, and returns default. See get? and getD for safer alternatives.

Equations
  • (a :: tail).get! 0 = a
  • (head :: as).get! n.succ = as.get! n
  • x✝.get! x = panicWithPosWithDecl "Init.Data.List.BasicAux" "List.get!" 28 18 "invalid index"
theorem List.get!_nil {α : Type u_1} [Inhabited α] (n : Nat) :
[].get! n = default
theorem List.get!_cons_succ {α : Type u_1} [Inhabited α] (l : List α) (a : α) (n : Nat) :
(a :: l).get! (n + 1) = l.get! n
theorem List.get!_cons_zero {α : Type u_1} [Inhabited α] (l : List α) (a : α) :
(a :: l).get! 0 = a

getLast! #

def List.getLast! {α : Type u_1} [Inhabited α] :
List αα

Returns the last element in the list.

If the list is empty, this function panics when executed, and returns default. See getLast and getLastD for safer alternatives.

Equations
  • [].getLast! = panicWithPosWithDecl "Init.Data.List.BasicAux" "List.getLast!" 44 13 "empty list"
  • (a :: as).getLast! = (a :: as).getLast

Head and tail #

def List.head! {α : Type u_1} [Inhabited α] :
List αα

Returns the first element in the list.

If the list is empty, this function panics when executed, and returns default. See head and headD for safer alternatives.

Equations

tail! #

def List.tail! {α : Type u_1} :
List αList α

Drops the first element of the list.

If the list is empty, this function panics when executed, and returns the empty list. See tail and tailD for safer alternatives.

Equations
@[simp]
theorem List.tail!_cons {α : Type u_1} {a : α} {l : List α} :
(a :: l).tail! = l

partitionM #

@[inline]
def List.partitionM {m : TypeType u_1} {α : Type} [Monad m] (p : αm Bool) (l : List α) :
m (List α × List α)

Monadic generalization of List.partition.

This uses Array.toList and which isn't imported by Init.Data.List.Basic or Init.Data.List.Control.

def posOrNeg (x : Int) : Except String Bool :=
  if x > 0 then pure true
  else if x < 0 then pure false
  else throw "Zero is not positive or negative"

partitionM posOrNeg [-1, 2, 3] = Except.ok ([2, 3], [-1])
partitionM posOrNeg [0, 2, 3] = Except.error "Zero is not positive or negative"
Equations
@[specialize #[]]
def List.partitionM.go {m : TypeType u_1} {α : Type} [Monad m] (p : αm Bool) :
List αArray αArray αm (List α × List α)

Auxiliary for partitionM: partitionM.go p l acc₁ acc₂ returns (acc₁.toList ++ left, acc₂.toList ++ right) if partitionM p l returns (left, right).

Equations

partitionMap #

@[inline]
def List.partitionMap {α : Type u_1} {β : Type u_2} {γ : Type u_3} (f : αβ γ) (l : List α) :
List β × List γ

Given a function f : α → β ⊕ γ, partitionMap f l maps the list by f whilst partitioning the result into a pair of lists, List β × List γ, partitioning the .inl _ into the left list, and the .inr _ into the right List.

partitionMap (id : NatNatNat ⊕ Nat) [inl 0, inr 1, inl 2] = ([0, 2], [1])
Equations
@[specialize #[]]
def List.partitionMap.go {α : Type u_1} {β : Type u_2} {γ : Type u_3} (f : αβ γ) :
List αArray βArray γList β × List γ

Auxiliary for partitionMap: partitionMap.go f l acc₁ acc₂ = (acc₁.toList ++ left, acc₂.toList ++ right) if partitionMap f l = (left, right).

Equations

mapMono #

This is a performance optimization for List.mapM that avoids allocating a new list when the result of each f a is a pointer equal value a.

For verification purposes, List.mapMono = List.map.

@[implemented_by _private.Init.Data.List.BasicAux.0.List.mapMonoMImp]
def List.mapMonoM {m : Type u_1 → Type u_2} {α : Type u_1} [Monad m] (as : List α) (f : αm α) :
m (List α)

Monomorphic List.mapM. The internal implementation uses pointer equality, and does not allocate a new list if the result of each f a is a pointer equal value a.

Equations
  • [].mapMonoM f = pure []
  • (a :: as_1).mapMonoM f = do let __do_liftf a let __do_lift_1as_1.mapMonoM f pure (__do_lift :: __do_lift_1)
def List.mapMono {α : Type u_1} (as : List α) (f : αα) :
List α
Equations
  • as.mapMono f = (as.mapMonoM f).run

Additional lemmas required for bootstrapping Array. #

theorem List.getElem_append_left {α : Type u_1} {i : Nat} {as bs : List α} (h : i < as.length) {h' : i < (as ++ bs).length} :
(as ++ bs)[i] = as[i]
theorem List.getElem_append_right {α : Type u_1} {as bs : List α} {i : Nat} (h₁ : as.length i) {h₂ : i < (as ++ bs).length} :
(as ++ bs)[i] = bs[i - as.length]
theorem List.get_last {α : Type u_1} {a : α} {as : List α} {i : Fin (as ++ [a]).length} (h : ¬i < as.length) :
(as ++ [a]).get i = a
theorem List.sizeOf_lt_of_mem {α : Type u_1} {a : α} [SizeOf α] {as : List α} (h : a as) :

This tactic, added to the decreasing_trivial toolbox, proves that sizeOf a < sizeOf as when a ∈ as, which is useful for well founded recursions over a nested inductive like inductive T | mk : List T → T.

Equations
theorem List.append_cancel_left {α : Type u_1} {as bs cs : List α} (h : as ++ bs = as ++ cs) :
bs = cs
theorem List.append_cancel_right {α : Type u_1} {as bs cs : List α} (h : as ++ bs = cs ++ bs) :
as = cs
@[simp]
theorem List.append_cancel_left_eq {α : Type u_1} (as bs cs : List α) :
(as ++ bs = as ++ cs) = (bs = cs)
@[simp]
theorem List.append_cancel_right_eq {α : Type u_1} (as bs cs : List α) :
(as ++ bs = cs ++ bs) = (as = cs)
theorem List.sizeOf_get {α : Type u_1} [SizeOf α] (as : List α) (i : Fin as.length) :
sizeOf (as.get i) < sizeOf as
theorem List.le_antisymm {α : Type u_1} [LT α] [s : Std.Antisymm fun (x1 x2 : α) => ¬x1 < x2] {as bs : List α} (h₁ : as bs) (h₂ : bs as) :
as = bs
instance List.instAntisymmLeOfNotLt {α : Type u_1} [LT α] [Std.Antisymm fun (x1 x2 : α) => ¬x1 < x2] :
Std.Antisymm fun (x1 x2 : List α) => x1 x2
Equations
  • =