doc-next-gen

Mathlib.Data.List.Basic

Module docstring

{"# Basic properties of lists ","### mem ","### length ","### set-theoretic notation of lists ","### bounded quantifiers over lists ","### list subset ","### append ","### replicate ","### pure ","### bind ","### concat ","### reverse ","### getLast ","### getLast? ","### head(!?) and tail ","### sublists ","### indexOf ","### nth element ","### map ","### foldl, foldr ","### foldlM, foldrM, mapM ","### intersperse ","### map for partial functions ","### filter ","### filterMap ","### filter ","### eraseP ","### erase ","### diff ","### Forall ","### Miscellaneous lemmas "}

List.uniqueOfIsEmpty instance
[IsEmpty α] : Unique (List α)
Full source
/-- There is only one list of an empty type -/
instance uniqueOfIsEmpty [IsEmpty α] : Unique (List α) :=
  { instInhabitedList with
    uniq := fun l =>
      match l with
      | [] => rfl
      | a :: _ => isEmptyElim a }
Uniqueness of Lists over Empty Types
Informal description
For any empty type $\alpha$, the type of lists over $\alpha$ has exactly one element (the empty list).
List.instLawfulIdentityAppendNil_mathlib instance
: Std.LawfulIdentity (α := List α) Append.append []
Full source
instance : Std.LawfulIdentity (α := List α) Append.append [] where
  left_id := nil_append
  right_id := append_nil
Empty List as Identity for Append
Informal description
The empty list `[]` is a lawful identity element for the append operation `++` on lists. That is, for any list `l`, we have `[] ++ l = l` and `l ++ [] = l`.
List.instAssociativeAppend_mathlib instance
: Std.Associative (α := List α) Append.append
Full source
instance : Std.Associative (α := List α) Append.append where
  assoc := append_assoc
Associativity of List Append
Informal description
The append operation on lists is associative. That is, for any three lists $l_1, l_2, l_3$ of type $\alpha$, we have $(l_1 \mathbin{+\!\!\!+} l_2) \mathbin{+\!\!\!+} l_3 = l_1 \mathbin{+\!\!\!+} (l_2 \mathbin{+\!\!\!+} l_3)$.
List.cons_injective theorem
{a : α} : Injective (cons a)
Full source
@[simp] theorem cons_injective {a : α} : Injective (cons a) := fun _ _ => tail_eq_of_cons_eq
Injectivity of List Cons Operation
Informal description
For any element $a$ of type $\alpha$, the function that prepends $a$ to a list (i.e., the function $\lambda l, a :: l$) is injective. In other words, if $a :: l_1 = a :: l_2$ for lists $l_1, l_2$, then $l_1 = l_2$.
List.singleton_injective theorem
: Injective fun a : α => [a]
Full source
theorem singleton_injective : Injective fun a : α => [a] := fun _ _ h => (cons_eq_cons.1 h).1
Injectivity of the Singleton List Construction
Informal description
The function that maps an element $a$ of type $\alpha$ to the singleton list $[a]$ is injective. That is, for any $a_1, a_2 \in \alpha$, if $[a_1] = [a_2]$, then $a_1 = a_2$.
List.set_of_mem_cons theorem
(l : List α) (a : α) : {x | x ∈ a :: l} = insert a {x | x ∈ l}
Full source
theorem set_of_mem_cons (l : List α) (a : α) : { x | x ∈ a :: l } = insert a { x | x ∈ l } :=
  Set.ext fun _ => mem_cons
Set Representation of Elements in a Cons List: $\{x \mid x \in a :: l\} = \{a\} \cup \{x \mid x \in l\}$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the set $\{x \mid x \in a :: l\}$ (the set of elements in the list obtained by prepending $a$ to $l$) is equal to the set obtained by inserting $a$ into the set $\{x \mid x \in l\}$ (the set of elements in $l$).
List.mem_pair theorem
{a b c : α} : a ∈ [b, c] ↔ a = b ∨ a = c
Full source
lemma mem_pair {a b c : α} : a ∈ [b, c]a ∈ [b, c] ↔ a = b ∨ a = c := by
  rw [mem_cons, mem_singleton]
Membership in Two-Element List Equals Either Element
Informal description
For any elements $a, b, c$ of type $\alpha$, the element $a$ belongs to the list $[b, c]$ if and only if $a$ is equal to $b$ or $a$ is equal to $c$.
List.mem_map_of_injective theorem
{f : α → β} (H : Injective f) {a : α} {l : List α} : f a ∈ map f l ↔ a ∈ l
Full source
@[simp 1100, nolint simpNF]
theorem mem_map_of_injective {f : α → β} (H : Injective f) {a : α} {l : List α} :
    f a ∈ map f lf a ∈ map f l ↔ a ∈ l :=
  ⟨fun m => let ⟨_, m', e⟩ := exists_of_mem_map m; H e ▸ m', mem_map_of_mem⟩
Membership Preservation under Injective Mapping
Informal description
For any injective function $f : \alpha \to \beta$, element $a \in \alpha$, and list $l$ of elements of type $\alpha$, the image $f(a)$ belongs to the mapped list $\mathrm{map}\,f\,l$ if and only if $a$ belongs to $l$.
Function.Involutive.exists_mem_and_apply_eq_iff theorem
{f : α → α} (hf : Function.Involutive f) (x : α) (l : List α) : (∃ y : α, y ∈ l ∧ f y = x) ↔ f x ∈ l
Full source
@[simp]
theorem _root_.Function.Involutive.exists_mem_and_apply_eq_iff {f : α → α}
    (hf : Function.Involutive f) (x : α) (l : List α) : (∃ y : α, y ∈ l ∧ f y = x) ↔ f x ∈ l :=
  ⟨by rintro ⟨y, h, rfl⟩; rwa [hf y], fun h => ⟨f x, h, hf _⟩⟩
Characterization of Membership under Involutive Functions: $(\exists y \in l, f(y) = x) \leftrightarrow f(x) \in l$
Informal description
For any involutive function $f : \alpha \to \alpha$ (i.e., $f(f(x)) = x$ for all $x \in \alpha$), an element $x \in \alpha$, and a list $l$ of elements of $\alpha$, the following are equivalent: 1. There exists an element $y \in l$ such that $f(y) = x$. 2. The element $f(x)$ belongs to $l$. In symbols: \[ (\exists y \in l, f(y) = x) \leftrightarrow f(x) \in l. \]
List.mem_map_of_involutive theorem
{f : α → α} (hf : Involutive f) {a : α} {l : List α} : a ∈ map f l ↔ f a ∈ l
Full source
theorem mem_map_of_involutive {f : α → α} (hf : Involutive f) {a : α} {l : List α} :
    a ∈ map f la ∈ map f l ↔ f a ∈ l := by rw [mem_map, hf.exists_mem_and_apply_eq_iff]
Membership in Mapped List under Involutive Function: $a \in \mathrm{map}\,f\,l \leftrightarrow f(a) \in l$
Informal description
For any involutive function $f : \alpha \to \alpha$ (i.e., $f(f(x)) = x$ for all $x \in \alpha$), an element $a \in \alpha$, and a list $l$ of elements of type $\alpha$, the element $a$ belongs to the mapped list $\mathrm{map}\,f\,l$ if and only if $f(a)$ belongs to $l$. In symbols: \[ a \in \mathrm{map}\,f\,l \leftrightarrow f(a) \in l. \]
List.exists_of_length_succ theorem
{n} : ∀ l : List α, l.length = n + 1 → ∃ h t, l = h :: t
Full source
theorem exists_of_length_succ {n} : ∀ l : List α, l.length = n + 1 → ∃ h t, l = h :: t
  | [], H => absurd H.symm <| succ_ne_zero n
  | h :: t, _ => ⟨h, t, rfl⟩
Decomposition of Nonempty Lists by Length
Informal description
For any natural number $n$ and any list $l$ of elements of type $\alpha$, if the length of $l$ is equal to $n + 1$, then there exists a head element $h$ and a tail list $t$ such that $l$ can be expressed as the cons (construction) of $h$ and $t$, i.e., $l = h :: t$.
List.length_injective_iff theorem
: Injective (List.length : List α → ℕ) ↔ Subsingleton α
Full source
@[simp] lemma length_injective_iff : InjectiveInjective (List.length : List α → ℕ) ↔ Subsingleton α := by
  constructor
  · intro h; refine ⟨fun x y => ?_⟩; (suffices [x] = [y] by simpa using this); apply h; rfl
  · intros hα l1 l2 hl
    induction l1 generalizing l2 <;> cases l2
    · rfl
    · cases hl
    · cases hl
    · next ih _ _ =>
      congr
      · subsingleton
      · apply ih; simpa using hl
Injectivity of List Length Function and Subsingleton Type Condition
Informal description
The length function on lists is injective if and only if the type $\alpha$ is a subsingleton (i.e., all elements of $\alpha$ are equal). In other words, the map $\text{length} : \text{List } \alpha \to \mathbb{N}$ is injective precisely when $\alpha$ has at most one distinct element.
List.length_injective theorem
[Subsingleton α] : Injective (length : List α → ℕ)
Full source
@[simp default+1] -- Raise priority above `length_injective_iff`.
lemma length_injective [Subsingleton α] : Injective (length : List α → ) :=
  length_injective_iff.mpr inferInstance
Injectivity of List Length for Subsingleton Types
Informal description
If the type $\alpha$ is a subsingleton (i.e., all elements of $\alpha$ are equal), then the length function on lists of type $\alpha$ is injective. In other words, for any lists $l_1, l_2 : \text{List } \alpha$, if $\text{length}(l_1) = \text{length}(l_2)$, then $l_1 = l_2$.
List.length_eq_two theorem
{l : List α} : l.length = 2 ↔ ∃ a b, l = [a, b]
Full source
theorem length_eq_two {l : List α} : l.length = 2 ↔ ∃ a b, l = [a, b] :=
  ⟨fun _ => let [a, b] := l; ⟨a, b, rfl⟩, fun ⟨_, _, e⟩ => e ▸ rfl⟩
List Length Two Characterization: $\text{length}(l) = 2 \leftrightarrow \exists a b, l = [a, b]$
Informal description
For any list $l$ of elements of type $\alpha$, the length of $l$ is equal to 2 if and only if there exist elements $a, b \in \alpha$ such that $l$ is equal to the list $[a, b]$.
List.length_eq_three theorem
{l : List α} : l.length = 3 ↔ ∃ a b c, l = [a, b, c]
Full source
theorem length_eq_three {l : List α} : l.length = 3 ↔ ∃ a b c, l = [a, b, c] :=
  ⟨fun _ => let [a, b, c] := l; ⟨a, b, c, rfl⟩, fun ⟨_, _, _, e⟩ => e ▸ rfl⟩
List Length Three Characterization: $\text{length}(l) = 3 \leftrightarrow \exists a b c, l = [a, b, c]$
Informal description
For any list $l$ of elements of type $\alpha$, the length of $l$ is equal to 3 if and only if there exist elements $a, b, c \in \alpha$ such that $l$ is equal to the list $[a, b, c]$.
List.instSingletonList instance
: Singleton α (List α)
Full source
instance instSingletonList : Singleton α (List α) := ⟨fun x => [x]⟩
Singleton List Construction
Informal description
For any type $\alpha$, there is a canonical way to construct a singleton list containing a given element $a \in \alpha$, namely $[a]$.
List.instInsertOfDecidableEq_mathlib instance
[DecidableEq α] : Insert α (List α)
Full source
instance [DecidableEq α] : Insert α (List α) := ⟨List.insert⟩
Insertion Operation for Lists with Decidable Equality
Informal description
For any type $\alpha$ with decidable equality, there is an insertion operation that allows inserting an element into a list of $\alpha$.
List.instLawfulSingleton_mathlib instance
[DecidableEq α] : LawfulSingleton α (List α)
Full source
instance [DecidableEq α] : LawfulSingleton α (List α) :=
  { insert_empty_eq := fun x =>
      show (if x ∈ ([] : List α) then [] else [x]) = [x] from if_neg not_mem_nil }
Lawful Singleton Properties for Lists with Decidable Equality
Informal description
For any type $\alpha$ with decidable equality, the singleton list construction $[a]$ for $a \in \alpha$ satisfies the lawful singleton properties.
List.singleton_eq theorem
(x : α) : ({ x } : List α) = [x]
Full source
theorem singleton_eq (x : α) : ({x} : List α) = [x] :=
  rfl
Singleton List Equality: $\{x\} = [x]$
Informal description
For any element $x$ of type $\alpha$, the singleton list $\{x\}$ is equal to the list $[x]$.
List.insert_neg theorem
[DecidableEq α] {x : α} {l : List α} (h : x ∉ l) : Insert.insert x l = x :: l
Full source
theorem insert_neg [DecidableEq α] {x : α} {l : List α} (h : x ∉ l) :
    Insert.insert x l = x :: l :=
  insert_of_not_mem h
Insertion of Absent Element into List
Informal description
For any type $\alpha$ with decidable equality, given an element $x \in \alpha$ and a list $l$ of elements of $\alpha$ such that $x \notin l$, inserting $x$ into $l$ results in the list $x :: l$.
List.insert_pos theorem
[DecidableEq α] {x : α} {l : List α} (h : x ∈ l) : Insert.insert x l = l
Full source
theorem insert_pos [DecidableEq α] {x : α} {l : List α} (h : x ∈ l) : Insert.insert x l = l :=
  insert_of_mem h
Insertion of Present Element Preserves List
Informal description
For any type $\alpha$ with decidable equality, given an element $x \in \alpha$ and a list $l$ of elements of $\alpha$ such that $x \in l$, inserting $x$ into $l$ results in the original list $l$.
List.doubleton_eq theorem
[DecidableEq α] {x y : α} (h : x ≠ y) : ({ x, y } : List α) = [x, y]
Full source
theorem doubleton_eq [DecidableEq α] {x y : α} (h : x ≠ y) : ({x, y} : List α) = [x, y] := by
  rw [insert_neg, singleton_eq]
  rwa [singleton_eq, mem_singleton]
Doubleton List Equality: $\{x, y\} = [x, y]$ for Distinct Elements
Informal description
For any type $\alpha$ with decidable equality and any two distinct elements $x, y \in \alpha$, the doubleton list $\{x, y\}$ is equal to the two-element list $[x, y]$.
List.forall_mem_of_forall_mem_cons theorem
{p : α → Prop} {a : α} {l : List α} (h : ∀ x ∈ a :: l, p x) : ∀ x ∈ l, p x
Full source
theorem forall_mem_of_forall_mem_cons {p : α → Prop} {a : α} {l : List α} (h : ∀ x ∈ a :: l, p x) :
    ∀ x ∈ l, p x := (forall_mem_cons.1 h).2
Universal Property of List Tail
Informal description
For any predicate $p$ on elements of type $\alpha$, if $p(x)$ holds for every element $x$ in the list $a :: l$ (i.e., the list formed by prepending $a$ to $l$), then $p(x)$ holds for every element $x$ in the list $l$.
List.exists_mem_cons_of theorem
{p : α → Prop} {a : α} (l : List α) (h : p a) : ∃ x ∈ a :: l, p x
Full source
theorem exists_mem_cons_of {p : α → Prop} {a : α} (l : List α) (h : p a) : ∃ x ∈ a :: l, p x :=
  ⟨a, mem_cons_self, h⟩
Existence of Satisfying Element in Prepended List
Informal description
For any predicate $p$ on elements of type $\alpha$, any element $a$ of type $\alpha$, and any list $l$ of elements of type $\alpha$, if $p(a)$ holds, then there exists an element $x$ in the list $a :: l$ (i.e., the list obtained by prepending $a$ to $l$) such that $p(x)$ holds.
List.exists_mem_cons_of_exists theorem
{p : α → Prop} {a : α} {l : List α} : (∃ x ∈ l, p x) → ∃ x ∈ a :: l, p x
Full source
theorem exists_mem_cons_of_exists {p : α → Prop} {a : α} {l : List α} : (∃ x ∈ l, p x) →
    ∃ x ∈ a :: l, p x :=
  fun ⟨x, xl, px⟩ => ⟨x, mem_cons_of_mem _ xl, px⟩
Existence in Prepended List from Original List
Informal description
For any predicate $p$ on elements of type $\alpha$, any element $a \in \alpha$, and any list $l$ of elements of type $\alpha$, if there exists an element $x \in l$ such that $p(x)$ holds, then there exists an element $x$ in the list $a :: l$ (i.e., the list constructed by prepending $a$ to $l$) such that $p(x)$ holds.
List.or_exists_of_exists_mem_cons theorem
{p : α → Prop} {a : α} {l : List α} : (∃ x ∈ a :: l, p x) → p a ∨ ∃ x ∈ l, p x
Full source
theorem or_exists_of_exists_mem_cons {p : α → Prop} {a : α} {l : List α} : (∃ x ∈ a :: l, p x) →
    p a ∨ ∃ x ∈ l, p x :=
  fun ⟨x, xal, px⟩ =>
    Or.elim (eq_or_mem_of_mem_cons xal) (fun h : x = a => by rw [← h]; left; exact px)
      fun h : x ∈ l => Or.inr ⟨x, h, px⟩
Existence in Prepended List Implies Either Head or Existence in Tail
Informal description
For any predicate $p$ on elements of type $\alpha$, any element $a$ of type $\alpha$, and any list $l$ of elements of type $\alpha$, if there exists an element $x$ in the list $a :: l$ (i.e., the list obtained by prepending $a$ to $l$) such that $p(x)$ holds, then either $p(a)$ holds or there exists an element $x$ in $l$ such that $p(x)$ holds.
List.exists_mem_cons_iff theorem
(p : α → Prop) (a : α) (l : List α) : (∃ x ∈ a :: l, p x) ↔ p a ∨ ∃ x ∈ l, p x
Full source
theorem exists_mem_cons_iff (p : α → Prop) (a : α) (l : List α) :
    (∃ x ∈ a :: l, p x) ↔ p a ∨ ∃ x ∈ l, p x :=
  Iff.intro or_exists_of_exists_mem_cons fun h =>
    Or.elim h (exists_mem_cons_of l) exists_mem_cons_of_exists
Existence in Prepended List Equivalent to Either Head or Existence in Tail
Informal description
For any predicate $p$ on elements of type $\alpha$, any element $a \in \alpha$, and any list $l$ of elements of type $\alpha$, there exists an element $x$ in the list $a :: l$ (the list obtained by prepending $a$ to $l$) such that $p(x)$ holds if and only if either $p(a)$ holds or there exists an element $x \in l$ such that $p(x)$ holds.
List.cons_subset_of_subset_of_mem theorem
{a : α} {l m : List α} (ainm : a ∈ m) (lsubm : l ⊆ m) : a :: l ⊆ m
Full source
theorem cons_subset_of_subset_of_mem {a : α} {l m : List α}
    (ainm : a ∈ m) (lsubm : l ⊆ m) : a::la::l ⊆ m :=
  cons_subset.2 ⟨ainm, lsubm⟩
Subset Preservation Under Cons Operation
Informal description
For any element $a$ and lists $l$, $m$ of type $\alpha$, if $a$ is an element of $m$ and $l$ is a subset of $m$, then the list obtained by prepending $a$ to $l$ (denoted $a :: l$) is also a subset of $m$.
List.append_subset_of_subset_of_subset theorem
{l₁ l₂ l : List α} (l₁subl : l₁ ⊆ l) (l₂subl : l₂ ⊆ l) : l₁ ++ l₂ ⊆ l
Full source
theorem append_subset_of_subset_of_subset {l₁ l₂ l : List α} (l₁subl : l₁ ⊆ l) (l₂subl : l₂ ⊆ l) :
    l₁ ++ l₂ ⊆ l :=
  fun _ h ↦ (mem_append.1 h).elim (@l₁subl _) (@l₂subl _)
Concatenation Preserves Subset Relation for Lists
Informal description
For any lists $l₁$, $l₂$, and $l$ of elements of type $\alpha$, if $l₁$ is a subset of $l$ and $l₂$ is a subset of $l$, then the concatenation $l₁ ++ l₂$ is also a subset of $l$.
List.map_subset_iff theorem
{l₁ l₂ : List α} (f : α → β) (h : Injective f) : map f l₁ ⊆ map f l₂ ↔ l₁ ⊆ l₂
Full source
theorem map_subset_iff {l₁ l₂ : List α} (f : α → β) (h : Injective f) :
    mapmap f l₁ ⊆ map f l₂map f l₁ ⊆ map f l₂ ↔ l₁ ⊆ l₂ := by
  refine ⟨?_, map_subset f⟩; intro h2 x hx
  rcases mem_map.1 (h2 (mem_map_of_mem hx)) with ⟨x', hx', hxx'⟩
  cases h hxx'; exact hx'
Subset Preservation Under Injective Mapping for Lists
Informal description
For any two lists $l₁$ and $l₂$ of elements of type $\alpha$, and an injective function $f : \alpha \to \beta$, the image of $l₁$ under $f$ is a subset of the image of $l₂$ under $f$ if and only if $l₁$ is a subset of $l₂$. In other words: $$\{f(x) \mid x \in l₁\} \subseteq \{f(x) \mid x \in l₂\} \iff l₁ \subseteq l₂$$
List.append_eq_has_append theorem
{L₁ L₂ : List α} : List.append L₁ L₂ = L₁ ++ L₂
Full source
theorem append_eq_has_append {L₁ L₂ : List α} : List.append L₁ L₂ = L₁ ++ L₂ :=
  rfl
Equality of List Append and Concatenation
Informal description
For any two lists $L₁$ and $L₂$ of elements of type $\alpha$, the function `List.append` applied to $L₁$ and $L₂$ is equal to the concatenation $L₁ ++ L₂$ of the two lists.
List.append_right_injective theorem
(s : List α) : Injective fun t ↦ s ++ t
Full source
theorem append_right_injective (s : List α) : Injective fun t ↦ s ++ t :=
  fun _ _ ↦ append_cancel_left
Right Concatenation with Fixed List is Injective
Informal description
For any list $s$ of elements of type $\alpha$, the function $t \mapsto s \mathbin{+\!\!+} t$ is injective, where $\mathbin{+\!\!+}$ denotes list concatenation. In other words, if $s \mathbin{+\!\!+} t_1 = s \mathbin{+\!\!+} t_2$ for lists $t_1, t_2$, then $t_1 = t_2$.
List.append_left_injective theorem
(t : List α) : Injective fun s ↦ s ++ t
Full source
theorem append_left_injective (t : List α) : Injective fun s ↦ s ++ t :=
  fun _ _ ↦ append_cancel_right
Right Concatenation Preserves Distinctness of Lists
Informal description
For any list $t$ of elements of type $\alpha$, the function $s \mapsto s ++ t$ that concatenates $t$ to the right of any list $s$ is injective. That is, for any lists $s_1, s_2$ of type $\alpha$, if $s_1 ++ t = s_2 ++ t$, then $s_1 = s_2$.
List.replicate_add theorem
(m n) (a : α) : replicate (m + n) a = replicate m a ++ replicate n a
Full source
theorem replicate_add (m n) (a : α) : replicate (m + n) a = replicate m a ++ replicate n a := by
  rw [replicate_append_replicate]
Additivity of List Replication: $\text{replicate}(m + n, a) = \text{replicate}(m, a) +\!\!\!+ \text{replicate}(n, a)$
Informal description
For any natural numbers $m$ and $n$ and any element $a$ of type $\alpha$, the list obtained by replicating $a$ exactly $m + n$ times is equal to the concatenation of the list with $a$ replicated $m$ times and the list with $a$ replicated $n$ times. In other words: $$\text{replicate}(m + n, a) = \text{replicate}(m, a) +\!\!\!+ \text{replicate}(n, a)$$
List.replicate_subset_singleton theorem
(n) (a : α) : replicate n a ⊆ [a]
Full source
theorem replicate_subset_singleton (n) (a : α) : replicatereplicate n a ⊆ [a] := fun _ h =>
  mem_singleton.2 (eq_of_mem_replicate h)
Replicated List is Subset of Singleton List
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the list obtained by replicating $a$ $n$ times is a subset of the singleton list $[a]$.
List.subset_singleton_iff theorem
{a : α} {L : List α} : L ⊆ [a] ↔ ∃ n, L = replicate n a
Full source
theorem subset_singleton_iff {a : α} {L : List α} : L ⊆ [a]L ⊆ [a] ↔ ∃ n, L = replicate n a := by
  simp only [eq_replicate_iff, subset_def, mem_singleton, exists_eq_left']
Characterization of Subsets of Singleton Lists via Replication
Informal description
For any element $a$ of type $\alpha$ and any list $L$ of elements of type $\alpha$, $L$ is a subset of the singleton list $[a]$ if and only if there exists a natural number $n$ such that $L$ is equal to the list obtained by replicating $a$ exactly $n$ times.
List.replicate_right_injective theorem
{n : ℕ} (hn : n ≠ 0) : Injective (@replicate α n)
Full source
theorem replicate_right_injective {n : } (hn : n ≠ 0) : Injective (@replicate α n) :=
  fun _ _ h => (eq_replicate_iff.1 h).2 _ <| mem_replicate.2 ⟨hn, rfl⟩
Injectivity of Replication for Nonzero Counts
Informal description
For any natural number $n \neq 0$, the function that replicates an element of type $\alpha$ exactly $n$ times is injective. In other words, if $\text{replicate}(n, a_1) = \text{replicate}(n, a_2)$, then $a_1 = a_2$.
List.replicate_right_inj theorem
{a b : α} {n : ℕ} (hn : n ≠ 0) : replicate n a = replicate n b ↔ a = b
Full source
theorem replicate_right_inj {a b : α} {n : } (hn : n ≠ 0) :
    replicatereplicate n a = replicate n b ↔ a = b :=
  (replicate_right_injective hn).eq_iff
Equality of Replicated Lists Implies Element Equality for Nonzero Counts
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any nonzero natural number $n$, the list obtained by replicating $a$ exactly $n$ times is equal to the list obtained by replicating $b$ exactly $n$ times if and only if $a = b$. In other words, $\text{replicate}(n, a) = \text{replicate}(n, b) \leftrightarrow a = b$ when $n \neq 0$.
List.replicate_right_inj' theorem
{a b : α} : ∀ {n}, replicate n a = replicate n b ↔ n = 0 ∨ a = b
Full source
theorem replicate_right_inj' {a b : α} : ∀ {n},
    replicatereplicate n a = replicate n b ↔ n = 0 ∨ a = b
  | 0 => by simp
  | n + 1 => (replicate_right_inj n.succ_ne_zero).trans <| by simp only [n.succ_ne_zero, false_or]
Equality of Replicated Lists Implies Zero Count or Element Equality
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any natural number $n$, the list obtained by replicating $a$ exactly $n$ times is equal to the list obtained by replicating $b$ exactly $n$ times if and only if either $n = 0$ or $a = b$. In other words, $\text{replicate}(n, a) = \text{replicate}(n, b) \leftrightarrow n = 0 \lor a = b$.
List.replicate_left_injective theorem
(a : α) : Injective (replicate · a)
Full source
theorem replicate_left_injective (a : α) : Injective (replicate · a) :=
  LeftInverse.injective (length_replicate (n := ·))
Injectivity of List Replication in Length Parameter
Informal description
For any element $a$ of type $\alpha$, the function $n \mapsto \text{replicate}(n, a)$ (which creates a list by repeating $a$ exactly $n$ times) is injective. In other words, if $\text{replicate}(n, a) = \text{replicate}(m, a)$, then $n = m$.
List.replicate_left_inj theorem
{a : α} {n m : ℕ} : replicate n a = replicate m a ↔ n = m
Full source
theorem replicate_left_inj {a : α} {n m : } : replicatereplicate n a = replicate m a ↔ n = m :=
  (replicate_left_injective a).eq_iff
Equality of Replicated Lists Implies Equal Lengths: $\text{replicate}(n, a) = \text{replicate}(m, a) \leftrightarrow n = m$
Informal description
For any element $a$ of type $\alpha$ and natural numbers $n$ and $m$, the list obtained by repeating $a$ exactly $n$ times is equal to the list obtained by repeating $a$ exactly $m$ times if and only if $n = m$. In other words, $\text{replicate}(n, a) = \text{replicate}(m, a) \leftrightarrow n = m$.
List.head?_flatten_replicate theorem
{n : ℕ} (h : n ≠ 0) (l : List α) : (List.replicate n l).flatten.head? = l.head?
Full source
@[simp]
theorem head?_flatten_replicate {n : } (h : n ≠ 0) (l : List α) :
    (List.replicate n l).flatten.head? = l.head? := by
  obtain ⟨n, rfl⟩ := Nat.exists_eq_succ_of_ne_zero h
  induction l <;> simp [replicate]
Head Preservation Under Flattening of Replicated Lists
Informal description
For any natural number $n \neq 0$ and any list $l$ of elements of type $\alpha$, the first element of the flattened list obtained by replicating $l$ $n$ times is equal to the first element of $l$ (if it exists). That is, $\text{head?}(\text{flatten}(\text{replicate}\ n\ l)) = \text{head?}(l)$.
List.getLast?_flatten_replicate theorem
{n : ℕ} (h : n ≠ 0) (l : List α) : (List.replicate n l).flatten.getLast? = l.getLast?
Full source
@[simp]
theorem getLast?_flatten_replicate {n : } (h : n ≠ 0) (l : List α) :
    (List.replicate n l).flatten.getLast? = l.getLast? := by
  rw [← List.head?_reverse, ← List.head?_reverse, List.reverse_flatten, List.map_replicate,
  List.reverse_replicate, head?_flatten_replicate h]
Last Element Preservation Under Flattening of Replicated Lists
Informal description
For any natural number $n \neq 0$ and any list $l$ of elements of type $\alpha$, the last element of the flattened list obtained by replicating $l$ $n$ times is equal to the last element of $l$ (if it exists). That is, $\text{getLast?}(\text{flatten}(\text{replicate}\ n\ l)) = \text{getLast?}(l)$.
List.mem_pure theorem
(x y : α) : x ∈ (pure y : List α) ↔ x = y
Full source
theorem mem_pure (x y : α) : x ∈ (pure y : List α)x ∈ (pure y : List α) ↔ x = y := by simp
Membership in Singleton List Equals Element Identity
Informal description
For any elements $x$ and $y$ of type $\alpha$, the element $x$ belongs to the singleton list containing $y$ (denoted as $\mathrm{pure}\,y$) if and only if $x$ equals $y$. In symbols: \[ x \in [y] \leftrightarrow x = y \]
List.bind_eq_flatMap theorem
{α β} (f : α → List β) (l : List α) : l >>= f = l.flatMap f
Full source
@[simp]
theorem bind_eq_flatMap {α β} (f : α → List β) (l : List α) : l >>= f = l.flatMap f :=
  rfl
Equivalence of List Bind and FlatMap Operations
Informal description
For any function $f : \alpha \to \text{List } \beta$ and any list $l : \text{List } \alpha$, the bind operation `l >>= f` is equal to the flatMap operation `l.flatMap f`.
List.reverse_cons' theorem
(a : α) (l : List α) : reverse (a :: l) = concat (reverse l) a
Full source
theorem reverse_cons' (a : α) (l : List α) : reverse (a :: l) = concat (reverse l) a := by
  simp only [reverse_cons, concat_eq_append]
Reversing a Cons List Equals Concatenating the Reversed Tail with the Head
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\alpha$, the reverse of the list obtained by prepending $a$ to $l$ is equal to the list obtained by appending $a$ to the reverse of $l$. In symbols: $$\mathrm{reverse}(a :: l) = \mathrm{concat}(\mathrm{reverse}(l), a)$$
List.reverse_concat' theorem
(l : List α) (a : α) : (l ++ [a]).reverse = a :: l.reverse
Full source
theorem reverse_concat' (l : List α) (a : α) : (l ++ [a]).reverse = a :: l.reverse := by
  rw [reverse_append]; rfl
Reversal of Concatenated Singleton List: $(l \mathbin{+\kern-0.5ex+} [a])^{\text{rev}} = a :: l^{\text{rev}}$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a : \alpha$, the reverse of the list obtained by appending $[a]$ to $l$ is equal to the list obtained by prepending $a$ to the reverse of $l$. In symbols: $$(l \mathbin{+\kern-0.5ex+} [a])^{\text{rev}} = a :: l^{\text{rev}}$$
List.reverse_singleton theorem
(a : α) : reverse [a] = [a]
Full source
@[simp]
theorem reverse_singleton (a : α) : reverse [a] = [a] :=
  rfl
Reversing a Singleton List Leaves It Unchanged
Informal description
For any element $a$ of type $\alpha$, the reverse of the singleton list $[a]$ is equal to itself, i.e., $\text{reverse}([a]) = [a]$.
List.reverse_involutive theorem
: Involutive (@reverse α)
Full source
@[simp]
theorem reverse_involutive : Involutive (@reverse α) :=
  reverse_reverse
Involutivity of List Reversal: $\text{reverse} \circ \text{reverse} = \text{id}$
Informal description
The list reversal operation is involutive, meaning that for any list $l$ of elements of type $\alpha$, reversing the list twice returns the original list: $\text{reverse}(\text{reverse}(l)) = l$.
List.reverse_injective theorem
: Injective (@reverse α)
Full source
@[simp]
theorem reverse_injective : Injective (@reverse α) :=
  reverse_involutive.injective
Injectivity of List Reversal: $\text{reverse}(l_1) = \text{reverse}(l_2) \implies l_1 = l_2$
Informal description
The list reversal operation is injective, meaning that for any two lists $l_1$ and $l_2$ of elements of type $\alpha$, if $\text{reverse}(l_1) = \text{reverse}(l_2)$, then $l_1 = l_2$.
List.reverse_surjective theorem
: Surjective (@reverse α)
Full source
theorem reverse_surjective : Surjective (@reverse α) :=
  reverse_involutive.surjective
Surjectivity of List Reversal
Informal description
The list reversal operation is surjective, meaning that for any list $l$ of elements of type $\alpha$, there exists a list $l'$ such that $\text{reverse}(l') = l$.
List.reverse_bijective theorem
: Bijective (@reverse α)
Full source
theorem reverse_bijective : Bijective (@reverse α) :=
  reverse_involutive.bijective
Bijectivity of List Reversal: $\text{reverse}$ is a Bijection
Informal description
The list reversal operation is bijective, meaning that for any list $l$ of elements of type $\alpha$, the function $\text{reverse}$ is both injective and surjective. In other words, $\text{reverse}$ is a bijection on the set of all lists of type $\alpha$.
List.concat_eq_reverse_cons theorem
(a : α) (l : List α) : concat l a = reverse (a :: reverse l)
Full source
theorem concat_eq_reverse_cons (a : α) (l : List α) : concat l a = reverse (a :: reverse l) := by
  simp only [concat_eq_append, reverse_cons, reverse_reverse]
Concatenation as Reverse of Prepended Reverse List
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the concatenation of $l$ with $a$ is equal to the reverse of the list obtained by prepending $a$ to the reverse of $l$. In symbols: $$\text{concat}(l, a) = \text{reverse}(a :: \text{reverse}(l))$$
List.map_reverseAux theorem
(f : α → β) (l₁ l₂ : List α) : map f (reverseAux l₁ l₂) = reverseAux (map f l₁) (map f l₂)
Full source
theorem map_reverseAux (f : α → β) (l₁ l₂ : List α) :
    map f (reverseAux l₁ l₂) = reverseAux (map f l₁) (map f l₂) := by
  simp only [reverseAux_eq, map_append, map_reverse]
Map Commutes with Reverse Auxiliary on Lists
Informal description
For any function $f : \alpha \to \beta$ and lists $l_1, l_2$ of elements of type $\alpha$, the map of $f$ over the reverse auxiliary of $l_1$ and $l_2$ is equal to the reverse auxiliary of the map of $f$ over $l_1$ and the map of $f$ over $l_2$. In symbols: $$ \mathsf{map}\, f\, (\mathsf{reverseAux}\, l_1\, l_2) = \mathsf{reverseAux}\, (\mathsf{map}\, f\, l_1)\, (\mathsf{map}\, f\, l_2). $$
List.perm_reverse theorem
: l₁ ~ l₂.reverse ↔ l₁ ~ l₂
Full source
@[simp] lemma perm_reverse : l₁ ~ l₂.reversel₁ ~ l₂.reverse ↔ l₁ ~ l₂ where
  mp hl := hl.trans l₂.reverse_perm
  mpr hl := hl.trans l₂.reverse_perm.symm
Permutation Equivalence Under List Reversal: $l₁ \sim \text{reverse}(l₂) \leftrightarrow l₁ \sim l₂$
Informal description
For any two lists $l₁$ and $l₂$, the list $l₁$ is a permutation of the reverse of $l₂$ if and only if $l₁$ is a permutation of $l₂$.
List.getLast_append_singleton theorem
{a : α} (l : List α) : getLast (l ++ [a]) (append_ne_nil_of_right_ne_nil l (cons_ne_nil a _)) = a
Full source
theorem getLast_append_singleton {a : α} (l : List α) :
    getLast (l ++ [a]) (append_ne_nil_of_right_ne_nil l (cons_ne_nil a _)) = a := by
  simp [getLast_append]
Last Element of List Appended with Singleton
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the last element of the list obtained by appending the singleton list $[a]$ to $l$ is equal to $a$.
List.getLast_append_of_right_ne_nil theorem
(l₁ l₂ : List α) (h : l₂ ≠ []) : getLast (l₁ ++ l₂) (append_ne_nil_of_right_ne_nil l₁ h) = getLast l₂ h
Full source
theorem getLast_append_of_right_ne_nil (l₁ l₂ : List α) (h : l₂ ≠ []) :
    getLast (l₁ ++ l₂) (append_ne_nil_of_right_ne_nil l₁ h) = getLast l₂ h := by
  induction l₁ with
  | nil => simp
  | cons _ _ ih => simp only [cons_append]; rw [List.getLast_cons]; exact ih
Last Element of Concatenated List with Non-Empty Second List
Informal description
For any two lists $l_1$ and $l_2$ in a type $\alpha$, if $l_2$ is non-empty, then the last element of the concatenated list $l_1 ++ l_2$ is equal to the last element of $l_2$.
List.getLast_concat' theorem
{a : α} (l : List α) : getLast (concat l a) (by simp) = a
Full source
theorem getLast_concat' {a : α} (l : List α) : getLast (concat l a) (by simp) = a := by
  simp
Last Element of Concatenated List with Appended Element
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the last element of the list obtained by concatenating $l$ with $a$ (i.e., $\text{concat}(l, a)$) is equal to $a$.
List.getLast_singleton' theorem
(a : α) : getLast [a] (cons_ne_nil a []) = a
Full source
@[simp]
theorem getLast_singleton' (a : α) : getLast [a] (cons_ne_nil a []) = a := rfl
Last Element of Singleton List is Its Only Element
Informal description
For any element $a$ of type $\alpha$, the last element of the singleton list $[a]$ is equal to $a$.
List.getLast_cons_cons theorem
(a₁ a₂ : α) (l : List α) : getLast (a₁ :: a₂ :: l) (cons_ne_nil _ _) = getLast (a₂ :: l) (cons_ne_nil a₂ l)
Full source
@[simp]
theorem getLast_cons_cons (a₁ a₂ : α) (l : List α) :
    getLast (a₁ :: a₂ :: l) (cons_ne_nil _ _) = getLast (a₂ :: l) (cons_ne_nil a₂ l) :=
  rfl
Last Element of Cons-Cons List Equals Last Element of Tail
Informal description
For any elements $a_1, a_2$ of type $\alpha$ and any list $l$ of type $\alpha$, the last element of the list $a_1 :: a_2 :: l$ is equal to the last element of the list $a_2 :: l$.
List.dropLast_append_getLast theorem
: ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
Full source
theorem dropLast_append_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
  | [], h => absurd rfl h
  | [_], _ => rfl
  | a :: b :: l, h => by
    rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)]
    congr
    exact dropLast_append_getLast (cons_ne_nil b l)
Reconstruction of List from DropLast and GetLast
Informal description
For any non-empty list $l$ of type $\alpha$, the concatenation of the list obtained by removing the last element of $l$ (denoted as $\operatorname{dropLast} l$) with the singleton list containing the last element of $l$ (denoted as $[\operatorname{getLast} l h]$) equals the original list $l$. In other words, $\operatorname{dropLast} l ++ [\operatorname{getLast} l h] = l$.
List.getLast_congr theorem
{l₁ l₂ : List α} (h₁ : l₁ ≠ []) (h₂ : l₂ ≠ []) (h₃ : l₁ = l₂) : getLast l₁ h₁ = getLast l₂ h₂
Full source
theorem getLast_congr {l₁ l₂ : List α} (h₁ : l₁ ≠ []) (h₂ : l₂ ≠ []) (h₃ : l₁ = l₂) :
    getLast l₁ h₁ = getLast l₂ h₂ := by subst l₁; rfl
Equality of Last Elements for Equal Non-Empty Lists
Informal description
For any two non-empty lists $l_1$ and $l_2$ of type $\alpha$, if $l_1 = l_2$, then the last element of $l_1$ (with proof $h_1$ that $l_1$ is non-empty) is equal to the last element of $l_2$ (with proof $h_2$ that $l_2$ is non-empty).
List.getLast_replicate_succ theorem
(m : ℕ) (a : α) : (replicate (m + 1) a).getLast (ne_nil_of_length_eq_add_one length_replicate) = a
Full source
theorem getLast_replicate_succ (m : ) (a : α) :
    (replicate (m + 1) a).getLast (ne_nil_of_length_eq_add_one length_replicate) = a := by
  simp only [replicate_succ']
  exact getLast_append_singleton _
Last Element of Replicated List with Succ Length is Original Element
Informal description
For any natural number $m$ and any element $a$ of type $\alpha$, the last element of the list obtained by replicating $a$ exactly $m + 1$ times is equal to $a$. That is, $\operatorname{getLast} (\operatorname{replicate} (m + 1) a) h = a$, where $h$ is a proof that the replicated list is non-empty (which holds because its length is $m + 1 \neq 0$).
List.mem_getLast?_eq_getLast theorem
: ∀ {l : List α} {x : α}, x ∈ l.getLast? → ∃ h, x = getLast l h
Full source
theorem mem_getLast?_eq_getLast : ∀ {l : List α} {x : α}, x ∈ l.getLast?∃ h, x = getLast l h
  | [], x, hx => False.elim <| by simp at hx
  | [a], x, hx =>
    have : a = x := by simpa using hx
    this ▸ ⟨cons_ne_nil a [], rfl⟩
  | a :: b :: l, x, hx => by
    rw [getLast?_cons_cons] at hx
    rcases mem_getLast?_eq_getLast hx with ⟨_, h₂⟩
    use cons_ne_nil _ _
    assumption
Membership in Optional Last Element Implies Existence of Last Element
Informal description
For any list $l$ of type $\alpha$ and any element $x$ of type $\alpha$, if $x$ is a member of the optional last element of $l$ (denoted by `l.getLast?`), then there exists a proof $h$ that $l$ is non-empty, and $x$ is equal to the last element of $l$ under this proof (i.e., $x = \text{getLast } l \ h$).
List.getLast?_eq_getLast_of_ne_nil theorem
: ∀ {l : List α} (h : l ≠ []), l.getLast? = some (l.getLast h)
Full source
theorem getLast?_eq_getLast_of_ne_nil : ∀ {l : List α} (h : l ≠ []), l.getLast? = some (l.getLast h)
  | [], h => (h rfl).elim
  | [_], _ => rfl
  | _ :: b :: l, _ => @getLast?_eq_getLast_of_ne_nil (b :: l) (cons_ne_nil _ _)
Equality of Optional Last Element and Last Element for Non-Empty Lists
Informal description
For any non-empty list $l$ of type $\alpha$, the optional last element `l.getLast?` is equal to `some` applied to the last element `l.getLast h`, where $h$ is a proof that $l$ is non-empty.
List.mem_getLast?_cons theorem
{x y : α} : ∀ {l : List α}, x ∈ l.getLast? → x ∈ (y :: l).getLast?
Full source
theorem mem_getLast?_cons {x y : α} : ∀ {l : List α}, x ∈ l.getLast?x ∈ (y :: l).getLast?
  | [], _ => by contradiction
  | _ :: _, h => h
Preservation of Last Element Membership Under Cons Operation
Informal description
For any elements $x, y$ of type $\alpha$ and any list $l$ of type $\alpha$, if $x$ is an element of the last element of $l$ (when it exists), then $x$ is also an element of the last element of the list obtained by prepending $y$ to $l$.
List.dropLast_append_getLast? theorem
: ∀ {l : List α}, ∀ a ∈ l.getLast?, dropLast l ++ [a] = l
Full source
theorem dropLast_append_getLast? : ∀ {l : List α}, ∀ a ∈ l.getLast?, dropLast l ++ [a] = l
  | [], a, ha => (Option.not_mem_none a ha).elim
  | [a], _, rfl => rfl
  | a :: b :: l, c, hc => by
    rw [getLast?_cons_cons] at hc
    rw [dropLast_cons₂, cons_append, dropLast_append_getLast? _ hc]
Reconstruction of List from DropLast and Last Element
Informal description
For any list $l$ of type $\alpha$ and any element $a$ in the last element of $l$ (i.e., $a \in l.\text{getLast?}$), the concatenation of the list obtained by removing the last element of $l$ (denoted $\text{dropLast } l$) with the singleton list $[a]$ equals the original list $l$. In other words, $\text{dropLast } l \mathbin{+\!\!+} [a] = l$.
List.getLastI_eq_getLast? theorem
[Inhabited α] : ∀ l : List α, l.getLastI = l.getLast?.iget
Full source
theorem getLastI_eq_getLast? [Inhabited α] : ∀ l : List α, l.getLastI = l.getLast?.iget
  | [] => by simp [getLastI, Inhabited.default]
  | [_] => rfl
  | [_, _] => rfl
  | [_, _, _] => rfl
  | _ :: _ :: c :: l => by simp [getLastI, getLastI_eq_getLast? (c :: l)]
Equality of Default-Extended Last Element and Default-Valued Extraction of Optional Last Element
Informal description
For any list $l$ of elements of type $\alpha$ (where $\alpha$ has a default inhabitant), the default-extended last element of $l$ (obtained via `getLastI`) is equal to the default-valued extraction of the optional last element of $l$ (obtained via `getLast?.iget`). That is, $\text{getLastI}(l) = \text{iget}(\text{getLast?}(l))$.
List.getLast?_append_cons theorem
: ∀ (l₁ : List α) (a : α) (l₂ : List α), getLast? (l₁ ++ a :: l₂) = getLast? (a :: l₂)
Full source
theorem getLast?_append_cons :
    ∀ (l₁ : List α) (a : α) (l₂ : List α), getLast? (l₁ ++ a :: l₂) = getLast? (a :: l₂)
  | [], _, _ => rfl
  | [_], _, _ => rfl
  | b :: c :: l₁, a, l₂ => by rw [cons_append, cons_append, getLast?_cons_cons,
    ← cons_append, getLast?_append_cons (c :: l₁)]
Last Element of Concatenated List with Cons
Informal description
For any list $l_1$ of elements of type $\alpha$, any element $a \in \alpha$, and any list $l_2$ of elements of type $\alpha$, the last element of the concatenated list $l_1 ++ (a :: l_2)$ is equal to the last element of the list $a :: l_2$.
List.getLast?_append_of_ne_nil theorem
(l₁ : List α) : ∀ {l₂ : List α} (_ : l₂ ≠ []), getLast? (l₁ ++ l₂) = getLast? l₂
Full source
theorem getLast?_append_of_ne_nil (l₁ : List α) :
    ∀ {l₂ : List α} (_ : l₂ ≠ []), getLast? (l₁ ++ l₂) = getLast? l₂
  | [], hl₂ => by contradiction
  | b :: l₂, _ => getLast?_append_cons l₁ b l₂
Last Element of Concatenated List with Non-Empty Second List
Informal description
For any list $l_1$ of elements of type $\alpha$ and any non-empty list $l_2$ of elements of type $\alpha$, the last element of the concatenated list $l_1 ++ l_2$ is equal to the last element of $l_2$.
List.mem_getLast?_append_of_mem_getLast? theorem
{l₁ l₂ : List α} {x : α} (h : x ∈ l₂.getLast?) : x ∈ (l₁ ++ l₂).getLast?
Full source
theorem mem_getLast?_append_of_mem_getLast? {l₁ l₂ : List α} {x : α} (h : x ∈ l₂.getLast?) :
    x ∈ (l₁ ++ l₂).getLast? := by
  cases l₂
  · contradiction
  · rw [List.getLast?_append_cons]
    exact h
Preservation of Last Element in List Concatenation
Informal description
For any lists $l_1$ and $l_2$ of elements of type $\alpha$, and any element $x \in \alpha$, if $x$ is the last element of $l_2$ (i.e., $x \in \text{getLast?}\, l_2$), then $x$ is also the last element of the concatenated list $l_1 ++ l_2$ (i.e., $x \in \text{getLast?}\, (l_1 ++ l_2)$).
List.head!_nil theorem
[Inhabited α] : ([] : List α).head! = default
Full source
@[simp]
theorem head!_nil [Inhabited α] : ([] : List α).head! = default := rfl
Default Value for Head of Empty List
Informal description
For any inhabited type $\alpha$, the `head!` function applied to the empty list `[]` returns the default element of $\alpha$.
List.head_cons_tail theorem
(x : List α) (h : x ≠ []) : x.head h :: x.tail = x
Full source
@[simp] theorem head_cons_tail (x : List α) (h : x ≠ []) : x.head h :: x.tail = x := by
  cases x <;> simp at h ⊢
Decomposition of Non-Empty List into Head and Tail
Informal description
For any non-empty list $x$ of elements of type $\alpha$, the list obtained by prepending the head of $x$ (with proof $h$ that $x$ is non-empty) to the tail of $x$ equals $x$ itself. In other words, $(\mathrm{head}\, x\, h) :: (\mathrm{tail}\, x) = x$.
List.head_eq_getElem_zero theorem
{l : List α} (hl : l ≠ []) : l.head hl = l[0]'(length_pos_iff.2 hl)
Full source
theorem head_eq_getElem_zero {l : List α} (hl : l ≠ []) :
    l.head hl = l[0]'(length_pos_iff.2 hl) :=
  (getElem_zero _).symm
Head of Non-Empty List Equals Zeroth Element
Informal description
For any non-empty list `l` of type `α`, the head of `l` (accessed with proof `hl` that `l` is non-empty) is equal to the zeroth element of `l` (accessed with proof derived from `hl` via `length_pos_iff`). In other words, if `l ≠ []`, then `l.head hl = l[0]`.
List.head!_eq_head? theorem
[Inhabited α] (l : List α) : head! l = (head? l).iget
Full source
theorem head!_eq_head? [Inhabited α] (l : List α) : head! l = (head? l).iget := by cases l <;> rfl
Equivalence of Head Operations: $\mathrm{head!}\, l = \mathrm{iget}\, (\mathrm{head?}\, l)$
Informal description
For any inhabited type $\alpha$ and any list $l$ of elements of type $\alpha$, the head of $l$ (accessed via the `head!` operation) is equal to the default-valued extraction of the optional head of $l$ (accessed via `head?`). That is, $\mathrm{head!}\, l = \mathrm{iget}\, (\mathrm{head?}\, l)$.
List.surjective_head! theorem
[Inhabited α] : Surjective (@head! α _)
Full source
theorem surjective_head! [Inhabited α] : Surjective (@head! α _) := fun x => ⟨[x], rfl⟩
Surjectivity of the `head!` function on lists over inhabited types
Informal description
For any inhabited type $\alpha$, the function `head!` that takes a list and returns its first element (or the default element if the list is empty) is surjective. That is, for every element $a \in \alpha$, there exists a list $l$ such that `head! l = a`.
List.surjective_head? theorem
: Surjective (@head? α)
Full source
theorem surjective_head? : Surjective (@head? α) :=
  Option.forall.2 ⟨⟨[], rfl⟩, fun x => ⟨[x], rfl⟩⟩
Surjectivity of the Optional Head Function on Lists
Informal description
The function `head?` that takes a list and returns its first element as an optional value (or `none` if the list is empty) is surjective. That is, for every optional value `o : Option α`, there exists a list `l : List α` such that `head? l = o`.
List.surjective_tail theorem
: Surjective (@tail α)
Full source
theorem surjective_tail : Surjective (@tail α)
  | [] => ⟨[], rfl⟩
  | a :: l => ⟨a :: a :: l, rfl⟩
Surjectivity of the Tail Function on Lists
Informal description
The function `tail` that takes a list and returns its tail (the list without its first element) is surjective. That is, for every list `l` of elements of type `α`, there exists a list `l'` such that `tail l' = l`.
List.head!_cons theorem
[Inhabited α] (a : α) (l : List α) : head! (a :: l) = a
Full source
@[simp] theorem head!_cons [Inhabited α] (a : α) (l : List α) : head! (a :: l) = a := rfl
Head of Cons List is First Element
Informal description
For any inhabited type $\alpha$, element $a \in \alpha$, and list $l$ of elements of $\alpha$, the head of the list $a :: l$ is equal to $a$.
List.head!_append theorem
[Inhabited α] (t : List α) {s : List α} (h : s ≠ []) : head! (s ++ t) = head! s
Full source
@[simp]
theorem head!_append [Inhabited α] (t : List α) {s : List α} (h : s ≠ []) :
    head! (s ++ t) = head! s := by
  induction s
  · contradiction
  · rfl
Head of Concatenated List Equals Head of First List
Informal description
For any inhabited type $\alpha$, given a list $t$ of elements of $\alpha$ and a non-empty list $s$ of elements of $\alpha$, the head element of the concatenated list $s ++ t$ is equal to the head element of $s$.
List.mem_head?_append_of_mem_head? theorem
{s t : List α} {x : α} (h : x ∈ s.head?) : x ∈ (s ++ t).head?
Full source
theorem mem_head?_append_of_mem_head? {s t : List α} {x : α} (h : x ∈ s.head?) :
    x ∈ (s ++ t).head? := by
  cases s
  · contradiction
  · exact h
Preservation of Head Membership under List Concatenation
Informal description
For any lists $s$ and $t$ of type $\alpha$, and any element $x \in \alpha$, if $x$ is in the head of $s$ (i.e., $x \in \text{head?}(s)$), then $x$ is also in the head of the concatenated list $s ++ t$ (i.e., $x \in \text{head?}(s ++ t)$).
List.head?_append_of_ne_nil theorem
: ∀ (l₁ : List α) {l₂ : List α} (_ : l₁ ≠ []), head? (l₁ ++ l₂) = head? l₁
Full source
theorem head?_append_of_ne_nil :
    ∀ (l₁ : List α) {l₂ : List α} (_ : l₁ ≠ []), head? (l₁ ++ l₂) = head? l₁
  | _ :: _, _, _ => rfl
Head of Concatenated List Equals Head of First Non-Empty List
Informal description
For any list $l_1$ of type $\alpha$ and any list $l_2$ of type $\alpha$, if $l_1$ is non-empty, then the head element of the concatenated list $l_1 ++ l_2$ is equal to the head element of $l_1$.
List.tail_append_singleton_of_ne_nil theorem
{a : α} {l : List α} (h : l ≠ nil) : tail (l ++ [a]) = tail l ++ [a]
Full source
theorem tail_append_singleton_of_ne_nil {a : α} {l : List α} (h : l ≠ nil) :
    tail (l ++ [a]) = tail l ++ [a] := by
  induction l
  · contradiction
  · rw [tail, cons_append, tail]
Tail of Concatenated List with Singleton
Informal description
For any element $a$ of type $\alpha$ and any non-empty list $l$ of type $\alpha$, the tail of the concatenation of $l$ with the singleton list $[a]$ is equal to the concatenation of the tail of $l$ with $[a]$. In other words, $\text{tail}(l \mathbin{+\!\!+} [a]) = \text{tail}(l) \mathbin{+\!\!+} [a]$.
List.cons_head?_tail theorem
: ∀ {l : List α} {a : α}, a ∈ head? l → a :: tail l = l
Full source
theorem cons_head?_tail : ∀ {l : List α} {a : α}, a ∈ head? la :: tail l = l
  | [], a, h => by contradiction
  | b :: l, a, h => by
    simp? at h says simp only [head?_cons, Option.mem_def, Option.some.injEq] at h
    simp [h]
Reconstruction of List from Head and Tail
Informal description
For any list `l` of type `α` and any element `a` of type `α`, if `a` is an element of the optional head of `l` (i.e., `head? l` returns `some a`), then prepending `a` to the tail of `l` reconstructs the original list `l`. In other words, $a \in \text{head?}(l) \implies a :: \text{tail}(l) = l$.
List.head!_mem_head? theorem
[Inhabited α] : ∀ {l : List α}, l ≠ [] → head! l ∈ head? l
Full source
theorem head!_mem_head? [Inhabited α] : ∀ {l : List α}, l ≠ []head!head! l ∈ head? l
  | [], h => by contradiction
  | _ :: _, _ => rfl
Head Element Membership in Optional Head
Informal description
For any nonempty list `l` of type `α` (where `α` is an inhabited type), the head element obtained via `head!` is contained in the optional head element obtained via `head?`. That is, if `l ≠ []`, then `head! l ∈ head? l`.
List.cons_head!_tail theorem
[Inhabited α] {l : List α} (h : l ≠ []) : head! l :: tail l = l
Full source
theorem cons_head!_tail [Inhabited α] {l : List α} (h : l ≠ []) : head!head! l :: tail l = l :=
  cons_head?_tail (head!_mem_head? h)
List Reconstruction from Head and Tail
Informal description
For any nonempty list $l$ of type $\alpha$ (where $\alpha$ is an inhabited type), prepending the head element of $l$ (obtained via `head!`) to the tail of $l$ reconstructs the original list $l$. That is, $\text{head!}(l) :: \text{tail}(l) = l$.
List.get_eq_getElem? theorem
(l : List α) (i : Fin l.length) : l.get i = l[i]?.get (by simp [getElem?_eq_getElem])
Full source
theorem get_eq_getElem? (l : List α) (i : Fin l.length) :
    l.get i = l[i]?.get (by simp [getElem?_eq_getElem]) := by
  simp
Equivalence of List Access Methods: `get` and `getElem?`
Informal description
For any list $l$ of type $\alpha$ and any index $i$ of type $\text{Fin } l.\text{length}$ (i.e., $i$ is a natural number less than the length of $l$), the element obtained by the `get` operation on $l$ at index $i$ is equal to the element obtained by the `getElem?` operation on $l$ at index $i$, after unwrapping the `Option` result (which is guaranteed to be `some` due to the bound on $i$).
List.exists_mem_iff_getElem theorem
{l : List α} {p : α → Prop} : (∃ x ∈ l, p x) ↔ ∃ (i : ℕ) (_ : i < l.length), p l[i]
Full source
theorem exists_mem_iff_getElem {l : List α} {p : α → Prop} :
    (∃ x ∈ l, p x) ↔ ∃ (i : ℕ) (_ : i < l.length), p l[i] := by
  simp only [mem_iff_getElem]
  exact ⟨fun ⟨_x, ⟨i, hi, hix⟩, hxp⟩ ↦ ⟨i, hi, hix ▸ hxp⟩, fun ⟨i, hi, hp⟩ ↦ ⟨_, ⟨i, hi, rfl⟩, hp⟩⟩
Existence in List via Indexing
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, there exists an element $x$ in $l$ satisfying $p(x)$ if and only if there exists an index $i$ with $i < \text{length}(l)$ such that $p(l[i])$ holds.
List.forall_mem_iff_getElem theorem
{l : List α} {p : α → Prop} : (∀ x ∈ l, p x) ↔ ∀ (i : ℕ) (_ : i < l.length), p l[i]
Full source
theorem forall_mem_iff_getElem {l : List α} {p : α → Prop} :
    (∀ x ∈ l, p x) ↔ ∀ (i : ℕ) (_ : i < l.length), p l[i] := by
  simp [mem_iff_getElem, @forall_swap α]
Universal Quantification over List Elements via Indexing
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the statement that every element $x$ in $l$ satisfies $p(x)$ is equivalent to the statement that for every index $i$ with $i < \text{length}(l)$, the element $l[i]$ satisfies $p$.
List.Sublist.cons_cons theorem
{l₁ l₂ : List α} (a : α) (s : l₁ <+ l₂) : a :: l₁ <+ a :: l₂
Full source
theorem Sublist.cons_cons {l₁ l₂ : List α} (a : α) (s : l₁ <+ l₂) : a :: l₁a :: l₁ <+ a :: l₂ :=
  Sublist.cons₂ _ s
Prepending Preserves Sublist Relation
Informal description
For any element $a$ of type $\alpha$ and any two lists $l_1$ and $l_2$ of type $\alpha$, if $l_1$ is a sublist of $l_2$ (denoted $l_1 \subseteq l_2$), then the list obtained by prepending $a$ to $l_1$ is a sublist of the list obtained by prepending $a$ to $l_2$ (i.e., $a :: l_1 \subseteq a :: l_2$).
List.cons_sublist_cons' theorem
{a b : α} : a :: l₁ <+ b :: l₂ ↔ a :: l₁ <+ l₂ ∨ a = b ∧ l₁ <+ l₂
Full source
lemma cons_sublist_cons' {a b : α} : a :: l₁a :: l₁ <+ b :: l₂a :: l₁ <+ b :: l₂ ↔ a :: l₁ <+ l₂ ∨ a = b ∧ l₁ <+ l₂ := by
  constructor
  · rintro (_ | _)
    · exact Or.inl ‹_›
    · exact Or.inr ⟨rfl, ‹_›⟩
  · rintro (h | ⟨rfl, h⟩)
    · exact h.cons _
    · rwa [cons_sublist_cons]
Sublist condition for cons lists: $a :: l_1 \subseteq b :: l_2 \leftrightarrow (a :: l_1 \subseteq l_2) ∨ (a = b ∧ l_1 \subseteq l_2)$
Informal description
For any elements $a, b$ of type $\alpha$ and lists $l_1, l_2$ of type $\alpha$, the list $a :: l_1$ is a sublist of $b :: l_2$ if and only if either $a :: l_1$ is a sublist of $l_2$, or $a = b$ and $l_1$ is a sublist of $l_2$.
List.sublist_cons_of_sublist theorem
(a : α) (h : l₁ <+ l₂) : l₁ <+ a :: l₂
Full source
theorem sublist_cons_of_sublist (a : α) (h : l₁ <+ l₂) : l₁ <+ a :: l₂ := h.cons _
Sublist Preservation Under Cons Operation
Informal description
For any element $a$ of type $\alpha$ and any lists $l_1, l_2$ of type $\alpha$, if $l_1$ is a sublist of $l_2$, then $l_1$ is also a sublist of the list obtained by prepending $a$ to $l_2$ (i.e., $l_1 <+ a :: l_2$).
List.sublist_singleton theorem
{l : List α} {a : α} : l <+ [a] ↔ l = [] ∨ l = [a]
Full source
@[simp] lemma sublist_singleton {l : List α} {a : α} : l <+ [a]l <+ [a] ↔ l = [] ∨ l = [a] := by
  constructor <;> rintro (_ | _) <;> aesop
Sublist of Singleton List Characterization
Informal description
For any list $l$ and element $a$ of type $\alpha$, the list $l$ is a sublist of the singleton list $[a]$ if and only if $l$ is the empty list or $l$ is the singleton list $[a]$ itself.
List.Sublist.antisymm theorem
(s₁ : l₁ <+ l₂) (s₂ : l₂ <+ l₁) : l₁ = l₂
Full source
theorem Sublist.antisymm (s₁ : l₁ <+ l₂) (s₂ : l₂ <+ l₁) : l₁ = l₂ :=
  s₁.eq_of_length_le s₂.length_le
Antisymmetry of Sublist Relation: $l₁ \subseteq l₂ \land l₂ \subseteq l₁ \implies l₁ = l₂$
Informal description
For any two lists $l₁$ and $l₂$ of elements of type $\alpha$, if $l₁$ is a sublist of $l₂$ and $l₂$ is a sublist of $l₁$, then $l₁ = l₂$.
List.Sublist.of_cons_of_ne theorem
{a b} (h₁ : a ≠ b) (h₂ : a :: l₁ <+ b :: l₂) : a :: l₁ <+ l₂
Full source
/-- If the first element of two lists are different, then a sublist relation can be reduced. -/
theorem Sublist.of_cons_of_ne {a b} (h₁ : a ≠ b) (h₂ : a :: l₁a :: l₁ <+ b :: l₂) : a :: l₁a :: l₁ <+ l₂ :=
  match h₁, h₂ with
  | _, .cons _ h =>  h
Sublist Reduction for Distinct Heads: $a \neq b \Rightarrow (a :: l₁ <+ b :: l₂) \to (a :: l₁ <+ l₂)$
Informal description
For any two distinct elements $a$ and $b$ of type $\alpha$, and any two lists $l₁$ and $l₂$ of elements of type $\alpha$, if the list $a :: l₁$ is a sublist of $b :: l₂$, then $a :: l₁$ is also a sublist of $l₂$.
List.idxOf_cons_eq theorem
{a b : α} (l : List α) : b = a → idxOf a (b :: l) = 0
Full source
theorem idxOf_cons_eq {a b : α} (l : List α) : b = a → idxOf a (b :: l) = 0
  | e => by rw [← e]; exact idxOf_cons_self
Index of Equal Head Element in List is Zero
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, if $b = a$, then the index of $a$ in the list $b :: l$ is $0$.
List.idxOf_cons_ne theorem
{a b : α} (l : List α) : b ≠ a → idxOf a (b :: l) = succ (idxOf a l)
Full source
@[simp]
theorem idxOf_cons_ne {a b : α} (l : List α) : b ≠ aidxOf a (b :: l) = succ (idxOf a l)
  | h => by simp only [idxOf_cons, Bool.cond_eq_ite, beq_iff_eq, if_neg h]
Index of Unequal Head Element in List is Successor of Tail Index
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, if $b \neq a$, then the index of $a$ in the list $b :: l$ is equal to the successor of the index of $a$ in $l$.
List.idxOf_eq_length_iff theorem
{a : α} {l : List α} : idxOf a l = length l ↔ a ∉ l
Full source
theorem idxOf_eq_length_iff {a : α} {l : List α} : idxOfidxOf a l = length l ↔ a ∉ l := by
  induction l with
  | nil => exact iff_of_true rfl not_mem_nil
  | cons b l ih =>
    simp only [length, mem_cons, idxOf_cons, eq_comm]
    rw [cond_eq_if]
    split_ifs with h <;> simp at h
    · exact iff_of_false (by rintro ⟨⟩) fun H => H <| Or.inl h.symm
    · simp only [Ne.symm h, false_or]
      rw [← ih]
      exact succ_inj
Index Equals Length iff Element Not in List
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the index of $a$ in $l$ equals the length of $l$ if and only if $a$ does not belong to $l$.
List.idxOf_of_not_mem theorem
{l : List α} {a : α} : a ∉ l → idxOf a l = length l
Full source
@[simp]
theorem idxOf_of_not_mem {l : List α} {a : α} : a ∉ lidxOf a l = length l :=
  idxOf_eq_length_iff.2
Index of Absent Element Equals List Length
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a$ of type $\alpha$, if $a$ does not belong to $l$, then the index of $a$ in $l$ equals the length of $l$.
List.idxOf_le_length theorem
{a : α} {l : List α} : idxOf a l ≤ length l
Full source
theorem idxOf_le_length {a : α} {l : List α} : idxOf a l ≤ length l := by
  induction l with | nil => rfl | cons b l ih => ?_
  simp only [length, idxOf_cons, cond_eq_if, beq_iff_eq]
  by_cases h : b = a
  · rw [if_pos h]; exact Nat.zero_le _
  · rw [if_neg h]; exact succ_le_succ ih
Index of Element in List is Bounded by List Length
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the index of $a$ in $l$ is less than or equal to the length of $l$.
List.idxOf_lt_length_iff theorem
{a} {l : List α} : idxOf a l < length l ↔ a ∈ l
Full source
theorem idxOf_lt_length_iff {a} {l : List α} : idxOfidxOf a l < length l ↔ a ∈ l :=
  ⟨fun h => Decidable.byContradiction fun al => Nat.ne_of_lt h <| idxOf_eq_length_iff.2 al,
   fun al => (lt_of_le_of_ne idxOf_le_length) fun h => idxOf_eq_length_iff.1 h al⟩
Index Less Than Length iff Element in List: $\text{idxOf}\,a\,l < \text{length}\,l \leftrightarrow a \in l$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the index of $a$ in $l$ is strictly less than the length of $l$ if and only if $a$ is a member of $l$.
List.idxOf_append_of_mem theorem
{a : α} (h : a ∈ l₁) : idxOf a (l₁ ++ l₂) = idxOf a l₁
Full source
theorem idxOf_append_of_mem {a : α} (h : a ∈ l₁) : idxOf a (l₁ ++ l₂) = idxOf a l₁ := by
  induction l₁ with
  | nil =>
    exfalso
    exact not_mem_nil h
  | cons d₁ t₁ ih =>
    rw [List.cons_append]
    by_cases hh : d₁ = a
    · iterate 2 rw [idxOf_cons_eq _ hh]
    rw [idxOf_cons_ne _ hh, idxOf_cons_ne _ hh, ih (mem_of_ne_of_mem (Ne.symm hh) h)]
Index Preservation in List Concatenation for Existing Elements
Informal description
For any element $a$ of type $\alpha$ and any lists $l₁$ and $l₂$ of elements of type $\alpha$, if $a$ is a member of $l₁$, then the index of $a$ in the concatenated list $l₁ ++ l₂$ is equal to the index of $a$ in $l₁$.
List.idxOf_append_of_not_mem theorem
{a : α} (h : a ∉ l₁) : idxOf a (l₁ ++ l₂) = l₁.length + idxOf a l₂
Full source
theorem idxOf_append_of_not_mem {a : α} (h : a ∉ l₁) :
    idxOf a (l₁ ++ l₂) = l₁.length + idxOf a l₂ := by
  induction l₁ with
  | nil => rw [List.nil_append, List.length, Nat.zero_add]
  | cons d₁ t₁ ih =>
    rw [List.cons_append, idxOf_cons_ne _ (ne_of_not_mem_cons h).symm, List.length,
      ih (not_mem_of_not_mem_cons h), Nat.succ_add]
Index of Element in Concatenated List When Not in First List: $\text{idxOf}\,a\,(l₁ ++ l₂) = \text{length}\,l₁ + \text{idxOf}\,a\,l₂$
Informal description
For any element $a$ of type $\alpha$ and lists $l₁, l₂$ of type $\alpha$, if $a$ is not in $l₁$, then the index of $a$ in the concatenated list $l₁ ++ l₂$ is equal to the length of $l₁$ plus the index of $a$ in $l₂$.
List.getElem?_length theorem
(l : List α) : l[l.length]? = none
Full source
@[simp]
theorem getElem?_length (l : List α) : l[l.length]? = none := getElem?_eq_none le_rfl
Optional Element Beyond List Length is None
Informal description
For any list $l$ of type $\alpha$, the optional element at index $\text{length}(l)$ is `none`.
List.getElem_map_rev theorem
(f : α → β) {l} {n : Nat} {h : n < l.length} : f l[n] = (map f l)[n]'((l.length_map f).symm ▸ h)
Full source
/-- A version of `getElem_map` that can be used for rewriting. -/
theorem getElem_map_rev (f : α → β) {l} {n : Nat} {h : n < l.length} :
    f l[n] = (map f l)[n]'((l.length_map f).symm ▸ h) := Eq.symm (getElem_map _)
Element-wise Mapping Equality: $f(l[n]) = (\text{map}\,f\,l)[n]$
Informal description
For any function $f : \alpha \to \beta$, list $l$ of type $\alpha$, and natural number $n$ such that $n < \text{length}(l)$, the application of $f$ to the $n$-th element of $l$ is equal to the $n$-th element of the mapped list $\text{map}\,f\,l$, where the proof of the index bound follows from the length preservation property of map.
List.get_length_sub_one theorem
{l : List α} (h : l.length - 1 < l.length) : l.get ⟨l.length - 1, h⟩ = l.getLast (by rintro rfl; exact Nat.lt_irrefl 0 h)
Full source
theorem get_length_sub_one {l : List α} (h : l.length - 1 < l.length) :
    l.get ⟨l.length - 1, h⟩ = l.getLast (by rintro rfl; exact Nat.lt_irrefl 0 h) :=
  (getLast_eq_getElem _).symm
Element at Length Minus One Equals Last Element in List
Informal description
For any nonempty list `l` of type `α`, the element at position `l.length - 1` (with the proof `h` that this index is valid) is equal to the last element of the list `l.getLast`.
List.ext_getElem?' theorem
{l₁ l₂ : List α} (h' : ∀ n < max l₁.length l₂.length, l₁[n]? = l₂[n]?) : l₁ = l₂
Full source
theorem ext_getElem?' {l₁ l₂ : List α} (h' : ∀ n < max l₁.length l₂.length, l₁[n]? = l₂[n]?) :
    l₁ = l₂ := by
  apply ext_getElem?
  intro n
  rcases Nat.lt_or_ge n <| max l₁.length l₂.length with hn | hn
  · exact h' n hn
  · simp_all [Nat.max_le, getElem?_eq_none]
List Equality via Element-wise Equality up to Maximum Length
Informal description
For any two lists $l₁$ and $l₂$ of type $\alpha$, if for every natural number $n$ less than the maximum of the lengths of $l₁$ and $l₂$, the optional $n$-th elements of $l₁$ and $l₂$ are equal (i.e., $l₁[n]? = l₂[n]?$), then $l₁ = l₂$.
List.ext_get_iff theorem
{l₁ l₂ : List α} : l₁ = l₂ ↔ l₁.length = l₂.length ∧ ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩
Full source
theorem ext_get_iff {l₁ l₂ : List α} :
    l₁ = l₂ ↔ l₁.length = l₂.length ∧ ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩ := by
  constructor
  · rintro rfl
    exact ⟨rfl, fun _ _ _ ↦ rfl⟩
  · intro ⟨h₁, h₂⟩
    exact ext_get h₁ h₂
List Equality via Length and Element-wise Equality
Informal description
Two lists $l₁$ and $l₂$ of type $\alpha$ are equal if and only if they have the same length and for every natural number $n$ and proofs $h₁$, $h₂$ that $n$ is within the bounds of $l₁$ and $l₂$ respectively, the $n$-th elements of $l₁$ and $l₂$ are equal.
List.ext_getElem?_iff' theorem
{l₁ l₂ : List α} : l₁ = l₂ ↔ ∀ n < max l₁.length l₂.length, l₁[n]? = l₂[n]?
Full source
theorem ext_getElem?_iff' {l₁ l₂ : List α} : l₁ = l₂ ↔
    ∀ n < max l₁.length l₂.length, l₁[n]? = l₂[n]? :=
  ⟨by rintro rfl _ _; rfl, ext_getElem?'⟩
List Equality via Element-wise Equality up to Maximum Length (Bidirectional)
Informal description
Two lists $l₁$ and $l₂$ of type $\alpha$ are equal if and only if for every natural number $n$ less than the maximum of their lengths, the optional $n$-th elements of $l₁$ and $l₂$ are equal (i.e., $l₁[n]? = l₂[n]?$).
List.ext_getElem! theorem
[Inhabited α] (hl : length l₁ = length l₂) (h : ∀ n : ℕ, l₁[n]! = l₂[n]!) : l₁ = l₂
Full source
/-- If two lists `l₁` and `l₂` are the same length and `l₁[n]! = l₂[n]!` for all `n`,
then the lists are equal. -/
theorem ext_getElem! [Inhabited α] (hl : length l₁ = length l₂) (h : ∀ n : , l₁[n]! = l₂[n]!) :
    l₁ = l₂ :=
  ext_getElem hl fun n h₁ h₂ ↦ by simpa only [← getElem!_pos] using h n
List Equality via Length and Element-wise Equality with Default Values
Informal description
Let $l₁$ and $l₂$ be two lists of elements of type $\alpha$ (where $\alpha$ is inhabited). If $l₁$ and $l₂$ have the same length, and for every natural number $n$, the $n$-th element of $l₁$ (with default value) equals the $n$-th element of $l₂$ (with default value), then $l₁ = l₂$.
List.getElem_idxOf theorem
[DecidableEq α] {a : α} : ∀ {l : List α} (h : idxOf a l < l.length), l[idxOf a l] = a
Full source
@[simp]
theorem getElem_idxOf [DecidableEq α] {a : α} : ∀ {l : List α} (h : idxOf a l < l.length),
    l[idxOf a l] = a
  | b :: l, h => by
    by_cases h' : b = a <;>
    simp [h', if_pos, if_false, getElem_idxOf]
Element at Index Position in List Equals Searched Element
Informal description
For any type $\alpha$ with decidable equality and any element $a \in \alpha$, if $l$ is a list of elements of type $\alpha$ and the index of $a$ in $l$ is less than the length of $l$, then the element of $l$ at position $\text{idxOf}(a, l)$ is equal to $a$.
List.idxOf_get theorem
[DecidableEq α] {a : α} {l : List α} (h) : get l ⟨idxOf a l, h⟩ = a
Full source
theorem idxOf_get [DecidableEq α] {a : α} {l : List α} (h) : get l ⟨idxOf a l, h⟩ = a := by
  simp
Element at Index Position in List Equals Searched Element via `get`
Informal description
For any type $\alpha$ with decidable equality and any element $a \in \alpha$, if $l$ is a list of elements of type $\alpha$ and $h$ is a proof that the index of $a$ in $l$ is within the bounds of $l$, then the element of $l$ at position $\text{idxOf}(a, l)$ is equal to $a$.
List.getElem?_idxOf theorem
[DecidableEq α] {a : α} {l : List α} (h : a ∈ l) : l[idxOf a l]? = some a
Full source
@[simp]
theorem getElem?_idxOf [DecidableEq α] {a : α} {l : List α} (h : a ∈ l) :
    l[idxOf a l]? = some a := by
  rw [getElem?_eq_getElem, getElem_idxOf (idxOf_lt_length_iff.2 h)]
Optional Element at Index of Member Equals Some Member: $l[\text{idxOf}\,a\,l]? = \text{some}\,a$
Informal description
For any type $\alpha$ with decidable equality, any element $a \in \alpha$, and any list $l$ of elements of type $\alpha$, if $a$ is a member of $l$, then the optional element of $l$ at position $\text{idxOf}(a, l)$ is equal to $\text{some }a$.
List.idxOf_inj theorem
[DecidableEq α] {l : List α} {x y : α} (hx : x ∈ l) (hy : y ∈ l) : idxOf x l = idxOf y l ↔ x = y
Full source
theorem idxOf_inj [DecidableEq α] {l : List α} {x y : α} (hx : x ∈ l) (hy : y ∈ l) :
    idxOfidxOf x l = idxOf y l ↔ x = y :=
  ⟨fun h => by
    have x_eq_y :
        get l ⟨idxOf x l, idxOf_lt_length_iff.2 hx⟩ =
        get l ⟨idxOf y l, idxOf_lt_length_iff.2 hy⟩ := by
      simp only [h]
    simp only [idxOf_get] at x_eq_y; exact x_eq_y, fun h => by subst h; rfl⟩
Injective Property of Index Function on List Elements: $\text{idxOf}\,x\,l = \text{idxOf}\,y\,l \leftrightarrow x = y$
Informal description
For any type $\alpha$ with decidable equality, any list $l$ of elements of type $\alpha$, and any elements $x, y \in l$, the index of $x$ in $l$ equals the index of $y$ in $l$ if and only if $x = y$.
List.get_reverse' theorem
(l : List α) (n) (hn') : l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩
Full source
theorem get_reverse' (l : List α) (n) (hn') :
    l.reverse.get n = l.get ⟨l.length - 1 - n, hn'⟩ := by
  simp
Element Access in Reversed List: $l.reverse[n] = l[|l| - 1 - n]$
Informal description
For any list $l$ of elements of type $\alpha$, any natural number $n$, and any proof $hn'$ that $n$ is a valid index for the reversed list $l.reverse$, the $n$-th element of $l.reverse$ is equal to the element at position $|l| - 1 - n$ in the original list $l$, where $|l|$ denotes the length of $l$.
List.getElem_set_of_ne theorem
{l : List α} {i j : ℕ} (h : i ≠ j) (a : α) (hj : j < (l.set i a).length) : (l.set i a)[j] = l[j]'(by simpa using hj)
Full source
@[simp]
theorem getElem_set_of_ne {l : List α} {i j : } (h : i ≠ j) (a : α)
    (hj : j < (l.set i a).length) :
    (l.set i a)[j] = l[j]'(by simpa using hj) := by
  rw [← Option.some_inj, ← List.getElem?_eq_getElem, List.getElem?_set_ne h,
    List.getElem?_eq_getElem]
Preservation of List Elements under Modification at Distinct Indices
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$ with $i \neq j$, and element $a : \alpha$, if $j$ is a valid index for the list obtained by setting the $i$-th element of $l$ to $a$ (i.e., $j < \text{length}(l.\text{set}\ i\ a)$), then the $j$-th element of the modified list equals the $j$-th element of the original list, i.e., $(l.\text{set}\ i\ a)[j] = l[j]$.
List.flatMap_pure_eq_map theorem
(f : α → β) (l : List α) : l.flatMap (pure ∘ f) = map f l
Full source
theorem flatMap_pure_eq_map (f : α → β) (l : List α) : l.flatMap (purepure ∘ f) = map f l :=
  .symm <| map_eq_flatMap ..
Equivalence of flatMap with Pure Composition and Map: $l.\text{flatMap} (\text{pure} \circ f) = \text{map}\ f\ l$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the flatMap operation of $l$ with the composition of the pure function and $f$ is equal to mapping $f$ over $l$. In other words, $l.\text{flatMap} (\text{pure} \circ f) = \text{map}\ f\ l$.
List.flatMap_congr theorem
{l : List α} {f g : α → List β} (h : ∀ x ∈ l, f x = g x) : l.flatMap f = l.flatMap g
Full source
theorem flatMap_congr {l : List α} {f g : α → List β} (h : ∀ x ∈ l, f x = g x) :
    l.flatMap f = l.flatMap g :=
  (congr_arg List.flatten <| map_congr_left h :)
Congruence of flatMap under Pointwise Equality of Functions
Informal description
For any list $l$ of elements of type $\alpha$ and any two functions $f, g : \alpha \to \text{List } \beta$, if for every element $x \in l$ we have $f(x) = g(x)$, then the flatMap of $f$ over $l$ is equal to the flatMap of $g$ over $l$, i.e., $l.\text{flatMap } f = l.\text{flatMap } g$.
List.infix_flatMap_of_mem theorem
{a : α} {as : List α} (h : a ∈ as) (f : α → List α) : f a <:+: as.flatMap f
Full source
theorem infix_flatMap_of_mem {a : α} {as : List α} (h : a ∈ as) (f : α → List α) :
    f a <:+: as.flatMap f :=
  infix_of_mem_flatten (mem_map_of_mem h)
Infix Property of flatMap: $f(a) \text{ is an infix of } \text{flatMap } f\ as$ when $a \in as$
Informal description
For any element $a$ in a list $as$ of type $\alpha$ and any function $f : \alpha \to \text{List } \alpha$, the list $f(a)$ is an infix of the flatMap of $f$ over $as$, i.e., $f(a) \text{ is an infix of } \text{flatMap } f\ as$.
List.map_eq_map theorem
{α β} (f : α → β) (l : List α) : f <$> l = map f l
Full source
@[simp]
theorem map_eq_map {α β} (f : α → β) (l : List α) : f <$> l = map f l :=
  rfl
Equivalence of Functorial Map and Standard Map on Lists
Informal description
For any types $\alpha$ and $\beta$, any function $f : \alpha \to \beta$, and any list $l$ of elements of type $\alpha$, the functorial map operation `<$>` applied to $f$ and $l$ is equal to the standard `map` function applied to $f$ and $l$, i.e., $f <$> l = \text{map } f l$.
List.comp_map theorem
(h : β → γ) (g : α → β) (l : List α) : map (h ∘ g) l = map h (map g l)
Full source
/-- A single `List.map` of a composition of functions is equal to
composing a `List.map` with another `List.map`, fully applied.
This is the reverse direction of `List.map_map`.
-/
theorem comp_map (h : β → γ) (g : α → β) (l : List α) : map (h ∘ g) l = map h (map g l) :=
  map_map.symm
Composition of Maps on Lists
Informal description
For any functions $g : \alpha \to \beta$ and $h : \beta \to \gamma$, and any list $l$ of elements of type $\alpha$, the map of the composition $h \circ g$ over $l$ is equal to the map of $h$ over the map of $g$ over $l$. In symbols: \[ \text{map}(h \circ g)(l) = \text{map}\, h (\text{map}\, g\, l). \]
List.map_comp_map theorem
(g : β → γ) (f : α → β) : map g ∘ map f = map (g ∘ f)
Full source
/-- Composing a `List.map` with another `List.map` is equal to
a single `List.map` of composed functions.
-/
@[simp]
theorem map_comp_map (g : β → γ) (f : α → β) : mapmap g ∘ map f = map (g ∘ f) := by
  ext l; rw [comp_map, Function.comp_apply]
Composition of List Mapping Operations
Informal description
For any functions $f : \alpha \to \beta$ and $g : \beta \to \gamma$, the composition of the list mapping operations $\text{map}\, g \circ \text{map}\, f$ is equal to the list mapping operation of the composed function $\text{map}\, (g \circ f)$. In symbols: \[ \text{map}\, g \circ \text{map}\, f = \text{map}\, (g \circ f). \]
Function.LeftInverse.list_map theorem
{f : α → β} {g : β → α} (h : LeftInverse f g) : LeftInverse (map f) (map g)
Full source
theorem _root_.Function.LeftInverse.list_map {f : α → β} {g : β → α} (h : LeftInverse f g) :
    LeftInverse (map f) (map g)
  | [] => by simp_rw [map_nil]
  | x :: xs => by simp_rw [map_cons, h x, h.list_map xs]
Preservation of Left Inverses under List Mapping
Informal description
Let $f : \alpha \to \beta$ and $g : \beta \to \alpha$ be functions such that $g$ is a left inverse of $f$, i.e., $g(f(x)) = x$ for all $x \in \alpha$. Then the list mapping operation preserves this left inverse property, meaning that for any list $l$ of elements of type $\alpha$, we have $\text{map}\, g (\text{map}\, f\, l) = l$.
Function.RightInverse.list_map theorem
{f : α → β} {g : β → α} (h : RightInverse f g) : RightInverse (map f) (map g)
Full source
nonrec theorem _root_.Function.RightInverse.list_map {f : α → β} {g : β → α}
    (h : RightInverse f g) : RightInverse (map f) (map g) :=
  h.list_map
Preservation of Right Inverses under List Mapping
Informal description
Let $f : \alpha \to \beta$ and $g : \beta \to \alpha$ be functions such that $f$ is a right inverse of $g$, i.e., $f(g(y)) = y$ for all $y \in \beta$. Then the list mapping operation preserves this right inverse property, meaning that for any list $l$ of elements of type $\beta$, we have $\text{map}\, f (\text{map}\, g\, l) = l$.
Function.Involutive.list_map theorem
{f : α → α} (h : Involutive f) : Involutive (map f)
Full source
nonrec theorem _root_.Function.Involutive.list_map {f : α → α}
    (h : Involutive f) : Involutive (map f) :=
  Function.LeftInverse.list_map h
Preservation of Involutive Property under List Mapping
Informal description
Let $f : \alpha \to \alpha$ be an involutive function, i.e., $f(f(x)) = x$ for all $x \in \alpha$. Then the list mapping operation preserves this involutive property, meaning that for any list $l$ of elements of type $\alpha$, we have $\text{map}\, f (\text{map}\, f\, l) = l$.
List.map_leftInverse_iff theorem
{f : α → β} {g : β → α} : LeftInverse (map f) (map g) ↔ LeftInverse f g
Full source
@[simp]
theorem map_leftInverse_iff {f : α → β} {g : β → α} :
    LeftInverseLeftInverse (map f) (map g) ↔ LeftInverse f g :=
  ⟨fun h x => by injection h [x], (·.list_map)⟩
List Map Preserves Left Inverses if and only if Pointwise Left Inverse Holds
Informal description
For functions $f : \alpha \to \beta$ and $g : \beta \to \alpha$, the map operation on lists preserves left inverses if and only if $g$ is a left inverse of $f$. That is, $\text{map}\, g \circ \text{map}\, f = \text{id}$ holds for all lists if and only if $g \circ f = \text{id}$ holds pointwise.
List.map_rightInverse_iff theorem
{f : α → β} {g : β → α} : RightInverse (map f) (map g) ↔ RightInverse f g
Full source
@[simp]
theorem map_rightInverse_iff {f : α → β} {g : β → α} :
    RightInverseRightInverse (map f) (map g) ↔ RightInverse f g := map_leftInverse_iff
List Map Preserves Right Inverses if and only if Pointwise Right Inverse Holds
Informal description
For functions $f : \alpha \to \beta$ and $g : \beta \to \alpha$, the map operation on lists preserves right inverses if and only if $g$ is a right inverse of $f$. That is, $\text{map}\, f \circ \text{map}\, g = \text{id}$ holds for all lists if and only if $f \circ g = \text{id}$ holds pointwise.
List.map_involutive_iff theorem
{f : α → α} : Involutive (map f) ↔ Involutive f
Full source
@[simp]
theorem map_involutive_iff {f : α → α} :
    InvolutiveInvolutive (map f) ↔ Involutive f := map_leftInverse_iff
List Map is Involutive if and only if Function is Involutive
Informal description
For any function $f : \alpha \to \alpha$, the map operation on lists $\text{map}\, f : \text{List}\, \alpha \to \text{List}\, \alpha$ is involutive if and only if $f$ is involutive. That is, $\text{map}\, f \circ \text{map}\, f = \text{id}$ holds for all lists if and only if $f \circ f = \text{id}$ holds pointwise.
Function.Injective.list_map theorem
{f : α → β} (h : Injective f) : Injective (map f)
Full source
theorem _root_.Function.Injective.list_map {f : α → β} (h : Injective f) :
    Injective (map f)
  | [], [], _ => rfl
  | x :: xs, y :: ys, hxy => by
    injection hxy with hxy hxys
    rw [h hxy, h.list_map hxys]
Injectivity of List Map under Injective Function
Informal description
If a function $f : \alpha \to \beta$ is injective, then the induced map on lists $\text{map}\, f : \text{List}\, \alpha \to \text{List}\, \beta$ is also injective.
List.map_injective_iff theorem
{f : α → β} : Injective (map f) ↔ Injective f
Full source
@[simp]
theorem map_injective_iff {f : α → β} : InjectiveInjective (map f) ↔ Injective f := by
  refine ⟨fun h x y hxy => ?_, (·.list_map)⟩
  suffices [x] = [y] by simpa using this
  apply h
  simp [hxy]
Injectivity of List Map Equivalent to Injectivity of Function
Informal description
For any function $f : \alpha \to \beta$, the map operation on lists $\text{map}\, f : \text{List}\, \alpha \to \text{List}\, \beta$ is injective if and only if $f$ is injective.
Function.Surjective.list_map theorem
{f : α → β} (h : Surjective f) : Surjective (map f)
Full source
theorem _root_.Function.Surjective.list_map {f : α → β} (h : Surjective f) :
    Surjective (map f) :=
  let ⟨_, h⟩ := h.hasRightInverse; h.list_map.surjective
Surjectivity of List Map under Surjective Function
Informal description
If a function $f : \alpha \to \beta$ is surjective, then the induced map on lists $\text{map}\, f : \text{List}\, \alpha \to \text{List}\, \beta$ is also surjective.
List.map_surjective_iff theorem
{f : α → β} : Surjective (map f) ↔ Surjective f
Full source
@[simp]
theorem map_surjective_iff {f : α → β} : SurjectiveSurjective (map f) ↔ Surjective f := by
  refine ⟨fun h x => ?_, (·.list_map)⟩
  let ⟨[y], hxy⟩ := h [x]
  exact ⟨_, List.singleton_injective hxy⟩
Surjectivity of List Map iff Function is Surjective
Informal description
For any function $f : \alpha \to \beta$, the map operation on lists $\text{map}\, f : \text{List}\, \alpha \to \text{List}\, \beta$ is surjective if and only if $f$ is surjective.
Function.Bijective.list_map theorem
{f : α → β} (h : Bijective f) : Bijective (map f)
Full source
theorem _root_.Function.Bijective.list_map {f : α → β} (h : Bijective f) : Bijective (map f) :=
  ⟨h.1.list_map, h.2.list_map⟩
Bijectivity of List Map under Bijective Function
Informal description
If a function \( f : \alpha \to \beta \) is bijective, then the induced map on lists \( \text{map}\, f : \text{List}\, \alpha \to \text{List}\, \beta \) is also bijective.
List.map_bijective_iff theorem
{f : α → β} : Bijective (map f) ↔ Bijective f
Full source
@[simp]
theorem map_bijective_iff {f : α → β} : BijectiveBijective (map f) ↔ Bijective f := by
  simp_rw [Function.Bijective, map_injective_iff, map_surjective_iff]
Bijectivity of List Map iff Function is Bijective
Informal description
For any function $f : \alpha \to \beta$, the map operation on lists induced by $f$ is bijective if and only if $f$ itself is bijective. In other words, the function $\text{map}\, f : \text{List}\, \alpha \to \text{List}\, \beta$ is bijective precisely when $f$ is bijective.
List.foldl_ext theorem
(f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) : foldl f a l = foldl g a l
Full source
theorem foldl_ext (f g : α → β → α) (a : α) {l : List β} (H : ∀ a : α, ∀ b ∈ l, f a b = g a b) :
    foldl f a l = foldl g a l := by
  induction l generalizing a with
  | nil => rfl
  | cons hd tl ih =>
    unfold foldl
    rw [ih _ fun a b bin => H a b <| mem_cons_of_mem _ bin, H a hd mem_cons_self]
Left Fold Extension Property: $\text{foldl}\ f\ a\ l = \text{foldl}\ g\ a\ l$ when $f$ and $g$ agree on all inputs from $l$
Informal description
Let $f, g : \alpha \to \beta \to \alpha$ be functions, $a \in \alpha$ an initial value, and $l$ a list of elements of type $\beta$. If for every $a \in \alpha$ and every $b \in l$ we have $f(a, b) = g(a, b)$, then the left fold operations $\text{foldl}\ f\ a\ l$ and $\text{foldl}\ g\ a\ l$ yield the same result.
List.foldr_ext theorem
(f g : α → β → β) (b : β) {l : List α} (H : ∀ a ∈ l, ∀ b : β, f a b = g a b) : foldr f b l = foldr g b l
Full source
theorem foldr_ext (f g : α → β → β) (b : β) {l : List α} (H : ∀ a ∈ l, ∀ b : β, f a b = g a b) :
    foldr f b l = foldr g b l := by
  induction l with | nil => rfl | cons hd tl ih => ?_
  simp only [mem_cons, or_imp, forall_and, forall_eq] at H
  simp only [foldr, ih H.2, H.1]
Right Fold Equality Under Pointwise Function Equality
Informal description
For any functions $f, g : \alpha \to \beta \to \beta$, any initial value $b : \beta$, and any list $l$ of elements of type $\alpha$, if for every element $a \in l$ and every $b' : \beta$ we have $f(a, b') = g(a, b')$, then the right fold operations $\text{foldr}\ f\ b\ l$ and $\text{foldr}\ g\ b\ l$ yield the same result.
List.foldl_concat theorem
(f : β → α → β) (b : β) (x : α) (xs : List α) : List.foldl f b (xs ++ [x]) = f (List.foldl f b xs) x
Full source
theorem foldl_concat
    (f : β → α → β) (b : β) (x : α) (xs : List α) :
    List.foldl f b (xs ++ [x]) = f (List.foldl f b xs) x := by
  simp only [List.foldl_append, List.foldl]
Left Fold over Concatenated List Equals Fold then Apply
Informal description
For any function $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, element $x \in \alpha$, and list $xs$ of elements of type $\alpha$, the left fold of $f$ over the concatenated list $xs \mathbin{+\kern-0.5ex+} [x]$ with initial value $b$ equals $f$ applied to the left fold of $f$ over $xs$ with initial value $b$ and the element $x$. In symbols: $$\text{foldl}\ f\ b\ (xs \mathbin{+\kern-0.5ex+} [x]) = f\ (\text{foldl}\ f\ b\ xs)\ x$$
List.foldr_concat theorem
(f : α → β → β) (b : β) (x : α) (xs : List α) : List.foldr f b (xs ++ [x]) = (List.foldr f (f x b) xs)
Full source
theorem foldr_concat
    (f : α → β → β) (b : β) (x : α) (xs : List α) :
    List.foldr f b (xs ++ [x]) = (List.foldr f (f x b) xs) := by
  simp only [List.foldr_append, List.foldr]
Right Fold over Concatenated List Equals Fold with Modified Initial Value
Informal description
For any function $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, element $x \in \alpha$, and list $xs$ of elements of type $\alpha$, the right fold of $f$ over the concatenated list $xs \mathbin{+\kern-0.5ex+} [x]$ with initial value $b$ equals the right fold of $f$ over $xs$ with initial value $f(x, b)$. In symbols: $$\text{foldr}\ f\ b\ (xs \mathbin{+\kern-0.5ex+} [x]) = \text{foldr}\ f\ (f\ x\ b)\ xs$$
List.foldl_fixed' theorem
{f : α → β → α} {a : α} (hf : ∀ b, f a b = a) : ∀ l : List β, foldl f a l = a
Full source
theorem foldl_fixed' {f : α → β → α} {a : α} (hf : ∀ b, f a b = a) : ∀ l : List β, foldl f a l = a
  | [] => rfl
  | b :: l => by rw [foldl_cons, hf b, foldl_fixed' hf l]
Left Fold with Fixed Point Property
Informal description
For any function $f : \alpha \to \beta \to \alpha$ and fixed value $a \in \alpha$ such that $f(a, b) = a$ for all $b \in \beta$, and for any list $l$ of elements of type $\beta$, the left fold of $f$ over $l$ with initial value $a$ equals $a$. In symbols: $$\text{foldl}\ f\ a\ l = a$$
List.foldr_fixed' theorem
{f : α → β → β} {b : β} (hf : ∀ a, f a b = b) : ∀ l : List α, foldr f b l = b
Full source
theorem foldr_fixed' {f : α → β → β} {b : β} (hf : ∀ a, f a b = b) : ∀ l : List α, foldr f b l = b
  | [] => rfl
  | a :: l => by rw [foldr_cons, foldr_fixed' hf l, hf a]
Right Fold with Fixed Point Property
Informal description
Let $f : \alpha \to \beta \to \beta$ be a function and $b \in \beta$ be an element such that $f(a, b) = b$ for all $a \in \alpha$. Then for any list $l$ of elements of type $\alpha$, the right fold of $l$ with initial value $b$ and operation $f$ equals $b$. In symbols: $$\text{foldr}\ f\ b\ l = b$$
List.foldl_fixed theorem
{a : α} : ∀ l : List β, foldl (fun a _ => a) a l = a
Full source
@[simp]
theorem foldl_fixed {a : α} : ∀ l : List β, foldl (fun a _ => a) a l = a :=
  foldl_fixed' fun _ => rfl
Left Fold with Constant Function Preserves Initial Value
Informal description
For any fixed value $a \in \alpha$ and any list $l$ of elements of type $\beta$, the left fold of the constant function (that ignores its second argument and returns $a$) over $l$ with initial value $a$ equals $a$. In symbols: $$\text{foldl}\ (\lambda x\ \_. x)\ a\ l = a$$
List.foldr_fixed theorem
{b : β} : ∀ l : List α, foldr (fun _ b => b) b l = b
Full source
@[simp]
theorem foldr_fixed {b : β} : ∀ l : List α, foldr (fun _ b => b) b l = b :=
  foldr_fixed' fun _ => rfl
Right Fold with Constant Function Preserves Initial Value
Informal description
For any element $b$ of type $\beta$ and any list $l$ of elements of type $\alpha$, the right fold of $l$ with the constant function (ignoring its first argument) and initial value $b$ equals $b$. In symbols: $$\text{foldr}\ (\lambda \_\ b', b')\ b\ l = b$$
List.foldr_eta theorem
(l : List α) : foldr cons [] l = l
Full source
@[deprecated foldr_cons_nil (since := "2025-02-10")]
theorem foldr_eta (l : List α) : foldr cons [] l = l := foldr_cons_nil
Right Fold with Cons Reconstructs Original List
Informal description
For any list $l$ of elements of type $\alpha$, the right fold of $l$ with the `cons` operation (list constructor) and the empty list `[]` as the initial value yields the original list $l$. In other words, $\text{foldr}\ (\mathbin{\mathtt{::}})\ []\ l = l$.
List.reverse_foldl theorem
{l : List α} : reverse (foldl (fun t h => h :: t) [] l) = l
Full source
theorem reverse_foldl {l : List α} : reverse (foldl (fun t h => h :: t) [] l) = l := by
  simp
Reversing a Left Fold Recovers the Original List
Informal description
For any list $l$ of elements of type $\alpha$, reversing the result of left-folding $l$ with the operation `(fun t h => h :: t)` (which prepends each element to the accumulator) starting from the empty list `[]` yields the original list $l$. In other words, $\text{reverse}(\text{foldl} (\lambda t\ h, h :: t)\ []\ l) = l$.
List.foldl_hom₂ theorem
(l : List ι) (f : α → β → γ) (op₁ : α → ι → α) (op₂ : β → ι → β) (op₃ : γ → ι → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ a i) (op₂ b i) = op₃ (f a b) i) : foldl op₃ (f a b) l = f (foldl op₁ a l) (foldl op₂ b l)
Full source
theorem foldl_hom₂ (l : List ι) (f : α → β → γ) (op₁ : α → ι → α) (op₂ : β → ι → β)
    (op₃ : γ → ι → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ a i) (op₂ b i) = op₃ (f a b) i) :
    foldl op₃ (f a b) l = f (foldl op₁ a l) (foldl op₂ b l) :=
  Eq.symm <| by
    revert a b
    induction l <;> intros <;> [rfl; simp only [*, foldl]]
Homomorphism Property of Left Fold with Binary Operation
Informal description
Let $l$ be a list of elements of type $\iota$, and let $f : \alpha \to \beta \to \gamma$ be a function. Suppose we have three binary operations: - $op₁ : \alpha \to \iota \to \alpha$, - $op₂ : \beta \to \iota \to \beta$, - $op₃ : \gamma \to \iota \to \gamma$. Given initial values $a : \alpha$ and $b : \beta$, if for all $a \in \alpha$, $b \in \beta$, and $i \in \iota$, the following holds: $$f(op₁(a, i), op₂(b, i)) = op₃(f(a, b), i),$$ then the left fold of $op₃$ over $l$ with initial value $f(a, b)$ is equal to $f$ applied to the left fold of $op₁$ over $l$ with initial value $a$ and the left fold of $op₂$ over $l$ with initial value $b$. In symbols: $$\text{foldl } op₃ (f(a, b)) l = f (\text{foldl } op₁ a l) (\text{foldl } op₂ b l).$$
List.foldr_hom₂ theorem
(l : List ι) (f : α → β → γ) (op₁ : ι → α → α) (op₂ : ι → β → β) (op₃ : ι → γ → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ i a) (op₂ i b) = op₃ i (f a b)) : foldr op₃ (f a b) l = f (foldr op₁ a l) (foldr op₂ b l)
Full source
theorem foldr_hom₂ (l : List ι) (f : α → β → γ) (op₁ : ι → α → α) (op₂ : ι → β → β)
    (op₃ : ι → γ → γ) (a : α) (b : β) (h : ∀ a b i, f (op₁ i a) (op₂ i b) = op₃ i (f a b)) :
    foldr op₃ (f a b) l = f (foldr op₁ a l) (foldr op₂ b l) := by
  revert a
  induction l <;> intros <;> [rfl; simp only [*, foldr]]
Homomorphism Property of Right Fold with Binary Function
Informal description
Let $l$ be a list of elements of type $\iota$, and let $f : \alpha \to \beta \to \gamma$ be a binary function. Suppose we have three operations: - $\text{op}_1 : \iota \to \alpha \to \alpha$, - $\text{op}_2 : \iota \to \beta \to \beta$, - $\text{op}_3 : \iota \to \gamma \to \gamma$, and initial values $a : \alpha$ and $b : \beta$. If for all $a \in \alpha$, $b \in \beta$, and $i \in \iota$, the following holds: \[ f(\text{op}_1(i, a), \text{op}_2(i, b)) = \text{op}_3(i, f(a, b)), \] then the right fold of $l$ using $\text{op}_3$ with initial value $f(a, b)$ is equal to $f$ applied to the right folds of $l$ using $\text{op}_1$ and $\text{op}_2$ with initial values $a$ and $b$, respectively. That is, \[ \text{foldr}(\text{op}_3, f(a, b), l) = f(\text{foldr}(\text{op}_1, a, l), \text{foldr}(\text{op}_2, b, l)). \]
List.injective_foldl_comp theorem
{l : List (α → α)} {f : α → α} (hl : ∀ f ∈ l, Function.Injective f) (hf : Function.Injective f) : Function.Injective (@List.foldl (α → α) (α → α) Function.comp f l)
Full source
theorem injective_foldl_comp {l : List (α → α)} {f : α → α}
    (hl : ∀ f ∈ l, Function.Injective f) (hf : Function.Injective f) :
    Function.Injective (@List.foldl (α → α) (α → α) Function.comp f l) := by
  induction l generalizing f with
  | nil => exact hf
  | cons lh lt l_ih =>
    apply l_ih fun _ h => hl _ (List.mem_cons_of_mem _ h)
    apply Function.Injective.comp hf
    apply hl _ mem_cons_self
Injectivity of Left-Folded Function Composition
Informal description
Let $l$ be a list of functions from $\alpha$ to $\alpha$, and let $f : \alpha \to \alpha$ be an injective function. If every function in $l$ is injective, then the composition of these functions via left fold (with $f$ as the initial value) is also injective. In symbols: If $\forall g \in l$, $g$ is injective, and $f$ is injective, then the function $\text{foldl}~(\circ)~f~l$ is injective.
List.append_cons_inj_of_not_mem theorem
{x₁ x₂ z₁ z₂ : List α} {a₁ a₂ : α} (notin_x : a₂ ∉ x₁) (notin_z : a₂ ∉ z₁) : x₁ ++ a₁ :: z₁ = x₂ ++ a₂ :: z₂ ↔ x₁ = x₂ ∧ a₁ = a₂ ∧ z₁ = z₂
Full source
/-- Consider two lists `l₁` and `l₂` with designated elements `a₁` and `a₂` somewhere in them:
`l₁ = x₁ ++ [a₁] ++ z₁` and `l₂ = x₂ ++ [a₂] ++ z₂`.
Assume the designated element `a₂` is present in neither `x₁` nor `z₁`.
We conclude that the lists are equal (`l₁ = l₂`) if and only if their respective parts are equal
(`x₁ = x₂ ∧ a₁ = a₂ ∧ z₁ = z₂`). -/
lemma append_cons_inj_of_not_mem {x₁ x₂ z₁ z₂ : List α} {a₁ a₂ : α}
    (notin_x : a₂ ∉ x₁) (notin_z : a₂ ∉ z₁) :
    x₁ ++ a₁ :: z₁ = x₂ ++ a₂ :: z₂ ↔ x₁ = x₂ ∧ a₁ = a₂ ∧ z₁ = z₂ := by
  constructor
  · simp only [append_eq_append_iff, cons_eq_append_iff, cons_eq_cons]
    rintro (⟨c, rfl, ⟨rfl, rfl, rfl⟩ | ⟨d, rfl, rfl⟩⟩ |
      ⟨c, rfl, ⟨rfl, rfl, rfl⟩ | ⟨d, rfl, rfl⟩⟩) <;> simp_all
  · rintro ⟨rfl, rfl, rfl⟩
    rfl
Equality of Concatenated Lists with Distinct Middle Elements
Informal description
Let $x_1, x_2, z_1, z_2$ be lists and $a_1, a_2$ be elements of type $\alpha$. Suppose $a_2$ does not appear in $x_1$ or $z_1$. Then the concatenated lists $x_1 \mathbin{+\kern-0.5em+} [a_1] \mathbin{+\kern-0.5em+} z_1$ and $x_2 \mathbin{+\kern-0.5em+} [a_2] \mathbin{+\kern-0.5em+} z_2$ are equal if and only if their corresponding components are equal: $x_1 = x_2$, $a_1 = a_2$, and $z_1 = z_2$.
List.foldl1_eq_foldr1 theorem
[hassoc : Std.Associative f] : ∀ a b l, foldl f a (l ++ [b]) = foldr f b (a :: l)
Full source
theorem foldl1_eq_foldr1 [hassoc : Std.Associative f] :
    ∀ a b l, foldl f a (l ++ [b]) = foldr f b (a :: l)
  | _, _, nil => rfl
  | a, b, c :: l => by
    simp only [cons_append, foldl_cons, foldr_cons, foldl1_eq_foldr1 _ _ l]
    rw [hassoc.assoc]
Equality of Left and Right Folds for Associative Operations
Informal description
Let $f$ be an associative binary operation on a type $\alpha$. For any elements $a, b \in \alpha$ and any list $l$ of elements of $\alpha$, the left fold of $f$ over the list $l$ appended with $[b]$, starting with initial value $a$, is equal to the right fold of $f$ over the list $a :: l$, starting with initial value $b$. In other words, \[ \text{foldl}~f~a~(l \mathbin{+\kern-1.5ex+} [b]) = \text{foldr}~f~b~(a :: l). \]
List.foldl_eq_of_comm_of_assoc theorem
[hcomm : Std.Commutative f] [hassoc : Std.Associative f] : ∀ a b l, foldl f a (b :: l) = f b (foldl f a l)
Full source
theorem foldl_eq_of_comm_of_assoc [hcomm : Std.Commutative f] [hassoc : Std.Associative f] :
    ∀ a b l, foldl f a (b :: l) = f b (foldl f a l)
  | a, b, nil => hcomm.comm a b
  | a, b, c :: l => by
    simp only [foldl_cons]
    have : RightCommutative f := inferInstance
    rw [← foldl_eq_of_comm_of_assoc .., this.right_comm, foldl_cons]
Left Fold Recursive Step for Commutative and Associative Operations
Informal description
Let $f$ be a binary operation that is both commutative and associative. For any elements $a, b$ and any list $l$, the left fold of $f$ over the list $b :: l$ with initial accumulator $a$ equals $f$ applied to $b$ and the left fold of $f$ over $l$ with initial accumulator $a$. In other words, \[ \text{foldl}\, f\, a\, (b :: l) = f\, b\, (\text{foldl}\, f\, a\, l). \]
List.foldl_eq_foldr theorem
[Std.Commutative f] [Std.Associative f] : ∀ a l, foldl f a l = foldr f a l
Full source
theorem foldl_eq_foldr [Std.Commutative f] [Std.Associative f] :
    ∀ a l, foldl f a l = foldr f a l
  | _, nil => rfl
  | a, b :: l => by
    simp only [foldr_cons, foldl_eq_of_comm_of_assoc]
    rw [foldl_eq_foldr a l]
Equality of Left and Right Folds for Commutative and Associative Operations
Informal description
Let $f$ be a binary operation that is both commutative and associative. For any element $a$ and any list $l$, the left fold of $f$ over $l$ with initial accumulator $a$ is equal to the right fold of $f$ over $l$ with initial accumulator $a$. In other words, \[ \text{foldl}\, f\, a\, l = \text{foldr}\, f\, a\, l. \]
List.foldl_eq_of_comm' theorem
: ∀ a b l, foldl f a (b :: l) = f (foldl f a l) b
Full source
theorem foldl_eq_of_comm' : ∀ a b l, foldl f a (b :: l) = f (foldl f a l) b
  | _, _, [] => rfl
  | a, b, c :: l => by rw [foldl, foldl, foldl, ← foldl_eq_of_comm' .., foldl, hf]
Left Fold Recursive Step for General Operation
Informal description
For any binary operation $f$, accumulator $a$, element $b$, and list $l$, the left fold of $f$ over the list $b :: l$ with initial accumulator $a$ is equal to applying $f$ to the left fold of $f$ over $l$ with initial accumulator $a$ and the element $b$. In other words, $\text{foldl}\, f\, a\, (b :: l) = f\, (\text{foldl}\, f\, a\, l)\, b$.
List.foldl_eq_foldr' theorem
: ∀ a l, foldl f a l = foldr (flip f) a l
Full source
theorem foldl_eq_foldr' : ∀ a l, foldl f a l = foldr (flip f) a l
  | _, [] => rfl
  | a, b :: l => by rw [foldl_eq_of_comm' hf, foldr, foldl_eq_foldr' ..]; rfl
Equivalence of Left Fold and Right Fold with Flipped Operation
Informal description
For any binary operation $f$, accumulator $a$, and list $l$, the left fold of $f$ over $l$ with initial accumulator $a$ is equal to the right fold of the flipped operation $\text{flip}\,f$ over $l$ with initial accumulator $a$. In other words, $\text{foldl}\, f\, a\, l = \text{foldr}\, (\text{flip}\, f)\, a\, l$.
List.foldr_eq_of_comm' theorem
(hf : ∀ a b c, f a (f b c) = f b (f a c)) : ∀ a b l, foldr f a (b :: l) = foldr f (f b a) l
Full source
theorem foldr_eq_of_comm' (hf : ∀ a b c, f a (f b c) = f b (f a c)) :
    ∀ a b l, foldr f a (b :: l) = foldr f (f b a) l
  | _, _, [] => rfl
  | a, b, c :: l => by rw [foldr, foldr, foldr, hf, ← foldr_eq_of_comm' hf ..]; rfl
Right Fold Commutativity Property for Lists
Informal description
Let $f$ be a binary operation that satisfies the commutativity-like property $f(a, f(b, c)) = f(b, f(a, c))$ for all $a, b, c$. Then for any initial value $a$, element $b$, and list $l$, the right fold operation satisfies: \[ \text{foldr } f\ a\ (b :: l) = \text{foldr } f\ (f(b, a))\ l \]
List.foldl_op_eq_op_foldr_assoc theorem
: ∀ {l : List α} {a₁ a₂}, ((l <*> a₁) ⋆ a₂) = a₁ ⋆ l.foldr (· ⋆ ·) a₂
Full source
theorem foldl_op_eq_op_foldr_assoc :
    ∀ {l : List α} {a₁ a₂}, ((l <*> a₁) ⋆ a₂) = a₁ ⋆ l.foldr (· ⋆ ·) a₂
  | [], _, _ => rfl
  | a :: l, a₁, a₂ => by
    simp only [foldl_cons, foldr_cons, foldl_assoc, ha.assoc]; rw [foldl_op_eq_op_foldr_assoc]
Equality between left-fold and right-fold operations with associative operator
Informal description
Let $l$ be a list of elements of type $\alpha$, and let $a₁, a₂$ be elements of $\alpha$. Suppose $\star$ is an associative binary operation on $\alpha$. Then the following equality holds: $$(l \text{ foldl } \star \text{ applied to } a₁) \star a₂ = a₁ \star (l \text{ foldr } \star \text{ applied to } a₂)$$ where $\text{foldl}$ and $\text{foldr}$ denote left and right fold operations respectively.
List.foldl_assoc_comm_cons theorem
{l : List α} {a₁ a₂} : ((a₁ :: l) <*> a₂) = a₁ ⋆ l <*> a₂
Full source
theorem foldl_assoc_comm_cons {l : List α} {a₁ a₂} : ((a₁ :: l) <*> a₂) = a₁ ⋆ l <*> a₂ := by
  rw [foldl_cons, hc.comm, foldl_assoc]
Associativity-commutativity property of left fold with cons
Informal description
For any list $l$ of elements of type $\alpha$ and elements $a_1, a_2$ of type $\alpha$, the left fold operation `⋆` satisfies the associativity and commutativity property: $$(a_1 :: l) \star a_2 = a_1 \star (l \star a_2)$$ where `::` denotes list cons (prepending an element to a list).
List.foldrM_eq_foldr theorem
(f : α → β → m β) (b l) : foldrM f b l = foldr (fun a mb => mb >>= f a) (pure b) l
Full source
theorem foldrM_eq_foldr (f : α → β → m β) (b l) :
    foldrM f b l = foldr (fun a mb => mb >>= f a) (pure b) l := by induction l <;> simp [*]
Monadic Right Fold Equivalence
Informal description
For any monad `m`, function `f : α → β → m β`, initial value `b : β`, and list `l : List α`, the monadic right fold `foldrM f b l` is equal to the right fold of the function `(fun a mb => mb >>= f a)` applied to the list `l` with initial value `pure b`.
List.foldlM_eq_foldl theorem
(f : β → α → m β) (b l) : List.foldlM f b l = foldl (fun mb a => mb >>= fun b => f b a) (pure b) l
Full source
theorem foldlM_eq_foldl (f : β → α → m β) (b l) :
    List.foldlM f b l = foldl (fun mb a => mb >>= fun b => f b a) (pure b) l := by
  suffices h :
    ∀ mb : m β, (mb >>= fun b => List.foldlM f b l) = foldl (fun mb a => mb >>= fun b => f b a) mb l
    by simp [← h (pure b)]
  induction l with
  | nil => intro; simp
  | cons _ _ l_ih => intro; simp only [List.foldlM, foldl, ← l_ih, functor_norm]
Monadic Left Fold Equals Standard Left Fold
Informal description
For any monad `m`, function `f : β → α → m β`, initial value `b : β`, and list `l : List α`, the monadic left fold `List.foldlM f b l` is equal to the standard left fold `foldl` applied to the function `fun mb a => mb >>= fun b => f b a` with initial value `pure b` and list `l`.
List.sizeOf_lt_sizeOf_of_mem theorem
[SizeOf α] {x : α} {l : List α} (hx : x ∈ l) : SizeOf.sizeOf x < SizeOf.sizeOf l
Full source
@[deprecated "Deprecated without replacement." (since := "2025-02-07")]
theorem sizeOf_lt_sizeOf_of_mem [SizeOf α] {x : α} {l : List α} (hx : x ∈ l) :
    SizeOf.sizeOf x < SizeOf.sizeOf l := by
  induction l with | nil => ?_ | cons h t ih => ?_ <;> cases hx <;> rw [cons.sizeOf_spec]
  · omega
  · specialize ih ‹_›
    omega
Size Comparison for List Members: $\text{sizeOf}(x) < \text{sizeOf}(l)$ when $x \in l$
Informal description
For any type `α` with a `SizeOf` instance, if an element `x` is a member of a list `l`, then the size of `x` is strictly less than the size of `l`.
List.length_eq_length_filter_add theorem
{l : List (α)} (f : α → Bool) : l.length = (l.filter f).length + (l.filter (!f ·)).length
Full source
theorem length_eq_length_filter_add {l : List (α)} (f : α → Bool) :
    l.length = (l.filter f).length + (l.filter (! f ·)).length := by
  simp_rw [← List.countP_eq_length_filter, l.length_eq_countP_add_countP f, Bool.not_eq_true,
    Bool.decide_eq_false]
Length Decomposition of Filtered Lists: $|l| = |\text{filter } f\ l| + |\text{filter } (\neg f)\ l|$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $f : \alpha \to \text{Bool}$, the length of $l$ is equal to the sum of the lengths of the sublists obtained by filtering $l$ with $f$ and its negation $\neg f$.
List.filterMap_eq_flatMap_toList theorem
(f : α → Option β) (l : List α) : l.filterMap f = l.flatMap fun a ↦ (f a).toList
Full source
theorem filterMap_eq_flatMap_toList (f : α → Option β) (l : List α) :
    l.filterMap f = l.flatMap fun a ↦ (f a).toList := by
  induction l with | nil => ?_ | cons a l ih => ?_ <;> simp [filterMap_cons]
  rcases f a <;> simp [ih]
`filterMap` as `flatMap` of `toList` Composition
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any list $l : \text{List } \alpha$, the result of applying `filterMap` with $f$ to $l$ is equal to the result of applying `flatMap` with the composition of `toList` and $f$ to $l$. In other words, \[ \text{filterMap } f \, l = \text{flatMap } (\lambda a \mapsto \text{toList } (f \, a)) \, l. \]
List.filterMap_congr theorem
{f g : α → Option β} {l : List α} (h : ∀ x ∈ l, f x = g x) : l.filterMap f = l.filterMap g
Full source
theorem filterMap_congr {f g : α → Option β} {l : List α}
    (h : ∀ x ∈ l, f x = g x) : l.filterMap f = l.filterMap g := by
  induction l <;> simp_all [filterMap_cons]
Congruence Property of `filterMap` on Lists
Informal description
For any two functions $f, g : \alpha \to \text{Option } \beta$ and a list $l$ of elements of type $\alpha$, if $f(x) = g(x)$ for every $x \in l$, then the results of applying `filterMap` with $f$ and $g$ to $l$ are equal, i.e., $\text{filterMap } f \, l = \text{filterMap } g \, l$.
List.filterMap_eq_map_iff_forall_eq_some theorem
{f : α → Option β} {g : α → β} {l : List α} : l.filterMap f = l.map g ↔ ∀ x ∈ l, f x = some (g x)
Full source
theorem filterMap_eq_map_iff_forall_eq_some {f : α → Option β} {g : α → β} {l : List α} :
    l.filterMap f = l.map g ↔ ∀ x ∈ l, f x = some (g x) where
  mp := by
    induction l with | nil => simp | cons a l ih => ?_
    rcases ha : f a with - | b <;> simp [ha, filterMap_cons]
    · intro h
      simpa [show (filterMap f l).length = l.length + 1 from by simp[h], Nat.add_one_le_iff]
        using List.length_filterMap_le f l
    · rintro rfl h
      exact ⟨rfl, ih h⟩
  mpr h := Eq.trans (filterMap_congr <| by simpa) (congr_fun filterMap_eq_map _)
Equivalence of `filterMap` and `map` via Option Condition
Informal description
For a function $f : \alpha \to \text{Option } \beta$, a function $g : \alpha \to \beta$, and a list $l$ of elements of type $\alpha$, the filtered map of $f$ over $l$ equals the map of $g$ over $l$ if and only if for every element $x \in l$, $f(x) = \text{some } (g(x))$. In mathematical notation: \[ \text{filterMap } f \, l = \text{map } g \, l \leftrightarrow \forall x \in l, f(x) = \text{some } (g(x)) \]
List.filter_singleton theorem
{a : α} : [a].filter p = bif p a then [a] else []
Full source
theorem filter_singleton {a : α} : [a].filter p = bif p a then [a] else [] :=
  rfl
Filtering a Singleton List: $\text{filter } p \text{ } [a] = \text{if } p(a) \text{ then } [a] \text{ else } []$
Informal description
For any predicate `p` and element `a` of type `α`, the result of filtering the singleton list `[a]` with `p` is `[a]` if `p a` holds, and the empty list `[]` otherwise. In mathematical notation: \[ \text{filter } p \text{ } [a] = \begin{cases} [a] & \text{if } p(a) \\ [] & \text{otherwise} \end{cases} \]
List.filter_eq_foldr theorem
(p : α → Bool) (l : List α) : filter p l = foldr (fun a out => bif p a then a :: out else out) [] l
Full source
theorem filter_eq_foldr (p : α → Bool) (l : List α) :
    filter p l = foldr (fun a out => bif p a then a :: out else out) [] l := by
  induction l <;> simp [*, filter]; rfl
Filter as Right Fold
Informal description
For any predicate `p : α → Bool` and any list `l : List α`, the filtered list `filter p l` is equal to the right fold of the function `(fun a out => bif p a then a :: out else out)` over `l` with initial value `[]`. In mathematical notation, this can be written as: \[ \text{filter } p \, l = \text{foldr } (\lambda a \, \text{out}, \text{if } p(a) \text{ then } a :: \text{out else out}) \, [] \, l \]
List.filter_subset' theorem
(l : List α) : filter p l ⊆ l
Full source
@[simp]
theorem filter_subset' (l : List α) : filterfilter p l ⊆ l :=
  filter_sublist.subset
Filtered List is Subset of Original List
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the list obtained by filtering $l$ with $p$ is a subset of $l$. In other words, every element in $\mathrm{filter}\ p\ l$ is also an element of $l$.
List.of_mem_filter theorem
{a : α} {l} (h : a ∈ filter p l) : p a
Full source
theorem of_mem_filter {a : α} {l} (h : a ∈ filter p l) : p a := (mem_filter.1 h).2
Elements in Filtered List Satisfy Predicate
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, if $a$ is in the filtered list $\mathrm{filter}\, p\, l$, then the predicate $p$ holds for $a$.
List.mem_of_mem_filter theorem
{a : α} {l} (h : a ∈ filter p l) : a ∈ l
Full source
theorem mem_of_mem_filter {a : α} {l} (h : a ∈ filter p l) : a ∈ l :=
  filter_subset' l h
Membership in Filtered List Implies Membership in Original List
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, if $a$ is in the filtered list $\mathrm{filter}\, p\, l$, then $a$ is also in the original list $l$.
List.mem_filter_of_mem theorem
{a : α} {l} (h₁ : a ∈ l) (h₂ : p a) : a ∈ filter p l
Full source
theorem mem_filter_of_mem {a : α} {l} (h₁ : a ∈ l) (h₂ : p a) : a ∈ filter p l :=
  mem_filter.2 ⟨h₁, h₂⟩
Membership in Filtered List from Membership in Original List
Informal description
For any element $a$ in a list $l$ and any predicate $p$, if $p(a)$ holds, then $a$ is in the filtered list $\mathrm{filter}\, p\, l$.
List.monotone_filter_right theorem
(l : List α) ⦃p q : α → Bool⦄ (h : ∀ a, p a → q a) : l.filter p <+ l.filter q
Full source
theorem monotone_filter_right (l : List α) ⦃p q : α → Bool⦄
    (h : ∀ a, p a → q a) : l.filter p <+ l.filter q := by
  induction l with
  | nil => rfl
  | cons hd tl IH =>
    by_cases hp : p hd
    · rw [filter_cons_of_pos hp, filter_cons_of_pos (h _ hp)]
      exact IH.cons_cons hd
    · rw [filter_cons_of_neg hp]
      by_cases hq : q hd
      · rw [filter_cons_of_pos hq]
        exact sublist_cons_of_sublist hd IH
      · rw [filter_cons_of_neg hq]
        exact IH
Monotonicity of List Filtering: $\mathrm{filter}\, p\, l \subseteq \mathrm{filter}\, q\, l$ when $p \Rightarrow q$
Informal description
For any list $l$ of type $\alpha$ and any predicates $p, q : \alpha \to \mathrm{Bool}$, if for every element $a \in \alpha$, $p(a)$ implies $q(a)$, then the filtered list $\mathrm{filter}\, p\, l$ is a sublist of $\mathrm{filter}\, q\, l$.
List.map_filter theorem
{f : α → β} (hf : Injective f) (l : List α) [DecidablePred fun b => ∃ a, p a ∧ f a = b] : (l.filter p).map f = (l.map f).filter fun b => ∃ a, p a ∧ f a = b
Full source
lemma map_filter {f : α → β} (hf : Injective f) (l : List α)
    [DecidablePred fun b => ∃ a, p a ∧ f a = b] :
    (l.filter p).map f = (l.map f).filter fun b => ∃ a, p a ∧ f a = b := by
  simp [comp_def, filter_map, hf.eq_iff]
Map-Filter Commutation for Injective Functions
Informal description
Let $f : \alpha \to \beta$ be an injective function and $l$ be a list of elements of type $\alpha$. Then the map of $f$ over the filtered list $\mathrm{filter}\, p\, l$ is equal to the filtered list obtained by applying $f$ to each element of $l$ and then filtering for elements $b$ such that there exists an $a \in l$ with $p(a)$ and $f(a) = b$.
List.filter_attach' theorem
(l : List α) (p : { a // a ∈ l } → Bool) [DecidableEq α] : l.attach.filter p = (l.filter fun x => ∃ h, p ⟨x, h⟩).attach.map (Subtype.map id fun _ => mem_of_mem_filter)
Full source
lemma filter_attach' (l : List α) (p : {a // a ∈ l}Bool) [DecidableEq α] :
    l.attach.filter p =
      (l.filter fun x => ∃ h, p ⟨x, h⟩).attach.map (Subtype.map id fun _ => mem_of_mem_filter) := by
  classical
  refine map_injective_iff.2 Subtype.coe_injective ?_
  simp [comp_def, map_filter _ Subtype.coe_injective]
Filter-Attach Commutation for Lists with Subtype Predicates
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on the subtype $\{a \in \alpha \mid a \in l\}$, the filtered list obtained by first attaching indices to $l$ and then filtering with $p$ is equal to the list obtained by first filtering $l$ with the predicate $\lambda x, \exists h, p \langle x, h \rangle$, attaching indices to the result, and then mapping with the subtype inclusion function. More precisely, let $\text{attach}(l)$ be the list of pairs $(x, h_x)$ where $x \in l$ and $h_x$ is a proof of $x \in l$. Then: \[ \text{filter } p (\text{attach}(l)) = \text{map } (\text{Subtype.map id } \lambda \_ \Rightarrow \text{mem\_of\_mem\_filter}) (\text{attach}(\text{filter } (\lambda x, \exists h, p \langle x, h \rangle) \, l)) \] where $\text{Subtype.map id } \lambda \_ \Rightarrow \text{mem\_of\_mem\_filter}$ is the function that maps $(x, h_x)$ to $(x, h'_x)$, with $h'_x$ being a proof that $x \in \text{filter } (\lambda x, \exists h, p \langle x, h \rangle) \, l$.
List.filter_attach theorem
(l : List α) (p : α → Bool) : (l.attach.filter fun x => p x : List { x // x ∈ l }) = (l.filter p).attach.map (Subtype.map id fun _ => mem_of_mem_filter)
Full source
lemma filter_attach (l : List α) (p : α → Bool) :
    (l.attach.filter fun x => p x : List {x // x ∈ l}) =
      (l.filter p).attach.map (Subtype.map id fun _ => mem_of_mem_filter) :=
  map_injective_iff.2 Subtype.coe_injective <| by
    simp_rw [map_map, comp_def, Subtype.map, id, ← Function.comp_apply (g := Subtype.val),
      ← filter_map, attach_map_subtype_val]
Filter-Attach Commutation for Lists
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the filtered list obtained by first attaching indices to $l$ and then filtering with $p$ is equal to the list obtained by first filtering $l$ with $p$, attaching indices to the result, and then mapping with the subtype inclusion function. More precisely, let $\text{attach}(l)$ be the list of pairs $(x, h_x)$ where $x \in l$ and $h_x$ is a proof of $x \in l$. Then: \[ \text{filter } p (\text{attach}(l)) = \text{map } (\text{Subtype.map id } \lambda \_ \Rightarrow \text{mem\_of\_mem\_filter}) (\text{attach}(\text{filter } p \, l)) \] where $\text{Subtype.map id } \lambda \_ \Rightarrow \text{mem\_of\_mem\_filter}$ is the function that maps $(x, h_x)$ to $(x, h'_x)$, with $h'_x$ being a proof that $x \in \text{filter } p \, l$.
List.filter_comm theorem
(q) (l : List α) : filter p (filter q l) = filter q (filter p l)
Full source
lemma filter_comm (q) (l : List α) : filter p (filter q l) = filter q (filter p l) := by
  simp [Bool.and_comm]
Commutativity of List Filtering Operations
Informal description
For any list $l$ of elements of type $\alpha$ and any predicates $p$ and $q$ on $\alpha$, the result of first filtering $l$ with $q$ and then with $p$ is equal to the result of first filtering $l$ with $p$ and then with $q$. In other words, the order of filtering operations is commutative: \[ \text{filter } p (\text{filter } q \, l) = \text{filter } q (\text{filter } p \, l). \]
List.filter_true theorem
(l : List α) : filter (fun _ => true) l = l
Full source
@[simp]
theorem filter_true (l : List α) :
    filter (fun _ => true) l = l := by induction l <;> simp [*, filter]
Filtering with True Predicate Preserves List
Informal description
For any list $l$ of elements of type $\alpha$, filtering $l$ with the constant predicate that always returns `true` yields the original list $l$, i.e., \[ \text{filter } (\lambda \_. \text{true}) \, l = l. \]
List.filter_false theorem
(l : List α) : filter (fun _ => false) l = []
Full source
@[simp]
theorem filter_false (l : List α) :
    filter (fun _ => false) l = [] := by induction l <;> simp [*, filter]
Filtering with False Predicate Yields Empty List
Informal description
For any list $l$ of elements of type $\alpha$, filtering $l$ with the constant false predicate returns the empty list, i.e., \[ \text{filter } (\lambda \_. \text{false}) \, l = []. \]
List.length_eraseP_add_one theorem
{l : List α} {a} (al : a ∈ l) (pa : p a) : (l.eraseP p).length + 1 = l.length
Full source
@[simp]
theorem length_eraseP_add_one {l : List α} {a} (al : a ∈ l) (pa : p a) :
    (l.eraseP p).length + 1 = l.length := by
  let ⟨_, l₁, l₂, _, _, h₁, h₂⟩ := exists_of_eraseP al pa
  rw [h₂, h₁, length_append, length_append]
  rfl
Length Relation for Predicate-Based List Removal: $|\text{eraseP}\, p\, l| + 1 = |l|$
Informal description
For any list $l$ of type $\alpha$ and an element $a \in l$ satisfying the predicate $p(a)$, the length of the list obtained by removing all elements satisfying $p$ from $l$ (denoted by $l.\text{eraseP}\, p$) plus one equals the length of the original list $l$. That is, $|l.\text{eraseP}\, p| + 1 = |l|$.
List.length_erase_add_one theorem
{a : α} {l : List α} (h : a ∈ l) : (l.erase a).length + 1 = l.length
Full source
@[simp] theorem length_erase_add_one {a : α} {l : List α} (h : a ∈ l) :
    (l.erase a).length + 1 = l.length := by
  rw [erase_eq_eraseP, length_eraseP_add_one h (decide_eq_true rfl)]
Length Relation for Element Removal: $|\text{erase}\, a\, l| + 1 = |l|$
Informal description
For any list $l$ of elements of type $\alpha$ and an element $a \in l$, the length of the list obtained by removing the first occurrence of $a$ from $l$ (denoted by $l.\text{erase}\, a$) plus one equals the length of the original list $l$. That is, $|l.\text{erase}\, a| + 1 = |l|$.
List.map_erase theorem
[DecidableEq β] {f : α → β} (finj : Injective f) {a : α} (l : List α) : map f (l.erase a) = (map f l).erase (f a)
Full source
theorem map_erase [DecidableEq β] {f : α → β} (finj : Injective f) {a : α} (l : List α) :
    map f (l.erase a) = (map f l).erase (f a) := by
  have this : (a == ·) = (f a == f ·) := by ext b; simp [beq_eq_decide, finj.eq_iff]
  rw [erase_eq_eraseP, erase_eq_eraseP, eraseP_map, this]; rfl
Image of List Erasure under Injective Function: $f(\text{erase}\, l\, a) = \text{erase}\, (f\, l)\, (f\, a)$
Informal description
Let $f : \alpha \to \beta$ be an injective function, and let $a \in \alpha$. For any list $l$ of elements of type $\alpha$, the image of the list obtained by removing the first occurrence of $a$ from $l$ under $f$ is equal to the list obtained by removing the first occurrence of $f(a)$ from the image of $l$ under $f$. That is, \[ f(\text{erase}\, l\, a) = \text{erase}\, (f\, l)\, (f\, a). \]
List.map_foldl_erase theorem
[DecidableEq β] {f : α → β} (finj : Injective f) {l₁ l₂ : List α} : map f (foldl List.erase l₁ l₂) = foldl (fun l a => l.erase (f a)) (map f l₁) l₂
Full source
theorem map_foldl_erase [DecidableEq β] {f : α → β} (finj : Injective f) {l₁ l₂ : List α} :
    map f (foldl List.erase l₁ l₂) = foldl (fun l a => l.erase (f a)) (map f l₁) l₂ := by
  induction l₂ generalizing l₁ <;> [rfl; simp only [foldl_cons, map_erase finj, *]]
Image of Folded List Erasure under Injective Function: $f(\text{foldl erase}\, l_1\, l_2) = \text{foldl}\, (\lambda l\, a, \text{erase}\, l\, (f\, a))\, (f\, l_1)\, l_2$
Informal description
Let $f : \alpha \to \beta$ be an injective function, and let $l_1, l_2$ be lists of elements of type $\alpha$. Then the image under $f$ of the list obtained by successively removing each element of $l_2$ from $l_1$ is equal to the list obtained by successively removing the image of each element of $l_2$ from the image of $l_1$ under $f$. That is, \[ f(\text{foldl List.erase}\, l_1\, l_2) = \text{foldl}\, (\lambda l\, a, l.\text{erase}\, (f\, a))\, (f\, l_1)\, l_2. \]
List.erase_getElem theorem
[DecidableEq ι] {l : List ι} {i : ℕ} (hi : i < l.length) : Perm (l.erase l[i]) (l.eraseIdx i)
Full source
theorem erase_getElem [DecidableEq ι] {l : List ι} {i : } (hi : i < l.length) :
    Perm (l.erase l[i]) (l.eraseIdx i) := by
  induction l generalizing i with
  | nil => simp
  | cons a l IH =>
    cases i with
    | zero => simp
    | succ i =>
      have hi' : i < l.length := by simpa using hi
      if ha : a = l[i] then
        simpa [ha] using .trans (perm_cons_erase (getElem_mem _)) (.cons _ (IH hi'))
      else
        simpa [ha] using IH hi'
Permutation of List Erasure Methods: `erase` vs `eraseIdx`
Informal description
For a list $l$ of elements of type $\iota$ with a decidable equality, and an index $i$ such that $i < \text{length}(l)$, the list obtained by erasing the element at position $i$ (via `eraseIdx`) is a permutation of the list obtained by erasing the first occurrence of the element $l[i]$ (via `erase`).
List.length_eraseIdx_add_one theorem
{l : List ι} {i : ℕ} (h : i < l.length) : (l.eraseIdx i).length + 1 = l.length
Full source
theorem length_eraseIdx_add_one {l : List ι} {i : } (h : i < l.length) :
    (l.eraseIdx i).length + 1 = l.length := by
  rw [length_eraseIdx]
  split <;> omega
Length Preservation After Element Removal: $|l.\text{eraseIdx}\ i| + 1 = |l|$
Informal description
For any list $l$ of type $\iota$ and any natural number $i$ such that $i$ is less than the length of $l$, the length of the list obtained by removing the element at index $i$ from $l$ (denoted as $l.\text{eraseIdx}\ i$) plus one equals the original length of $l$. In other words, $|l.\text{eraseIdx}\ i| + 1 = |l|$.
List.map_diff theorem
[DecidableEq β] {f : α → β} (finj : Injective f) {l₁ l₂ : List α} : map f (l₁.diff l₂) = (map f l₁).diff (map f l₂)
Full source
@[simp]
theorem map_diff [DecidableEq β] {f : α → β} (finj : Injective f) {l₁ l₂ : List α} :
    map f (l₁.diff l₂) = (map f l₁).diff (map f l₂) := by
  simp only [diff_eq_foldl, foldl_map, map_foldl_erase finj]
Image of List Difference under Injective Function: $f(l_1 \setminus l_2) = f(l_1) \setminus f(l_2)$
Informal description
Let $f : \alpha \to \beta$ be an injective function, and let $l_1, l_2$ be lists of elements of type $\alpha$. Then the image under $f$ of the list difference $l_1 \setminus l_2$ is equal to the difference of the images of $l_1$ and $l_2$ under $f$, i.e., \[ f(l_1 \setminus l_2) = f(l_1) \setminus f(l_2). \]
List.choose_spec theorem
(hp : ∃ a, a ∈ l ∧ p a) : choose p l hp ∈ l ∧ p (choose p l hp)
Full source
theorem choose_spec (hp : ∃ a, a ∈ l ∧ p a) : choosechoose p l hp ∈ lchoose p l hp ∈ l ∧ p (choose p l hp) :=
  (chooseX p l hp).property
First Satisfying Element in List Meets Predicate and Membership Conditions
Informal description
Given a list $l$ of elements of type $\alpha$ and a decidable predicate $p$ on $\alpha$, if there exists an element $a \in l$ such that $p(a)$ holds, then the element returned by `List.choose p l hp` satisfies both $a \in l$ and $p(a)$.
List.choose_mem theorem
(hp : ∃ a, a ∈ l ∧ p a) : choose p l hp ∈ l
Full source
theorem choose_mem (hp : ∃ a, a ∈ l ∧ p a) : choosechoose p l hp ∈ l :=
  (choose_spec _ _ _).1
Membership of First Satisfying Element in List
Informal description
Given a list $l$ of elements of type $\alpha$ and a decidable predicate $p$ on $\alpha$, if there exists an element $a \in l$ such that $p(a)$ holds, then the element returned by $\text{choose}(p, l, hp)$ belongs to $l$.
List.choose_property theorem
(hp : ∃ a, a ∈ l ∧ p a) : p (choose p l hp)
Full source
theorem choose_property (hp : ∃ a, a ∈ l ∧ p a) : p (choose p l hp) :=
  (choose_spec _ _ _).2
First Satisfying Element in List Meets Predicate
Informal description
Given a list $l$ of elements of type $\alpha$ and a decidable predicate $p$ on $\alpha$, if there exists an element $a \in l$ such that $p(a)$ holds, then the element returned by $\text{choose}(p, l, hp)$ satisfies $p$.
List.forall_cons theorem
(p : α → Prop) (x : α) : ∀ l : List α, Forall p (x :: l) ↔ p x ∧ Forall p l
Full source
@[simp]
theorem forall_cons (p : α → Prop) (x : α) : ∀ l : List α, ForallForall p (x :: l) ↔ p x ∧ Forall p l
  | [] => (and_iff_left_of_imp fun _ ↦ trivial).symm
  | _ :: _ => Iff.rfl
Universal Quantification over Cons List: $(\forall y \in x::l, p(y)) \leftrightarrow p(x) \land (\forall y \in l, p(y))$
Informal description
For any predicate $p$ on elements of type $\alpha$, any element $x \in \alpha$, and any list $l$ of elements of type $\alpha$, the universal quantification `Forall p (x :: l)` holds if and only if $p(x)$ holds and `Forall p l` holds. In other words, all elements in the list `x :: l` satisfy $p$ if and only if $x$ satisfies $p$ and all elements in $l$ satisfy $p$.
List.forall_append theorem
{p : α → Prop} : ∀ {xs ys : List α}, Forall p (xs ++ ys) ↔ Forall p xs ∧ Forall p ys
Full source
@[simp]
theorem forall_append {p : α → Prop} : ∀ {xs ys : List α},
    ForallForall p (xs ++ ys) ↔ Forall p xs ∧ Forall p ys
  | [] => by simp
  | _ :: _ => by simp [forall_append, and_assoc]
Concatenation Preserves Universal Quantification over Lists
Informal description
For any predicate $p$ on elements of type $\alpha$ and any two lists $xs$ and $ys$ of type $\alpha$, the following equivalence holds: every element in the concatenated list $xs \mathbin{+\!\!+} ys$ satisfies $p$ if and only if every element in $xs$ satisfies $p$ and every element in $ys$ satisfies $p$. In symbols: $$\text{Forall } p (xs \mathbin{+\!\!+} ys) \leftrightarrow \text{Forall } p xs \land \text{Forall } p ys$$
List.forall_iff_forall_mem theorem
: ∀ {l : List α}, Forall p l ↔ ∀ x ∈ l, p x
Full source
theorem forall_iff_forall_mem : ∀ {l : List α}, ForallForall p l ↔ ∀ x ∈ l, p x
  | [] => (iff_true_intro <| forall_mem_nil _).symm
  | x :: l => by rw [forall_mem_cons, forall_cons, forall_iff_forall_mem]
Equivalence of List Forall and Membership Quantifier
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the following are equivalent: 1. The universal quantification `Forall p l` holds. 2. For every element $x$ in the list $l$, the predicate $p(x)$ holds. In symbols: $$\text{Forall } p\, l \leftrightarrow \forall x \in l, p(x)$$
List.Forall.imp theorem
(h : ∀ x, p x → q x) : ∀ {l : List α}, Forall p l → Forall q l
Full source
theorem Forall.imp (h : ∀ x, p x → q x) : ∀ {l : List α}, Forall p l → Forall q l
  | [] => id
  | x :: l => by
    simp only [forall_cons, and_imp]
    rw [← and_imp]
    exact And.imp (h x) (Forall.imp h)
Implication Preserves Universal Quantification over Lists
Informal description
Let $p$ and $q$ be predicates on a type $\alpha$, and suppose that for every $x \in \alpha$, $p(x)$ implies $q(x)$. Then for any list $l$ of elements of $\alpha$, if every element of $l$ satisfies $p$, then every element of $l$ also satisfies $q$.
List.forall_map_iff theorem
{p : β → Prop} (f : α → β) : Forall p (l.map f) ↔ Forall (p ∘ f) l
Full source
@[simp]
theorem forall_map_iff {p : β → Prop} (f : α → β) : ForallForall p (l.map f) ↔ Forall (p ∘ f) l := by
  induction l <;> simp [*]
Universal Quantifier Preservation under List Mapping
Informal description
For any list $l$ of elements of type $\alpha$, any predicate $p$ on $\beta$, and any function $f : \alpha \to \beta$, the following are equivalent: 1. Every element in the mapped list $\mathrm{map}\, f\, l$ satisfies $p$. 2. Every element in the original list $l$ satisfies $p \circ f$ (i.e., $p$ applied to $f$ of the element). In other words, $\mathrm{Forall}\, p\, (\mathrm{map}\, f\, l) \leftrightarrow \mathrm{Forall}\, (p \circ f)\, l$.
List.instDecidablePredForall instance
(p : α → Prop) [DecidablePred p] : DecidablePred (Forall p)
Full source
instance (p : α → Prop) [DecidablePred p] : DecidablePred (Forall p) := fun _ =>
  decidable_of_iff' _ forall_iff_forall_mem
Decidability of Universal Quantification over Lists with Decidable Predicate
Informal description
For any predicate $p$ on a type $\alpha$ such that $p$ is decidable (i.e., for every $x \in \alpha$, it is decidable whether $p(x)$ holds), the universal quantification `Forall p l` over any list $l$ of elements of $\alpha$ is also decidable. In other words, given a decidable predicate $p$, one can algorithmically determine whether all elements in a list $l$ satisfy $p$.
List.get_attach theorem
(l : List α) (i) : (l.attach.get i).1 = l.get ⟨i, length_attach (l := l) ▸ i.2⟩
Full source
theorem get_attach (l : List α) (i) :
    (l.attach.get i).1 = l.get ⟨i, length_attach (l := l) ▸ i.2⟩ := by simp
Equality of Projected Attached List Element and Original List Element
Informal description
For any list $l$ of elements of type $\alpha$ and any index $i$, the first projection of the $i$-th element of the attached list (where each element is paired with its index) equals the $i$-th element of the original list $l$. More precisely, if we consider the attached list where each element $x$ in $l$ is paired with its index, then accessing the $i$-th element of this attached list and taking its first component gives the same result as directly accessing the $i$-th element of $l$.
List.disjoint_pmap theorem
{p : α → Prop} {f : ∀ a : α, p a → β} {s t : List α} (hs : ∀ a ∈ s, p a) (ht : ∀ a ∈ t, p a) (hf : ∀ (a a' : α) (ha : p a) (ha' : p a'), f a ha = f a' ha' → a = a') (h : Disjoint s t) : Disjoint (s.pmap f hs) (t.pmap f ht)
Full source
/-- The images of disjoint lists under a partially defined map are disjoint -/
theorem disjoint_pmap {p : α → Prop} {f : ∀ a : α, p a → β} {s t : List α}
    (hs : ∀ a ∈ s, p a) (ht : ∀ a ∈ t, p a)
    (hf : ∀ (a a' : α) (ha : p a) (ha' : p a'), f a ha = f a' ha' → a = a')
    (h : Disjoint s t) :
    Disjoint (s.pmap f hs) (t.pmap f ht) := by
  simp only [Disjoint, mem_pmap]
  rintro b ⟨a, ha, rfl⟩ ⟨a', ha', ha''⟩
  apply h ha
  rwa [hf a a' (hs a ha) (ht a' ha') ha''.symm]
Disjointness Preservation under Partial Map of Lists
Informal description
Let $p$ be a predicate on elements of type $\alpha$, and let $f$ be a partial function defined on elements satisfying $p$, mapping them to type $\beta$. For two lists $s$ and $t$ of elements of type $\alpha$, assume that: 1. Every element in $s$ satisfies $p$ (i.e., $\forall a \in s, p(a)$), 2. Every element in $t$ satisfies $p$ (i.e., $\forall a \in t, p(a)$), 3. $f$ is injective on its domain (i.e., $\forall a, a' \in \alpha$, if $p(a)$ and $p(a')$ hold and $f(a) = f(a')$, then $a = a'$), 4. $s$ and $t$ are disjoint (i.e., $s \cap t = \emptyset$). Then the images of $s$ and $t$ under the partial map $f$ are also disjoint, i.e., $\text{pmap}(f, s) \cap \text{pmap}(f, t) = \emptyset$.
List.disjoint_map theorem
{f : α → β} {s t : List α} (hf : Function.Injective f) (h : Disjoint s t) : Disjoint (s.map f) (t.map f)
Full source
/-- The images of disjoint lists under an injective map are disjoint -/
theorem disjoint_map {f : α → β} {s t : List α} (hf : Function.Injective f)
    (h : Disjoint s t) : Disjoint (s.map f) (t.map f) := by
  rw [← pmap_eq_map (fun _ _ ↦ trivial), ← pmap_eq_map (fun _ _ ↦ trivial)]
  exact disjoint_pmap _ _ (fun _ _ _ _ h' ↦ hf h') h
Disjointness Preservation under Injective Map of Lists
Informal description
Let $f : \alpha \to \beta$ be an injective function, and let $s$ and $t$ be two disjoint lists of elements of type $\alpha$. Then the images of $s$ and $t$ under $f$ are also disjoint, i.e., $\text{map}(f, s) \cap \text{map}(f, t) = \emptyset$.
List.Disjoint.of_map theorem
{f : α → β} {s t : List α} (h : Disjoint (s.map f) (t.map f)) : Disjoint s t
Full source
theorem Disjoint.of_map {f : α → β} {s t : List α} (h : Disjoint (s.map f) (t.map f)) :
    Disjoint s t := fun _a has hat ↦
  h (mem_map_of_mem has) (mem_map_of_mem hat)
Disjointness of Lists Implies Disjointness of Their Images Under a Function
Informal description
For any function $f : \alpha \to \beta$ and lists $s, t$ of elements of type $\alpha$, if the images of $s$ and $t$ under $f$ are disjoint (i.e., $s.map f$ and $t.map f$ have no common elements), then $s$ and $t$ themselves are disjoint (i.e., they have no common elements).
List.Disjoint.map_iff theorem
{f : α → β} {s t : List α} (hf : Function.Injective f) : Disjoint (s.map f) (t.map f) ↔ Disjoint s t
Full source
theorem Disjoint.map_iff {f : α → β} {s t : List α} (hf : Function.Injective f) :
    DisjointDisjoint (s.map f) (t.map f) ↔ Disjoint s t :=
  ⟨fun h ↦ h.of_map, fun h ↦ h.map hf⟩
Disjointness of Lists and Their Images Under Injective Function
Informal description
For any injective function $f : \alpha \to \beta$ and lists $s, t$ of elements of type $\alpha$, the images of $s$ and $t$ under $f$ are disjoint if and only if $s$ and $t$ themselves are disjoint. In other words, $\text{map}(f, s) \cap \text{map}(f, t) = \emptyset$ if and only if $s \cap t = \emptyset$.
List.Perm.disjoint_left theorem
{l₁ l₂ l : List α} (p : List.Perm l₁ l₂) : Disjoint l₁ l ↔ Disjoint l₂ l
Full source
theorem Perm.disjoint_left {l₁ l₂ l : List α} (p : List.Perm l₁ l₂) :
    DisjointDisjoint l₁ l ↔ Disjoint l₂ l := by
  simp_rw [List.disjoint_left, p.mem_iff]
Permutation Preserves Disjointness on Left
Informal description
For any lists $l₁, l₂, l$ of elements of type $\alpha$, if $l₁$ is a permutation of $l₂$ (denoted $l₁ \sim l₂$), then $l₁$ is disjoint from $l$ if and only if $l₂$ is disjoint from $l$. Here, two lists are disjoint if they have no common elements.
List.Perm.disjoint_right theorem
{l₁ l₂ l : List α} (p : List.Perm l₁ l₂) : Disjoint l l₁ ↔ Disjoint l l₂
Full source
theorem Perm.disjoint_right {l₁ l₂ l : List α} (p : List.Perm l₁ l₂) :
    DisjointDisjoint l l₁ ↔ Disjoint l l₂ := by
  simp_rw [List.disjoint_right, p.mem_iff]
Permutation Preserves Disjointness on Right
Informal description
For any lists $l₁, l₂, l$ of elements of type $\alpha$, if $l₁$ is a permutation of $l₂$ (denoted $l₁ \sim l₂$), then $l$ is disjoint from $l₁$ if and only if $l$ is disjoint from $l₂$. Here, two lists are disjoint if they have no common elements.
List.disjoint_reverse_left theorem
{l₁ l₂ : List α} : Disjoint l₁.reverse l₂ ↔ Disjoint l₁ l₂
Full source
@[simp]
theorem disjoint_reverse_left {l₁ l₂ : List α} : DisjointDisjoint l₁.reverse l₂ ↔ Disjoint l₁ l₂ :=
  reverse_perm _ |>.disjoint_left
Disjointness Preservation under List Reversal
Informal description
For any two lists $l₁$ and $l₂$ of elements of type $\alpha$, the reverse of $l₁$ is disjoint from $l₂$ if and only if $l₁$ is disjoint from $l₂$. Here, two lists are disjoint if they have no common elements.
List.disjoint_reverse_right theorem
{l₁ l₂ : List α} : Disjoint l₁ l₂.reverse ↔ Disjoint l₁ l₂
Full source
@[simp]
theorem disjoint_reverse_right {l₁ l₂ : List α} : DisjointDisjoint l₁ l₂.reverse ↔ Disjoint l₁ l₂ :=
  reverse_perm _ |>.disjoint_right
Disjointness is Preserved Under List Reversal on Right
Informal description
For any two lists $l₁$ and $l₂$ of elements of type $\alpha$, $l₁$ is disjoint from the reverse of $l₂$ if and only if $l₁$ is disjoint from $l₂$. Here, two lists are disjoint if they have no common elements.
List.lookup_graph theorem
(f : α → β) {a : α} {as : List α} (h : a ∈ as) : lookup a (as.map fun x => (x, f x)) = some (f a)
Full source
lemma lookup_graph (f : α → β) {a : α} {as : List α} (h : a ∈ as) :
    lookup a (as.map fun x => (x, f x)) = some (f a) := by
  induction as with
  | nil => exact (not_mem_nil h).elim
  | cons a' as ih =>
    by_cases ha : a = a'
    · simp [ha, lookup_cons]
    · simpa [lookup_cons, beq_false_of_ne ha] using ih (List.mem_of_ne_of_mem ha h)
Lookup in Mapped Pair List Yields Function Value
Informal description
For any function $f : \alpha \to \beta$, element $a \in \alpha$, and list $as$ of elements of $\alpha$, if $a$ is a member of $as$, then the lookup of $a$ in the list obtained by mapping each element $x$ of $as$ to the pair $(x, f(x))$ returns $\mathrm{some}(f(a))$.
List.range'_0 theorem
(a b : ℕ) : range' a b 0 = replicate b a
Full source
@[simp]
lemma range'_0 (a b : ) :
   range' a b 0 = replicate b a := by
  induction b with
  | zero => simp
  | succ b ih => simp [range'_succ, ih, replicate_succ]
Range' with Step Zero Equals Replicate
Informal description
For any natural numbers $a$ and $b$, the list `range' a b 0` is equal to the list obtained by replicating $a$ exactly $b$ times, i.e., $\text{range'}\ a\ b\ 0 = \text{replicate}\ b\ a$.
List.left_le_of_mem_range' theorem
{a b s x : ℕ} (hx : x ∈ List.range' a b s) : a ≤ x
Full source
lemma left_le_of_mem_range' {a b s x : }
    (hx : x ∈ List.range' a b s) : a ≤ x := by
  obtain ⟨i, _, rfl⟩ := List.mem_range'.mp hx
  exact le_add_right a (s * i)
Lower Bound Property of `range'` Lists
Informal description
For any natural numbers $a$, $b$, $s$, and $x$, if $x$ belongs to the list `range' a b s`, then $a \leq x$.