doc-next-gen

Init.Data.List.Lemmas

Module docstring

{"# Theorems about List operations.

For each List operation, we would like theorems describing the following, when relevant: * if it is a \"convenience\" function, a @[simp] lemma reducing it to more basic operations (e.g. List.partition_eq_filter_filter), and otherwise: * any special cases of equational lemmas that require additional hypotheses * lemmas for special cases of the arguments (e.g. List.map_id) * the length of the result (f L).length * the i-th element, described via (f L)[i] and/or (f L)[i]? (these should typically be @[simp]) * consequences for f L of the fact x ∈ L or x ∉ L * conditions characterising x ∈ f L (often but not always @[simp]) * injectivity statements, or congruence statements of the form p L M → f L = f M. * conditions characterising the result, i.e. of the form f L = M ↔ p M for some predicate p, along with special cases of M (e.g. List.append_eq_nil : L ++ M = [] ↔ L = [] ∧ M = []) * negative characterisations are also useful, e.g. List.cons_ne_nil * interactions with all previously described List operations where possible (some of these should be @[simp], particularly if the result can be described by a single operation) * characterising (∀ (i) (_ : i ∈ f L), P i), for some predicate P

Of course for any individual operation, not all of these will be relevant or helpful, so some judgement is required.

General principles for simp normal forms for List operations: * Conversion operations (e.g. toArray, or length) should be moved inwards aggressively, to make the conversion effective. * Similarly, operations which work on elements should be moved inwards in preference to \"structural\" operations on the list, e.g. we prefer to simplify List.map f (L ++ M) ~> (List.map f L) ++ (List.map f M), List.map f L.reverse ~> (List.map f L).reverse, and List.map f (L.take n) ~> (List.map f L).take n. * Arithmetic operations are \"light\", so e.g. we prefer to simplify drop i (drop j L) to drop (i + j) L, rather than the other way round. * Function compositions are \"light\", so we prefer to simplify (L.map f).map g to L.map (g ∘ f). * We try to avoid non-linear left hand sides (i.e. with subexpressions appearing multiple times), but this is only a weak preference. * Generally, we prefer that the right hand side does not introduce duplication, however generally duplication of higher order arguments (functions, predicates, etc) is allowed, as we expect to be able to compute these once they reach ground terms.

See also * Init.Data.List.Attach for definitions and lemmas about List.attach and List.pmap. * Init.Data.List.Count for lemmas about List.countP and List.count. * Init.Data.List.Erase for lemmas about List.eraseP and List.erase. * Init.Data.List.Find for lemmas about List.find?, List.findSome?, List.findIdx, List.findIdx?, and List.indexOf * Init.Data.List.MinMax for lemmas about List.min? and List.max?. * Init.Data.List.Pairwise for lemmas about List.Pairwise and List.Nodup. * Init.Data.List.Sublist for lemmas about List.Subset, List.Sublist, List.IsPrefix, List.IsSuffix, and List.IsInfix. * Init.Data.List.TakeDrop for additional lemmas about List.take and List.drop. * Init.Data.List.Zip for lemmas about List.zip, List.zipWith, List.zipWithAll, and List.unzip.

Further results, which first require developing further automation around Nat, appear in * Init.Data.List.Nat.Basic: miscellaneous lemmas * Init.Data.List.Nat.Range: List.range and List.enum * Init.Data.List.Nat.TakeDrop: List.take and List.drop

Also * Init.Data.List.Monadic for addiation lemmas about List.mapM and List.forM.

","## Preliminaries ","### nil ","### length ","### cons ","## L[i] and L[i]? ","### get and get?.

We simplify l.get i to l[i.1]'i.2 and l.get? i to l[i]?. ","### getElem!

We simplify l[i]! to (l[i]?).getD default. ","### getElem? and getElem ","### getD

We simplify away getD, replacing getD l n a with (l[n]?).getD a. Because of this, there is only minimal API for getD. ","### get!

We simplify l.get! i to l[i]!. ","### mem ","### isEmpty ","### any / all ","### set ","### BEq ","### isEqv ","### getLast ","### getLast? ","### getLast! ","## Head and tail ","### head ","### headD ","### tailD ","### tail ","## Basic operations ","### map ","### filter ","### filterMap ","### append ","### concat

Note that concat_eq_append is a @[simp] lemma, so concat should usually not appear in goals. As such there's no need for a thorough set of lemmas describing concat. ","### flatten ","### flatMap ","### replicate ","### reverse ","### foldlM and foldrM ","### foldl and foldr ","#### Further results about getLast and getLast? ","## Additional operations ","### leftpad ","## List membership ","### elem / contains ","## Sublists ","### partition

Because we immediately simplify partition into two filters for verification purposes, we do not separately develop much theory about it. ","### dropLast

dropLast is the specification for Array.pop, so theorems about List.dropLast are often used for theorems about Array.pop. ","### splitAt

We don't provide any API for splitAt, beyond the @[simp] lemma splitAt n l = (l.take n, l.drop n), which is proved in Init.Data.List.TakeDrop. ","## Manipulating elements ","### replace ","### insert ","## Logic ","### any / all ","### Legacy lemmas about get, get?, and get!.

Hopefully these should not be needed, in favour of lemmas about xs[i], xs[i]?, and xs[i]!, to which these simplify.

We may consider deprecating or downstreaming these lemmas. ","### Deprecations "}

List.nil_eq theorem
{α} {xs : List α} : [] = xs ↔ xs = []
Full source
@[simp] theorem nil_eq {α} {xs : List α} : [][] = xs ↔ xs = [] := by
  cases xs <;> simp
Empty List Equality: `[] = xs ↔ xs = []`
Informal description
For any list `xs` of elements of type `α`, the empty list `[]` is equal to `xs` if and only if `xs` is equal to the empty list `[]`. In other words, `[] = xs ↔ xs = []`.
List.ne_nil_of_length_eq_add_one theorem
(_ : length l = n + 1) : l ≠ []
Full source
theorem ne_nil_of_length_eq_add_one (_ : length l = n + 1) : l ≠ [] := fun _ => nomatch l
Non-emptiness of List with Length $n + 1$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $n$, if the length of $l$ is equal to $n + 1$, then $l$ is not the empty list.
List.ne_nil_of_length_pos theorem
(_ : 0 < length l) : l ≠ []
Full source
theorem ne_nil_of_length_pos (_ : 0 < length l) : l ≠ [] := fun _ => nomatch l
Non-empty list has positive length
Informal description
For any list $l$, if the length of $l$ is positive (i.e., $0 < \text{length}(l)$), then $l$ is not the empty list (i.e., $l \neq []$).
List.length_eq_zero abbrev
Full source
@[deprecated length_eq_zero_iff (since := "2025-02-24")]
abbrev length_eq_zero := @length_eq_zero_iff
Empty List Characterization by Length Zero
Informal description
For any list $l$, the length of $l$ is zero if and only if $l$ is the empty list, i.e., $\text{length}(l) = 0 \leftrightarrow l = []$.
List.length_pos_of_mem theorem
{a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
Full source
theorem length_pos_of_mem {a : α} : ∀ {l : List α}, a ∈ l → 0 < length l
  | _::_, _ => Nat.zero_lt_succ _
Non-empty list from membership: $a \in l \to 0 < \text{length}(l)$
Informal description
For any element $a$ in a list $l$ of type $\alpha$, the length of $l$ is strictly positive, i.e., $0 < \text{length}(l)$.
List.exists_mem_of_length_pos theorem
: ∀ {l : List α}, 0 < length l → ∃ a, a ∈ l
Full source
theorem exists_mem_of_length_pos : ∀ {l : List α}, 0 < length l → ∃ a, a ∈ l
  | _::_, _ => ⟨_, .head ..⟩
Non-empty lists contain at least one element
Informal description
For any non-empty list $l$ (i.e., a list with length greater than 0), there exists an element $a$ in $l$.
List.length_pos_iff_exists_mem theorem
{l : List α} : 0 < length l ↔ ∃ a, a ∈ l
Full source
theorem length_pos_iff_exists_mem {l : List α} : 0 < length l ↔ ∃ a, a ∈ l :=
  ⟨exists_mem_of_length_pos, fun ⟨_, h⟩ => length_pos_of_mem h⟩
Characterization of Non-Empty Lists: $0 < \text{length}(l) \leftrightarrow \exists a \in l$
Informal description
For any list $l$ of type $\alpha$, the length of $l$ is strictly positive if and only if there exists an element $a$ in $l$. In other words, $0 < \text{length}(l) \leftrightarrow \exists a, a \in l$.
List.exists_mem_of_length_eq_add_one theorem
: ∀ {l : List α}, l.length = n + 1 → ∃ a, a ∈ l
Full source
theorem exists_mem_of_length_eq_add_one :
    ∀ {l : List α}, l.length = n + 1 → ∃ a, a ∈ l
  | _::_, _ => ⟨_, .head ..⟩
Existence of Element in List of Length $n + 1$
Informal description
For any list $l$ of type $\alpha$ whose length is equal to $n + 1$ for some natural number $n$, there exists an element $a$ in $l$.
List.exists_cons_of_length_pos theorem
: ∀ {l : List α}, 0 < l.length → ∃ h t, l = h :: t
Full source
theorem exists_cons_of_length_pos : ∀ {l : List α}, 0 < l.length∃ h t, l = h :: t
  | _::_, _ => ⟨_, _, rfl⟩
Decomposition of Non-Empty Lists into Head and Tail
Informal description
For any non-empty list $l$ (i.e., a list with length greater than 0), there exists a head element $h$ and a tail list $t$ such that $l$ can be expressed as the cons operation $h :: t$.
List.length_pos_iff_exists_cons theorem
: ∀ {l : List α}, 0 < l.length ↔ ∃ h t, l = h :: t
Full source
theorem length_pos_iff_exists_cons :
    ∀ {l : List α}, 0 < l.length ↔ ∃ h t, l = h :: t :=
  ⟨exists_cons_of_length_pos, fun ⟨_, _, eq⟩ => eq ▸ Nat.succ_pos _⟩
Positive Length of List is Equivalent to Existence of Head and Tail
Informal description
For any list $l$ of type $\alpha$, the length of $l$ is positive (i.e., $0 < \text{length}(l)$) if and only if there exists an element $h$ and a tail list $t$ such that $l$ can be written as $h :: t$.
List.exists_cons_of_length_eq_add_one theorem
: ∀ {l : List α}, l.length = n + 1 → ∃ h t, l = h :: t
Full source
theorem exists_cons_of_length_eq_add_one :
    ∀ {l : List α}, l.length = n + 1 → ∃ h t, l = h :: t
  | _::_, _ => ⟨_, _, rfl⟩
Decomposition of List with Length $n+1$ into Head and Tail
Informal description
For any list $l$ of type $\alpha$ whose length is equal to $n + 1$ for some natural number $n$, there exists an element $h$ and a tail list $t$ such that $l$ can be expressed as the cons (prepend) operation $h :: t$.
List.length_pos abbrev
Full source
@[deprecated length_pos_iff (since := "2025-02-24")]
abbrev length_pos := @length_pos_iff
Positive Length Implies Non-Empty List
Informal description
For any list $l$ of type $\alpha$, if the length of $l$ is positive (i.e., $0 < \text{length}(l)$), then $l$ is not the empty list (i.e., $l \neq []$).
List.ne_nil_iff_length_pos theorem
{l : List α} : l ≠ [] ↔ 0 < length l
Full source
theorem ne_nil_iff_length_pos {l : List α} : l ≠ []l ≠ [] ↔ 0 < length l :=
  length_pos_iff.symm
Non-empty list iff positive length
Informal description
For any list $l$ of elements of type $\alpha$, the list $l$ is non-empty if and only if its length is positive, i.e., $l \neq [] \leftrightarrow 0 < \text{length}(l)$.
List.length_eq_one_iff theorem
{l : List α} : length l = 1 ↔ ∃ a, l = [a]
Full source
theorem length_eq_one_iff {l : List α} : lengthlength l = 1 ↔ ∃ a, l = [a] :=
  ⟨fun h => match l, h with | [_], _ => ⟨_, rfl⟩, fun ⟨_, h⟩ => by simp [h]⟩
Characterization of Singleton Lists via Length: $\text{length}(l) = 1 \leftrightarrow \exists a, l = [a]$
Informal description
For any list $l$ of type $\alpha$, the length of $l$ is equal to $1$ if and only if there exists an element $a$ of type $\alpha$ such that $l$ is the singleton list $[a]$.
List.length_eq_one abbrev
Full source
@[deprecated length_eq_one_iff (since := "2025-02-24")]
abbrev length_eq_one := @length_eq_one_iff
Characterization of Singleton Lists via Length: $\text{length}(l) = 1 \leftrightarrow \exists a, l = [a]$
Informal description
For any list $l$ of type $\alpha$, the length of $l$ is equal to $1$ if and only if there exists an element $a$ of type $\alpha$ such that $l$ is the singleton list $[a]$.
List.cons_ne_nil theorem
(a : α) (l : List α) : a :: l ≠ []
Full source
theorem cons_ne_nil (a : α) (l : List α) : a :: la :: l ≠ [] := nofun
Non-emptiness of cons operation on lists
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the list constructed by prepending $a$ to $l$ is not equal to the empty list, i.e., $a :: l \neq []$.
List.cons_ne_self theorem
(a : α) (l : List α) : a :: l ≠ l
Full source
@[simp]
theorem cons_ne_self (a : α) (l : List α) : a :: la :: l ≠ l := mt (congrArg length) (Nat.succ_ne_self _)
List Inequality: $a :: l \neq l$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the list obtained by prepending $a$ to $l$ is not equal to $l$ itself, i.e., $a :: l \neq l$.
List.ne_cons_self theorem
{a : α} {l : List α} : l ≠ a :: l
Full source
@[simp] theorem ne_cons_self {a : α} {l : List α} : l ≠ a :: l := by
  rw [ne_eq, eq_comm]
  simp
List is not equal to its own cons extension
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the list $l$ is not equal to the list obtained by prepending $a$ to $l$, i.e., $l \neq a :: l$.
List.head_eq_of_cons_eq theorem
(H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂
Full source
theorem head_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : h₁ = h₂ := (cons.inj H).1
Equality of Cons Lists Implies Equality of Heads
Informal description
If two non-empty lists are equal, then their first elements are equal. That is, for any elements $h_1, h_2$ of type $\alpha$ and any lists $t_1, t_2$ of type $\text{List}\,\alpha$, if $h_1 :: t_1 = h_2 :: t_2$, then $h_1 = h_2$.
List.tail_eq_of_cons_eq theorem
(H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂
Full source
theorem tail_eq_of_cons_eq (H : h₁ :: t₁ = h₂ :: t₂) : t₁ = t₂ := (cons.inj H).2
Equality of Tails in Cons-Equal Lists
Informal description
Given two non-empty lists $h_1 :: t_1$ and $h_2 :: t_2$ of type $\text{List}\,\alpha$ that are equal, their tails $t_1$ and $t_2$ are also equal.
List.cons_inj_right theorem
(a : α) {l l' : List α} : a :: l = a :: l' ↔ l = l'
Full source
theorem cons_inj_right (a : α) {l l' : List α} : a :: la :: l = a :: l' ↔ l = l' :=
  ⟨tail_eq_of_cons_eq, congrArg _⟩
Equality of Lists with Identical Heads: $a :: l = a :: l' \leftrightarrow l = l'$
Informal description
For any element $a$ of type $\alpha$ and any lists $l, l'$ of type $\text{List}\,\alpha$, the equality $a :: l = a :: l'$ holds if and only if $l = l'$.
List.cons_eq_cons theorem
{a b : α} {l l' : List α} : a :: l = b :: l' ↔ a = b ∧ l = l'
Full source
theorem cons_eq_cons {a b : α} {l l' : List α} : a :: la :: l = b :: l' ↔ a = b ∧ l = l' :=
  List.cons.injEq .. ▸ .rfl
Equality of Cons Lists: $a :: l = b :: l' \leftrightarrow a = b \land l = l'$
Informal description
For any elements $a, b$ of type $\alpha$ and any lists $l, l'$ of type $\text{List}\,\alpha$, the equality $a :: l = b :: l'$ holds if and only if $a = b$ and $l = l'$.
List.exists_cons_of_ne_nil theorem
: ∀ {l : List α}, l ≠ [] → ∃ b l', l = b :: l'
Full source
theorem exists_cons_of_ne_nil : ∀ {l : List α}, l ≠ []∃ b l', l = b :: l'
  | c :: l', _ => ⟨c, l', rfl⟩
Decomposition of Non-Empty Lists into Head and Tail
Informal description
For any non-empty list $l$ of elements of type $\alpha$, there exist an element $b \in \alpha$ and a list $l'$ such that $l$ can be expressed as the cons (prepend) operation $b :: l'$.
List.ne_nil_iff_exists_cons theorem
{l : List α} : l ≠ [] ↔ ∃ b l', l = b :: l'
Full source
theorem ne_nil_iff_exists_cons {l : List α} : l ≠ []l ≠ [] ↔ ∃ b l', l = b :: l' :=
  ⟨exists_cons_of_ne_nil, fun ⟨_, _, eq⟩ => eq.symm ▸ cons_ne_nil _ _⟩
Characterization of Non-Empty Lists via Head and Tail Existence
Informal description
A list $l$ of elements of type $\alpha$ is non-empty if and only if there exist an element $b \in \alpha$ and a list $l'$ such that $l$ can be expressed as the concatenation of $b$ and $l'$, i.e., $l = b :: l'$.
List.singleton_inj theorem
{α : Type _} {a b : α} : [a] = [b] ↔ a = b
Full source
theorem singleton_inj {α : Type _} {a b : α} : [a][a] = [b] ↔ a = b := by
  simp
Injectivity of Singleton List Construction: $[a] = [b] \leftrightarrow a = b$
Informal description
For any elements $a$ and $b$ of type $\alpha$, the singleton list $[a]$ is equal to $[b]$ if and only if $a$ is equal to $b$.
List.concat_ne_nil theorem
(a : α) (l : List α) : l ++ [a] ≠ []
Full source
@[simp] theorem concat_ne_nil (a : α) (l : List α) : l ++ [a] ≠ [] := by
  cases l <;> simp
Non-emptiness of List Concatenation with Singleton: $l \mathbin{+\!\!+} [a] \neq []$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the concatenation of $l$ with the singleton list $[a]$ is not the empty list, i.e., $l \mathbin{+\!\!+} [a] \neq []$.
List.get_eq_getElem theorem
{l : List α} {i : Fin l.length} : l.get i = l[i.1]'i.2
Full source
@[simp] theorem get_eq_getElem {l : List α} {i : Fin l.length} : l.get i = l[i.1]'i.2 := rfl
Equivalence of List Access Methods: $\text{get}(l, i) = l[i]$
Informal description
For any list $l$ of elements of type $\alpha$ and any valid index $i$ (where $i$ is a natural number less than the length of $l$), the element obtained by `l.get i` is equal to the element obtained by the list indexing operation $l[i]$.
List.get?_eq_none theorem
: ∀ {l : List α} {n}, length l ≤ n → l.get? n = none
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
theorem get?_eq_none : ∀ {l : List α} {n}, length l ≤ n → l.get? n = none
  | [], _, _ => rfl
  | _ :: l, _+1, h => get?_eq_none (l := l) <| Nat.le_of_succ_le_succ h
Out-of-Bounds List Access Yields `none`: $\text{length}(l) \leq n \to l[n]? = \text{none}$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $n$, if the length of $l$ is less than or equal to $n$, then the $n$-th element of $l$ (accessed via `get?`) is `none`.
List.get?_eq_get theorem
: ∀ {l : List α} {n} (h : n < l.length), l.get? n = some (get l ⟨n, h⟩)
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
theorem get?_eq_get : ∀ {l : List α} {n} (h : n < l.length), l.get? n = some (get l ⟨n, h⟩)
  | _ :: _, 0, _ => rfl
  | _ :: l, _+1, _ => get?_eq_get (l := l) _
Equivalence of List Element Access: $l[n]? = \text{some}(a)$ when $n < \text{length}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $n$ such that $n < \text{length}(l)$, the optional element access $l[n]?$ returns $\text{some}(a)$ where $a$ is the $n$-th element of $l$ (accessed via $\text{get}$ with proof that $n$ is within bounds).
List.get?_eq_some_iff theorem
: l.get? n = some a ↔ ∃ h, get l ⟨n, h⟩ = a
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
theorem get?_eq_some_iff : l.get? n = some a ↔ ∃ h, get l ⟨n, h⟩ = a :=
  ⟨fun e =>
    have : n < length l := Nat.gt_of_not_le fun hn => by cases get?_eq_none hn ▸ e
    ⟨this, by rwa [get?_eq_get this, Option.some.injEq] at e⟩,
  fun ⟨_, e⟩ => e ▸ get?_eq_get _⟩
Characterization of List Element Access: $l[n]? = \text{some}(a)$ if and only if $a$ is the $n$-th element of $l$
Informal description
For any list $l$ of elements of type $\alpha$, natural number $n$, and element $a$, the optional element access $l[n]?$ returns $\text{some}(a)$ if and only if there exists a proof $h$ that $n$ is within bounds of $l$ and the $n$-th element of $l$ (accessed via $\text{get}$) equals $a$.
List.get?_eq_none_iff theorem
: l.get? n = none ↔ length l ≤ n
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
theorem get?_eq_none_iff : l.get? n = none ↔ length l ≤ n :=
  ⟨fun e => Nat.ge_of_not_lt (fun h' => by cases e ▸ get?_eq_some_iff.2 ⟨h', rfl⟩), get?_eq_none⟩
Characterization of Out-of-Bounds List Access: $l[n]? = \text{none} \leftrightarrow \text{length}(l) \leq n$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number $n$, the optional element access $l[n]?$ returns `none` if and only if the length of $l$ is less than or equal to $n$.
List.get?_eq_getElem? theorem
{l : List α} {i : Nat} : l.get? i = l[i]?
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12"), simp]
theorem get?_eq_getElem? {l : List α} {i : Nat} : l.get? i = l[i]? := by
  simp only [getElem?_def]; split
  · exact (get?_eq_get ‹_›)
  · exact (get?_eq_none_iff.2 <| Nat.not_lt.1 ‹_›)
Equivalence of Traditional and Notation-Based List Lookup: $l.\text{get?}\ i = l[i]?$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number index $i$, the traditional list lookup operation $l.\text{get?}\ i$ is equal to the optional element access notation $l[i]?$.
List.getElem!_eq_getElem?_getD theorem
[Inhabited α] {l : List α} {i : Nat} : l[i]! = (l[i]?).getD (default : α)
Full source
@[simp] theorem getElem!_eq_getElem?_getD [Inhabited α] {l : List α} {i : Nat} :
    l[i]! = (l[i]?).getD (default : α) := by
  simp only [getElem!_def]
  match l[i]? with
  | some _ => simp
  | none => simp
Equivalence of List Bang Access and Default Value Operation: $l[i]! = (l[i]?).\text{getD}\ \text{default}$
Informal description
For any inhabited type $\alpha$, list $l$ of type $\text{List}\ \alpha$, and natural number index $i$, the element access operation $l[i]!$ is equal to the default value operation applied to the optional element access $l[i]?$ with the default value being the designated element of $\alpha$.
List.getElem?_nil theorem
{i : Nat} : ([] : List α)[i]? = none
Full source
@[simp] theorem getElem?_nil {i : Nat} : ([] : List α)[i]? = none := rfl
Empty List Optional Lookup Yields None
Informal description
For any natural number index $i$, the optional lookup operation on the empty list returns `none`, i.e., $\text{nil}[i]? = \text{none}$.
List.getElem_cons theorem
{l : List α} (w : i < (a :: l).length) : (a :: l)[i] = if h : i = 0 then a else l[i - 1]'(match i, h with | i + 1, _ => succ_lt_succ_iff.mp w)
Full source
theorem getElem_cons {l : List α} (w : i < (a :: l).length) :
    (a :: l)[i] =
      if h : i = 0 then a else l[i-1]'(match i, h with | i+1, _ => succ_lt_succ_iff.mp w) := by
  cases i <;> simp
Element Access in Cons List: $(a :: l)[i] = a$ if $i=0$, else $l[i-1]$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and index $i$ such that $i < \text{length}(a :: l)$, the element at position $i$ in the list $a :: l$ is equal to $a$ if $i = 0$, and otherwise it is equal to the element at position $i-1$ in $l$.
List.getElem?_cons_zero theorem
{l : List α} : (a :: l)[0]? = some a
Full source
theorem getElem?_cons_zero {l : List α} : (a::l)[0]? = some a := rfl
Optional Indexing of Cons List at Zero Returns Head Element
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the optional indexing operation on the cons list $(a :: l)$ at index $0$ returns $\text{some}\,a$, i.e., $(a :: l)[0]? = \text{some}\,a$.
List.getElem?_cons_succ theorem
{l : List α} : (a :: l)[i + 1]? = l[i]?
Full source
@[simp] theorem getElem?_cons_succ {l : List α} : (a::l)[i+1]? = l[i]? := rfl
Optional Lookup on Cons List at Successor Index
Informal description
For any list `l` of type `List α` and natural number index `i`, the optional lookup operation on the cons list `a :: l` at index `i + 1` is equal to the optional lookup operation on `l` at index `i`. That is, $(a :: l)[i + 1]? = l[i]?$.
List.getElem?_cons theorem
: (a :: l)[i]? = if i = 0 then some a else l[i - 1]?
Full source
theorem getElem?_cons : (a :: l)[i]? = if i = 0 then some a else l[i-1]? := by
  cases i <;> simp [getElem?_cons_zero]
Optional Indexing of Cons List: $(a :: l)[i]? = \text{if } i = 0 \text{ then some } a \text{ else } l[i-1]?$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the optional indexing operation on the cons list $(a :: l)$ at index $i$ satisfies: $$(a :: l)[i]? = \begin{cases} \text{some}\,a & \text{if } i = 0 \\ l[i-1]? & \text{otherwise} \end{cases}$$
List.getElem?_eq_some_iff theorem
{l : List α} : l[i]? = some a ↔ ∃ h : i < l.length, l[i] = a
Full source
theorem getElem?_eq_some_iff {l : List α} : l[i]?l[i]? = some a ↔ ∃ h : i < l.length, l[i] = a :=
  match l with
  | [] => by simp
  | _ :: l => by
    simp only [getElem?_cons, length_cons]
    split <;> rename_i h
    · simp_all
    · match i, h with
      | i + 1, h => simp [getElem?_eq_some_iff, Nat.succ_lt_succ_iff]
Characterization of Optional List Indexing: $l[i]? = \text{some}\,a \leftrightarrow i < \text{length}\,l \land l[i] = a$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and natural number index $i$, the optional indexing operation $l[i]?$ returns $\text{some}\,a$ if and only if $i$ is a valid index for $l$ (i.e., $i < \text{length}\,l$) and the element at index $i$ in $l$ is equal to $a$. In symbols: $$l[i]? = \text{some}\,a \leftrightarrow \exists h : i < \text{length}\,l, l[i] = a$$
List.some_eq_getElem?_iff theorem
{l : List α} : some a = l[i]? ↔ ∃ h : i < l.length, l[i] = a
Full source
theorem some_eq_getElem?_iff {l : List α} : somesome a = l[i]? ↔ ∃ h : i < l.length, l[i] = a := by
  rw [eq_comm, getElem?_eq_some_iff]
Characterization of Optional List Indexing: $\text{some}\,a = l[i]? \leftrightarrow i < \text{length}\,l \land l[i] = a$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and natural number index $i$, the equality $\text{some}\,a = l[i]?$ holds if and only if $i$ is a valid index for $l$ (i.e., $i < \text{length}\,l$) and the element at index $i$ in $l$ is equal to $a$. In symbols: $$\text{some}\,a = l[i]? \leftrightarrow \exists h : i < \text{length}\,l, l[i] = a$$
List.some_getElem_eq_getElem?_iff theorem
{xs : List α} {i : Nat} (h : i < xs.length) : (some xs[i] = xs[i]?) ↔ True
Full source
@[simp] theorem some_getElem_eq_getElem?_iff {xs : List α} {i : Nat} (h : i < xs.length) :
    (some xs[i] = xs[i]?) ↔ True := by
  simp [h]
Equivalence of Some List Element and Optional Indexing for Valid Indices
Informal description
For any list $xs$ of type $\text{List}\,\alpha$ and natural number index $i$ such that $i < \text{length}\,xs$, the equality $\text{some}\,xs[i] = xs[i]?$ holds if and only if the true proposition $\text{True}$ holds.
List.getElem?_eq_some_getElem_iff theorem
{xs : List α} {i : Nat} (h : i < xs.length) : (xs[i]? = some xs[i]) ↔ True
Full source
@[simp] theorem getElem?_eq_some_getElem_iff {xs : List α} {i : Nat} (h : i < xs.length) :
    (xs[i]? = some xs[i]) ↔ True := by
  simp [h]
Optional Indexing Yields Some Element for Valid Indices
Informal description
For any list $xs$ of type $\text{List}\,\alpha$ and natural number index $i$ such that $i < \text{length}\,xs$, the optional indexing operation $xs[i]?$ equals $\text{some}\,xs[i]$ if and only if the true proposition $\text{True}$ holds.
List.getElem_eq_iff theorem
{l : List α} {i : Nat} (h : i < l.length) : l[i] = x ↔ l[i]? = some x
Full source
theorem getElem_eq_iff {l : List α} {i : Nat} (h : i < l.length) : l[i]l[i] = x ↔ l[i]? = some x := by
  simp only [getElem?_eq_some_iff]
  exact ⟨fun w => ⟨h, w⟩, fun h => h.2⟩
Equivalence of List Indexing and Optional Lookup: $l[i] = x \leftrightarrow l[i]? = \text{some } x$
Informal description
For any list $l$ of type $\alpha$, natural number index $i$ such that $i < \text{length}(l)$, and element $x$ of type $\alpha$, the $i$-th element of $l$ equals $x$ if and only if the optional lookup of the $i$-th element of $l$ returns $\text{some } x$.
List.getElem_eq_getElem?_get theorem
{l : List α} {i : Nat} (h : i < l.length) : l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h])
Full source
theorem getElem_eq_getElem?_get {l : List α} {i : Nat} (h : i < l.length) :
    l[i] = l[i]?.get (by simp [getElem?_eq_getElem, h]) := by
  simp [getElem_eq_iff]
Equality of List Indexing and Optional Lookup Value: $l[i] = l[i]?.get$ for Valid Indices
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$ such that $i < \text{length}(l)$, the $i$-th element of $l$ equals the value obtained from the optional lookup $l[i]?$ when it is non-empty (i.e., $l[i] = l[i]?.get$).
List.getD_getElem? theorem
{l : List α} {i : Nat} {d : α} : l[i]?.getD d = if p : i < l.length then l[i]'p else d
Full source
theorem getD_getElem? {l : List α} {i : Nat} {d : α} :
    l[i]?.getD d = if p : i < l.length then l[i]'p else d := by
  if h : i < l.length then
    simp [h, getElem?_def]
  else
    have p : i ≥ l.length := Nat.le_of_not_gt h
    simp [getElem?_eq_none p, h]
Default Value for Optional List Indexing: $l[i]?.getD d = \text{if } i < \text{length}(l) \text{ then } l[i] \text{ else } d$
Informal description
For any list $l$ of type $\alpha$, natural number index $i$, and default value $d$ of type $\alpha$, the operation `l[i]?.getD d` is equal to `l[i]` if $i$ is a valid index for $l$ (i.e., $i < \text{length}(l)$), and otherwise returns $d$.
List.getElem_singleton theorem
{a : α} {i : Nat} (h : i < 1) : [a][i] = a
Full source
@[simp] theorem getElem_singleton {a : α} {i : Nat} (h : i < 1) : [a][a][i] = a :=
  match i, h with
  | 0, _ => rfl
Singleton List Indexing: $[a][i] = a$ for $i < 1$
Informal description
For any element $a$ of type $\alpha$ and natural number index $i$ such that $i < 1$, the $i$-th element of the singleton list $[a]$ is equal to $a$.
List.getElem?_singleton theorem
{a : α} {i : Nat} : [a][i]? = if i = 0 then some a else none
Full source
theorem getElem?_singleton {a : α} {i : Nat} : [a][a][i]? = if i = 0 then some a else none := by
  simp [getElem?_cons]
Optional Indexing of Singleton List: $[a][i]? = \text{if } i = 0 \text{ then some } a \text{ else none}$
Informal description
For any element $a$ of type $\alpha$ and natural number index $i$, the optional indexing operation on the singleton list $[a]$ satisfies: $$[a][i]? = \begin{cases} \text{some}\,a & \text{if } i = 0 \\ \text{none} & \text{otherwise} \end{cases}$$
List.getElem_of_eq theorem
{l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) : l[i] = l'[i]'(h ▸ w)
Full source
/--
If one has `l[i]` in an expression and `h : l = l'`,
`rw [h]` will give a "motive it not type correct" error, as it cannot rewrite the
implicit `i < l.length` to `i < l'.length` directly. The theorem `getElem_of_eq` can be used to make
such a rewrite, with `rw [getElem_of_eq h]`.
-/
theorem getElem_of_eq {l l' : List α} (h : l = l') {i : Nat} (w : i < l.length) :
    l[i] = l'[i]'(h ▸ w) := by cases h; rfl
Equality of List Elements Under List Equality
Informal description
Given two lists $l$ and $l'$ of type $\alpha$ such that $l = l'$, and a natural number index $i$ satisfying $i < \text{length}(l)$, the $i$-th element of $l$ is equal to the $i$-th element of $l'$ (where the proof that $i < \text{length}(l')$ is obtained by transporting $w$ along the equality $h$).
List.getElem_zero theorem
{l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos_iff.mp h)
Full source
theorem getElem_zero {l : List α} (h : 0 < l.length) : l[0] = l.head (length_pos_iff.mp h) :=
  match l, h with
  | _ :: _, _ => rfl
First Element Equals Head in Non-Empty Lists
Informal description
For any non-empty list $l$ of type $\alpha$ (i.e., $0 < \text{length}(l)$), the first element of $l$ (accessed via $l[0]$) is equal to the head of $l$.
List.ext_getElem? theorem
{l₁ l₂ : List α} (h : ∀ i : Nat, l₁[i]? = l₂[i]?) : l₁ = l₂
Full source
@[ext] theorem ext_getElem? {l₁ l₂ : List α} (h : ∀ i : Nat, l₁[i]? = l₂[i]?) : l₁ = l₂ :=
  match l₁, l₂, h with
  | [], [], _ => rfl
  | _ :: _, [], h => by simpa using h 0
  | [], _ :: _, h => by simpa using h 0
  | a :: l₁, a' :: l₂, h => by
    have h0 : some a = some a' := by simpa using h 0
    injection h0 with aa; simp only [aa, ext_getElem? fun n => by simpa using h (n+1)]
List Equality via Optional Indexing
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$, if for every natural number index $i$ the optional indexing operations satisfy $l_1[i]? = l_2[i]?$, then $l_1 = l_2$.
List.ext_getElem theorem
{l₁ l₂ : List α} (hl : length l₁ = length l₂) (h : ∀ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length), l₁[i]'h₁ = l₂[i]'h₂) : l₁ = l₂
Full source
theorem ext_getElem {l₁ l₂ : List α} (hl : length l₁ = length l₂)
    (h : ∀ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length), l₁[i]'h₁ = l₂[i]'h₂) : l₁ = l₂ :=
  ext_getElem? fun n =>
    if h₁ : n < length l₁ then by
      simp_all [getElem?_eq_getElem]
    else by
      have h₁ := Nat.le_of_not_lt h₁
      rw [getElem?_eq_none h₁, getElem?_eq_none]; rwa [← hl]
List Equality via Index-wise Element Comparison
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, if they have the same length and for every natural number index $i$ and proofs $h_1 : i < \text{length}\,l_1$ and $h_2 : i < \text{length}\,l_2$, the elements $l_1[i]$ and $l_2[i]$ are equal, then $l_1 = l_2$.
List.getElem_concat_length theorem
{l : List α} {a : α} {i : Nat} (h : i = l.length) (w) : (l ++ [a])[i]'w = a
Full source
@[simp] theorem getElem_concat_length {l : List α} {a : α} {i : Nat} (h : i = l.length) (w) :
    (l ++ [a])[i]'w = a := by
  subst h; simp
Element at Concatenation Length Equals Appended Element
Informal description
For any list $l$ of elements of type $\alpha$, any element $a \in \alpha$, and any natural number index $i$ such that $i = \text{length}(l)$, the element at position $i$ in the concatenated list $l \mathbin{+\kern-1.5ex+} [a]$ is equal to $a$.
List.getElem?_concat_length theorem
{l : List α} {a : α} : (l ++ [a])[l.length]? = some a
Full source
theorem getElem?_concat_length {l : List α} {a : α} : (l ++ [a])[l.length]? = some a := by
  simp
Optional Indexing at Concatenated List's End Yields Appended Element
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the optional indexing operation $(l \mathbin{+\kern-1.5ex+} [a])[|l|]?$ returns $\text{some}\,a$, where $|l|$ denotes the length of $l$.
List.getD_eq_getElem?_getD theorem
{l : List α} {i : Nat} {a : α} : getD l i a = (l[i]?).getD a
Full source
@[simp] theorem getD_eq_getElem?_getD {l : List α} {i : Nat} {a : α} : getD l i a = (l[i]?).getD a := by
  simp [getD]
Equivalence of List Default Access and Optional Lookup with Default
Informal description
For any list $l$ of type $\alpha$, natural number index $i$, and default value $a$ of type $\alpha$, the default access operation $\text{getD}(l, i, a)$ is equal to applying the default value operation $\text{getD}$ to the optional lookup result $l[i]?$ and $a$.
List.getD_cons_zero theorem
: getD (x :: xs) 0 d = x
Full source
theorem getD_cons_zero : getD (x :: xs) 0 d = x := by simp
Default Access to Head of List: $\text{getD}(x :: xs, 0, d) = x$
Informal description
For any list of the form `x :: xs` (a head element `x` followed by tail list `xs`), and any default value `d`, the default access operation at index `0` returns the head element `x`. That is, $\text{getD}(x :: xs, 0, d) = x$.
List.getD_cons_succ theorem
: getD (x :: xs) (n + 1) d = getD xs n d
Full source
theorem getD_cons_succ : getD (x :: xs) (n + 1) d = getD xs n d := by simp
Default Access on Successor Index of Cons List Equals Default Access on Tail List
Informal description
For any element $x$, list $xs$, natural number $n$, and default value $d$, the default access operation on the list $x :: xs$ at index $n+1$ is equal to the default access operation on $xs$ at index $n$ with the same default value $d$. In other words, $\text{getD}(x :: xs, n+1, d) = \text{getD}(xs, n, d)$.
List.get!_eq_getD theorem
[Inhabited α] : ∀ (l : List α) i, l.get! i = l.getD i default
Full source
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
theorem get!_eq_getD [Inhabited α] : ∀ (l : List α) i, l.get! i = l.getD i default
  | [], _      => rfl
  | _a::_, 0   => by simp [get!]
  | _a::l, n+1 => by simpa using get!_eq_getD l n
Equivalence of Unsafe Indexing and Default Access for Inhabited Types
Informal description
For any inhabited type $\alpha$, list $l$ of type $\text{List}\,\alpha$, and natural number index $i$, the unsafe indexing operation $l.\text{get!}\,i$ is equal to the default access operation $\text{getD}(l, i, \text{default})$, where $\text{default}$ is the designated element of $\alpha$.
List.get!_eq_getElem! theorem
[Inhabited α] (l : List α) (i) : l.get! i = l[i]!
Full source
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12"), simp]
theorem get!_eq_getElem! [Inhabited α] (l : List α) (i) : l.get! i = l[i]! := by
  simp [get!_eq_getD]
Equivalence of Unsafe Indexing and Bang Access for Lists
Informal description
For any inhabited type $\alpha$, list $l$ of type $\text{List}\,\alpha$, and natural number index $i$, the unsafe indexing operation $l.\text{get!}\,i$ is equal to the bang element access operation $l[i]!$.
List.not_mem_nil theorem
{a : α} : ¬a ∈ []
Full source
@[simp] theorem not_mem_nil {a : α} : ¬ a ∈ [] := nofun
No element belongs to the empty list
Informal description
For any element $a$ of type $\alpha$, $a$ is not an element of the empty list, i.e., $\neg (a \in [])$.
List.mem_cons theorem
: a ∈ (b :: l) ↔ a = b ∨ a ∈ l
Full source
@[simp] theorem mem_cons : a ∈ (b :: l)a ∈ (b :: l) ↔ a = b ∨ a ∈ l :=
  ⟨fun h => by cases h <;> simp [Membership.mem, *],
   fun | Or.inl rfl => by constructor | Or.inr h => by constructor; assumption⟩
Membership in Cons List: $a \in (b :: l) \leftrightarrow a = b \lor a \in l$
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the element $a$ belongs to the list $b :: l$ if and only if either $a$ equals $b$ or $a$ belongs to $l$.
List.mem_cons_self theorem
{a : α} {l : List α} : a ∈ a :: l
Full source
theorem mem_cons_self {a : α} {l : List α} : a ∈ a :: l := .head ..
Element is member of its own cons list
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the element $a$ is contained in the list obtained by prepending $a$ to $l$, i.e., $a \in (a :: l)$.
List.mem_concat_self theorem
{xs : List α} {a : α} : a ∈ xs ++ [a]
Full source
theorem mem_concat_self {xs : List α} {a : α} : a ∈ xs ++ [a] :=
  mem_append_right xs mem_cons_self
Element is member of its own appended singleton list
Informal description
For any list $xs$ of elements of type $\alpha$ and any element $a$ of type $\alpha$, the element $a$ is contained in the list obtained by appending $[a]$ to $xs$, i.e., $a \in (xs ++ [a])$.
List.mem_append_cons_self theorem
: a ∈ xs ++ a :: ys
Full source
theorem mem_append_cons_self : a ∈ xs ++ a :: ys := mem_append_right _ mem_cons_self
Membership in Concatenated List with Cons
Informal description
For any element $a$ of type $\alpha$ and any lists $xs, ys$ of elements of type $\alpha$, the element $a$ is contained in the list obtained by appending $xs$ with the list constructed by prepending $a$ to $ys$, i.e., $a \in (xs ++ (a :: ys))$.
List.mem_cons_of_mem theorem
(y : α) {a : α} {l : List α} : a ∈ l → a ∈ y :: l
Full source
theorem mem_cons_of_mem (y : α) {a : α} {l : List α} : a ∈ la ∈ y :: l := .tail _
Membership Preservation under List Cons
Informal description
For any element $y$ of type $\alpha$, any element $a$ of type $\alpha$, and any list $l$ of type $\alpha$, if $a$ is an element of $l$, then $a$ is also an element of the list constructed by prepending $y$ to $l$, denoted as $y :: l$.
List.mem_dite_nil_left theorem
{x : α} [Decidable p] {l : ¬p → List α} : (x ∈ if h : p then [] else l h) ↔ ∃ h : ¬p, x ∈ l h
Full source
@[simp] theorem mem_dite_nil_left {x : α} [Decidable p] {l : ¬ pList α} :
    (x ∈ if h : p then [] else l h) ↔ ∃ h : ¬ p, x ∈ l h := by
  split <;> simp_all
Membership in Dependent If-Then-Else List with Empty True Branch: $x \in (\text{if } h : p \text{ then } [] \text{ else } l(h)) \leftrightarrow \exists h : \neg p, x \in l(h)$
Informal description
For any element $x$ of type $\alpha$ and decidable proposition $p$, the element $x$ is in the list obtained from the dependent if-then-else expression `if h : p then [] else l h` if and only if there exists a proof $h$ of $\neg p$ such that $x$ is in the list $l(h)$.
List.mem_dite_nil_right theorem
{x : α} [Decidable p] {l : p → List α} : (x ∈ if h : p then l h else []) ↔ ∃ h : p, x ∈ l h
Full source
@[simp] theorem mem_dite_nil_right {x : α} [Decidable p] {l : p → List α} :
    (x ∈ if h : p then l h else []) ↔ ∃ h : p, x ∈ l h := by
  split <;> simp_all
Membership in Conditional List Construction via Dependent If-Then-Else
Informal description
For any element $x$ of type $\alpha$ and a decidable proposition $p$, given a function $l$ that maps proofs of $p$ to lists of $\alpha$, the element $x$ is in the list obtained by evaluating `if h : p then l h else []` if and only if there exists a proof $h$ of $p$ such that $x$ is in the list $l(h)$.
List.mem_ite_nil_left theorem
{x : α} [Decidable p] {l : List α} : (x ∈ if p then [] else l) ↔ ¬p ∧ x ∈ l
Full source
@[simp] theorem mem_ite_nil_left {x : α} [Decidable p] {l : List α} :
    (x ∈ if p then [] else l) ↔ ¬ p ∧ x ∈ l := by
  split <;> simp_all
Membership in Conditional Empty List: $x \in (\text{if}\ p\ \text{then}\ []\ \text{else}\ l) \leftrightarrow \neg p \land x \in l$
Informal description
For any element $x$ of type $\alpha$, a decidable proposition $p$, and a list $l$ of type $\text{List}\ \alpha$, the element $x$ is in the list $\text{if}\ p\ \text{then}\ []\ \text{else}\ l$ if and only if $p$ is false and $x$ is in $l$.
List.mem_ite_nil_right theorem
{x : α} [Decidable p] {l : List α} : (x ∈ if p then l else []) ↔ p ∧ x ∈ l
Full source
@[simp] theorem mem_ite_nil_right {x : α} [Decidable p] {l : List α} :
    (x ∈ if p then l else []) ↔ p ∧ x ∈ l := by
  split <;> simp_all
Membership in Conditional List: $x \in (\text{if } p \text{ then } l \text{ else } []) \leftrightarrow p \land x \in l$
Informal description
For any element $x$ of type $\alpha$, a decidable proposition $p$, and a list $l$ of elements of type $\alpha$, the element $x$ belongs to the list `if p then l else []` if and only if $p$ holds and $x$ belongs to $l$. In symbols: \[ x \in (\text{if } p \text{ then } l \text{ else } []) \leftrightarrow p \land x \in l \]
List.mem_singleton theorem
{a b : α} : a ∈ [b] ↔ a = b
Full source
@[simp] theorem mem_singleton {a b : α} : a ∈ [b]a ∈ [b] ↔ a = b :=
  ⟨eq_of_mem_singleton, (by simp [·])⟩
Membership in Singleton List: $a \in [b] \leftrightarrow a = b$
Informal description
For any elements $a$ and $b$ of type $\alpha$, the element $a$ belongs to the singleton list $[b]$ if and only if $a$ equals $b$. In symbols: \[ a \in [b] \leftrightarrow a = b \]
List.forall_mem_cons theorem
{p : α → Prop} {a : α} {l : List α} : (∀ x, x ∈ a :: l → p x) ↔ p a ∧ ∀ x, x ∈ l → p x
Full source
theorem forall_mem_cons {p : α → Prop} {a : α} {l : List α} :
    (∀ x, x ∈ a :: l → p x) ↔ p a ∧ ∀ x, x ∈ l → p x :=
  ⟨fun H => ⟨H _ (.head ..), fun _ h => H _ (.tail _ h)⟩,
   fun ⟨H₁, H₂⟩ _ => fun | .head .. => H₁ | .tail _ h => H₂ _ h⟩
Universal Quantification over Cons List Decomposition
Informal description
For any predicate $p : \alpha \to \text{Prop}$, element $a : \alpha$, and list $l : \text{List}\ \alpha$, the following equivalence holds: \[ (\forall x, x \in a :: l \to p(x)) \leftrightarrow p(a) \land (\forall x, x \in l \to p(x)) \] Here, $a :: l$ denotes the list constructed by prepending $a$ to $l$, and $x \in l$ means $x$ is an element of list $l$.
List.forall_mem_ne theorem
{a : α} {l : List α} : (∀ a' : α, a' ∈ l → ¬a = a') ↔ a ∉ l
Full source
theorem forall_mem_ne {a : α} {l : List α} : (∀ a' : α, a' ∈ l → ¬a = a') ↔ a ∉ l :=
  ⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
Characterization of Non-Membership via Inequality
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the following are equivalent: 1. For every element $a'$ in $l$, $a$ is not equal to $a'$. 2. The element $a$ does not belong to the list $l$. In symbols: \[ (\forall a' \in l, a \neq a') \leftrightarrow a \notin l \]
List.forall_mem_ne' theorem
{a : α} {l : List α} : (∀ a' : α, a' ∈ l → ¬a' = a) ↔ a ∉ l
Full source
theorem forall_mem_ne' {a : α} {l : List α} : (∀ a' : α, a' ∈ l → ¬a' = a) ↔ a ∉ l :=
  ⟨fun h m => h _ m rfl, fun h _ m e => h (e.symm ▸ m)⟩
Characterization of Non-Membership via Inequality (Symmetric Version)
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the following are equivalent: 1. For every element $a'$ in $l$, $a'$ is not equal to $a$. 2. The element $a$ does not belong to the list $l$. In symbols: \[ (\forall a' \in l, a' \neq a) \leftrightarrow a \notin l \]
List.exists_mem_nil theorem
(p : α → Prop) : ¬(∃ x, ∃ _ : x ∈ @nil α, p x)
Full source
theorem exists_mem_nil (p : α → Prop) : ¬ (∃ x, ∃ _ : x ∈ @nil α, p x) := nofun
Nonexistence in Empty List
Informal description
For any predicate $p : \alpha \to \text{Prop}$, there does not exist an element $x$ in the empty list $\text{nil}$ such that $p(x)$ holds. In other words, $\neg (\exists x \in \text{nil}, p(x))$.
List.forall_mem_nil theorem
(p : α → Prop) : ∀ (x) (_ : x ∈ @nil α), p x
Full source
theorem forall_mem_nil (p : α → Prop) : ∀ (x) (_ : x ∈ @nil α), p x := nofun
Universal Quantification over Empty List Holds Vacuously
Informal description
For any predicate $p : \alpha \to \text{Prop}$ and for any element $x$ in the empty list $\text{nil}$, the proposition $p(x)$ holds. In other words, $\forall x \in \text{nil}, p(x)$.
List.exists_mem_cons theorem
{p : α → Prop} {a : α} {l : List α} : (∃ x, ∃ _ : x ∈ a :: l, p x) ↔ p a ∨ ∃ x, ∃ _ : x ∈ l, p x
Full source
theorem exists_mem_cons {p : α → Prop} {a : α} {l : List α} :
    (∃ x, ∃ _ : x ∈ a :: l, p x) ↔ p a ∨ ∃ x, ∃ _ : x ∈ l, p x := by simp
Existence in Cons List Decomposes as Disjunction
Informal description
For any predicate $p : \alpha \to \text{Prop}$, element $a \in \alpha$, and list $l \in \text{List } \alpha$, the following equivalence holds: \[ (\exists x \in a :: l, p(x)) \leftrightarrow p(a) \lor (\exists x \in l, p(x)) \] where $a :: l$ denotes the list constructed by prepending $a$ to $l$.
List.forall_mem_singleton theorem
{p : α → Prop} {a : α} : (∀ (x) (_ : x ∈ [a]), p x) ↔ p a
Full source
theorem forall_mem_singleton {p : α → Prop} {a : α} : (∀ (x) (_ : x ∈ [a]), p x) ↔ p a := by
  simp only [mem_singleton, forall_eq]
Universal Quantification over Singleton List is Equivalent to Predicate at the Element
Informal description
For any predicate $p : \alpha \to \text{Prop}$ and any element $a \in \alpha$, the statement that $p(x)$ holds for all $x$ in the singleton list $[a]$ is equivalent to $p(a)$ holding. In other words, $\forall x \in [a], p(x) \leftrightarrow p(a)$.
List.mem_nil_iff theorem
(a : α) : a ∈ ([] : List α) ↔ False
Full source
theorem mem_nil_iff (a : α) : a ∈ ([] : List α)a ∈ ([] : List α) ↔ False := by simp
Membership in Empty List is False
Informal description
For any element $a$ of type $\alpha$, the statement that $a$ is a member of the empty list is equivalent to false, i.e., $a \in [] \leftrightarrow \text{False}$.
List.mem_singleton_self theorem
(a : α) : a ∈ [a]
Full source
theorem mem_singleton_self (a : α) : a ∈ [a] := mem_cons_self
Element is Member of Its Own Singleton List
Informal description
For any element $a$ of type $\alpha$, the element $a$ is contained in the singleton list $[a]$, i.e., $a \in [a]$.
List.mem_of_mem_cons_of_mem theorem
: ∀ {a b : α} {l : List α}, a ∈ b :: l → b ∈ l → a ∈ l
Full source
theorem mem_of_mem_cons_of_mem : ∀ {a b : α} {l : List α}, a ∈ b :: lb ∈ la ∈ l
  | _, _, _, .head .., h | _, _, _, .tail _ h, _ => h
Membership Propagation in Cons List
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any list $l$ of type $\alpha$, if $a$ is an element of the list $b :: l$ and $b$ is an element of $l$, then $a$ is also an element of $l$.
List.ne_nil_of_mem theorem
{a : α} {l : List α} (h : a ∈ l) : l ≠ []
Full source
theorem ne_nil_of_mem {a : α} {l : List α} (h : a ∈ l) : l ≠ [] := by cases h <;> nofun
Non-empty List from Membership
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List } \alpha$, if $a$ is a member of $l$, then $l$ is not the empty list.
List.mem_of_ne_of_mem theorem
{a y : α} {l : List α} (h₁ : a ≠ y) (h₂ : a ∈ y :: l) : a ∈ l
Full source
theorem mem_of_ne_of_mem {a y : α} {l : List α} (h₁ : a ≠ y) (h₂ : a ∈ y :: l) : a ∈ l :=
  Or.elim (mem_cons.mp h₂) (absurd · h₁) (·)
Membership in Tail from Inequality and Membership in Cons List
Informal description
For any elements $a$ and $y$ of type $\alpha$ and any list $l$ of type $\text{List } \alpha$, if $a \neq y$ and $a$ is an element of the list $y :: l$, then $a$ must be an element of $l$.
List.ne_of_not_mem_cons theorem
{a b : α} {l : List α} : a ∉ b :: l → a ≠ b
Full source
theorem ne_of_not_mem_cons {a b : α} {l : List α} : a ∉ b :: la ≠ b := mt (· ▸ .head _)
Inequality from Non-Membership in Cons List
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any list $l$ of type $\alpha$, if $a$ is not an element of the list $b :: l$, then $a$ is not equal to $b$.
List.not_mem_of_not_mem_cons theorem
{a b : α} {l : List α} : a ∉ b :: l → a ∉ l
Full source
theorem not_mem_of_not_mem_cons {a b : α} {l : List α} : a ∉ b :: la ∉ l := mt (.tail _)
Non-membership in tail from non-membership in cons
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any list $l$ of type $\alpha$, if $a$ is not an element of the list $b :: l$, then $a$ is not an element of the list $l$.
List.not_mem_cons_of_ne_of_not_mem theorem
{a y : α} {l : List α} : a ≠ y → a ∉ l → a ∉ y :: l
Full source
theorem not_mem_cons_of_ne_of_not_mem {a y : α} {l : List α} : a ≠ ya ∉ la ∉ y :: l :=
  mtmt ∘ mem_of_ne_of_mem
Non-membership in Cons List from Inequality and Non-membership in Tail
Informal description
For any elements $a$ and $y$ of type $\alpha$ and any list $l$ of type $\text{List } \alpha$, if $a$ is not equal to $y$ and $a$ is not an element of $l$, then $a$ is not an element of the list $y :: l$.
List.ne_and_not_mem_of_not_mem_cons theorem
{a y : α} {l : List α} : a ∉ y :: l → a ≠ y ∧ a ∉ l
Full source
theorem ne_and_not_mem_of_not_mem_cons {a y : α} {l : List α} : a ∉ y :: la ≠ ya ≠ y ∧ a ∉ l :=
  fun p => ⟨ne_of_not_mem_cons p, not_mem_of_not_mem_cons p⟩
Non-membership in Cons List Implies Inequality and Non-membership in Tail
Informal description
For any elements $a$ and $y$ of type $\alpha$ and any list $l$ of type $\alpha$, if $a$ is not an element of the list $y :: l$, then $a$ is not equal to $y$ and $a$ is not an element of $l$.
List.getElem_of_mem theorem
: ∀ {a} {l : List α}, a ∈ l → ∃ (i : Nat) (h : i < l.length), l[i]'h = a
Full source
theorem getElem_of_mem : ∀ {a} {l : List α}, a ∈ l∃ (i : Nat) (h : i < l.length), l[i]'h = a
  | _, _ :: _, .head .. => ⟨0, Nat.succ_pos _, rfl⟩
  | _, _ :: _, .tail _ m => let ⟨i, h, e⟩ := getElem_of_mem m; ⟨i+1, Nat.succ_lt_succ h, e⟩
Existence of Index for List Membership: $a \in l \implies \exists i < \text{length}(l), l[i] = a$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List } \alpha$, if $a$ is a member of $l$ (i.e., $a \in l$), then there exists a natural number index $i$ with $i < \text{length}(l)$ such that the $i$-th element of $l$ equals $a$ (i.e., $l[i] = a$).
List.getElem?_of_mem theorem
{a} {l : List α} (h : a ∈ l) : ∃ i : Nat, l[i]? = some a
Full source
theorem getElem?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ i : Nat, l[i]? = some a := by
  let ⟨n, _, e⟩ := getElem_of_mem h
  exact ⟨n, e ▸ getElem?_eq_getElem _⟩
Existence of Valid Index for List Membership via Optional Indexing
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, if $a$ is a member of $l$ (i.e., $a \in l$), then there exists a natural number index $i$ such that the optional indexing operation $l[i]?$ returns $\text{some}\,a$.
List.mem_of_getElem theorem
{l : List α} {i : Nat} {h} {a : α} (e : l[i] = a) : a ∈ l
Full source
theorem mem_of_getElem {l : List α} {i : Nat} {h} {a : α} (e : l[i] = a) : a ∈ l := by
  subst e
  simp
Membership from Indexed Access: $l[i] = a \implies a \in l$
Informal description
For any list $l$ of type $\alpha$, natural number index $i$ with $i < \text{length}(l)$, and element $a \in \alpha$, if the $i$-th element of $l$ is equal to $a$ (i.e., $l[i] = a$), then $a$ is a member of $l$ (i.e., $a \in l$).
List.mem_of_getElem? theorem
{l : List α} {i : Nat} {a : α} (e : l[i]? = some a) : a ∈ l
Full source
theorem mem_of_getElem? {l : List α} {i : Nat} {a : α} (e : l[i]? = some a) : a ∈ l :=
  let ⟨_, e⟩ := getElem?_eq_some_iff.1 e; e ▸ getElem_mem ..
Membership from Optional Indexing: $l[i]? = \text{some}\,a \implies a \in l$
Informal description
For any list $l$ of type $\text{List}\,\alpha$, natural number index $i$, and element $a \in \alpha$, if the optional indexing operation $l[i]?$ returns $\text{some}\,a$, then $a$ is a member of $l$. In symbols: $$l[i]? = \text{some}\,a \implies a \in l$$
List.mem_iff_getElem theorem
{a} {l : List α} : a ∈ l ↔ ∃ (i : Nat) (h : i < l.length), l[i]'h = a
Full source
theorem mem_iff_getElem {a} {l : List α} : a ∈ la ∈ l ↔ ∃ (i : Nat) (h : i < l.length), l[i]'h = a :=
  ⟨getElem_of_mem, fun ⟨_, _, e⟩ => e ▸ getElem_mem ..⟩
List Membership Characterization via Indexing: $a \in l \leftrightarrow \exists i < \text{length}(l), l[i] = a$
Informal description
For any element $a$ and list $l$ of type $\alpha$, $a$ is a member of $l$ if and only if there exists a natural number index $i$ with $i < \text{length}(l)$ such that the $i$-th element of $l$ equals $a$ (i.e., $l[i] = a$).
List.mem_iff_getElem? theorem
{a} {l : List α} : a ∈ l ↔ ∃ i : Nat, l[i]? = some a
Full source
theorem mem_iff_getElem? {a} {l : List α} : a ∈ la ∈ l ↔ ∃ i : Nat, l[i]? = some a := by
  simp [getElem?_eq_some_iff, mem_iff_getElem]
List Membership via Optional Indexing: $a \in l \leftrightarrow \exists i, l[i]? = \text{some }a$
Informal description
For any element $a$ and list $l$ of type $\alpha$, $a$ is a member of $l$ if and only if there exists a natural number index $i$ such that the optional lookup operation $l[i]?$ returns $\text{some }a$.
List.forall_getElem theorem
{l : List α} {p : α → Prop} : (∀ (i : Nat) h, p (l[i]'h)) ↔ ∀ a, a ∈ l → p a
Full source
theorem forall_getElem {l : List α} {p : α → Prop} :
    (∀ (i : Nat) h, p (l[i]'h)) ↔ ∀ a, a ∈ l → p a := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [length_cons, mem_cons, forall_eq_or_imp]
    constructor
    · intro w
      constructor
      · exact w 0 (by simp)
      · apply ih.1
        intro n h
        simpa using w (n+1) (Nat.add_lt_add_right h 1)
    · rintro ⟨h, w⟩
      rintro (_ | n) h
      · simpa
      · apply w
        simp only [getElem_cons_succ]
        exact getElem_mem (lt_of_succ_lt_succ h)
Universal Quantification over List Elements via Indexing vs Membership
Informal description
For any list $l$ of type $\alpha$ and predicate $p$ on $\alpha$, the following are equivalent: 1. For every natural number index $i$ with $i < \text{length}(l)$, the predicate $p$ holds for the $i$-th element $l[i]$. 2. For every element $a$ in the list $l$, the predicate $p$ holds for $a$.
List.elem_eq_contains theorem
[BEq α] {a : α} {l : List α} : elem a l = l.contains a
Full source
@[simp] theorem elem_eq_contains [BEq α] {a : α} {l : List α} :
    elem a l = l.contains a := by
  simp [contains]
Equivalence of List Membership and Containment Functions
Informal description
For any type $\alpha$ with a boolean equality relation `BEq`, and for any element $a \in \alpha$ and list $l$ of elements of type $\alpha$, the boolean-valued membership function `elem a l` is equal to the list containment function `contains a l$.
List.decide_mem_cons theorem
[BEq α] [LawfulBEq α] {l : List α} : decide (y ∈ a :: l) = (y == a || decide (y ∈ l))
Full source
@[simp] theorem decide_mem_cons [BEq α] [LawfulBEq α] {l : List α} :
    decide (y ∈ a :: l) = (y == a || decide (y ∈ l)) := by
  cases h : y == a <;> simp_all
Membership Decision in Cons List: $\text{decide}(y \in a :: l) = (y == a) \lor \text{decide}(y \in l)$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, any element $y \in \alpha$, any element $a \in \alpha$, and any list $l$ of elements of type $\alpha$, the boolean decision of whether $y$ is in the list $a :: l$ is equal to the boolean disjunction of $y == a$ and the decision of whether $y$ is in $l$.
List.elem_iff theorem
[BEq α] [LawfulBEq α] {a : α} {as : List α} : elem a as = true ↔ a ∈ as
Full source
theorem elem_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
    elemelem a as = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩
Boolean Membership Test Characterizes List Membership
Informal description
For any type $\alpha$ with a lawful boolean equality relation, an element $a \in \alpha$, and a list $as$ of elements of type $\alpha$, the boolean membership test `elem a as` returns `true` if and only if $a$ is an element of $as$.
List.contains_iff theorem
[BEq α] [LawfulBEq α] {a : α} {as : List α} : as.contains a = true ↔ a ∈ as
Full source
theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : List α} :
    as.contains a = true ↔ a ∈ as := ⟨mem_of_elem_eq_true, elem_eq_true_of_mem⟩
Boolean Membership Test Characterizes List Membership
Informal description
For any type $\alpha$ with a lawful boolean equality relation, an element $a \in \alpha$, and a list $as$ of elements of type $\alpha$, the boolean membership test `as.contains a` returns `true` if and only if $a$ is an element of $as$.
List.elem_eq_mem theorem
[BEq α] [LawfulBEq α] (a : α) (as : List α) : elem a as = decide (a ∈ as)
Full source
theorem elem_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
    elem a as = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
Equivalence of Boolean Membership Test and Propositional Membership for Lists
Informal description
For any type $\alpha$ with a lawful boolean equality relation, an element $a \in \alpha$, and a list $as$ of elements of type $\alpha$, the boolean membership test `elem a as` is equal to the result of deciding whether $a$ is an element of $as$.
List.contains_eq_mem theorem
[BEq α] [LawfulBEq α] (a : α) (as : List α) : as.contains a = decide (a ∈ as)
Full source
@[simp] theorem contains_eq_mem [BEq α] [LawfulBEq α] (a : α) (as : List α) :
    as.contains a = decide (a ∈ as) := by rw [Bool.eq_iff_iff, elem_iff, decide_eq_true_iff]
Equivalence of List Membership Test and Decision Procedure: $\text{contains}(a, as) = \text{decide}(a \in as)$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, an element $a \in \alpha$, and a list $as$ of elements of type $\alpha$, the boolean membership test `as.contains a` is equal to the result of the decision procedure `decide (a ∈ as)`.
List.contains_cons theorem
[BEq α] {a : α} {b : α} {l : List α} : (a :: l).contains b = (b == a || l.contains b)
Full source
@[simp] theorem contains_cons [BEq α] {a : α} {b : α} {l : List α} :
    (a :: l).contains b = (b == a || l.contains b) := by
  simp only [contains, elem_cons]
  split <;> simp_all
Containment in Cons List: $(a :: l).\text{contains}(b) = (b == a) \lor l.\text{contains}(b)$
Informal description
For any type $\alpha$ with a boolean equality relation, and for any elements $a, b \in \alpha$ and list $l$ of elements of type $\alpha$, the containment check $(a :: l).\text{contains}(b)$ is equal to $(b == a) \lor l.\text{contains}(b)$.
List.isEmpty_iff theorem
{l : List α} : l.isEmpty ↔ l = []
Full source
@[simp] theorem isEmpty_iff {l : List α} : l.isEmpty ↔ l = [] := by
  cases l <;> simp
Empty List Characterization: $\text{isEmpty}(l) \leftrightarrow l = []$
Informal description
For any list $l$ of elements of type $\alpha$, the predicate $\text{isEmpty}(l)$ holds if and only if $l$ is the empty list, i.e., $l = []$.
List.isEmpty_eq_true abbrev
Full source
@[deprecated isEmpty_iff (since := "2025-02-17")]
abbrev isEmpty_eq_true := @isEmpty_iff
Empty List Characterization via `isEmpty`
Informal description
For any list $l$ of elements of type $\alpha$, the boolean value `l.isEmpty` is `true` if and only if $l$ is the empty list, i.e., $l = []$.
List.isEmpty_eq_false_iff theorem
{l : List α} : l.isEmpty = false ↔ l ≠ []
Full source
@[simp] theorem isEmpty_eq_false_iff {l : List α} : l.isEmpty = false ↔ l ≠ [] := by
  cases l <;> simp
Non-emptiness of a List via `isEmpty`
Informal description
For any list $l$ of type $\alpha$, the boolean value `l.isEmpty` is `false` if and only if $l$ is not the empty list, i.e., $l \neq []$.
List.isEmpty_eq_false abbrev
Full source
@[deprecated isEmpty_eq_false_iff (since := "2025-02-17")]
abbrev isEmpty_eq_false := @isEmpty_eq_false_iff
Non-emptiness of a List via `isEmpty`
Informal description
For any list $l$ of type $\alpha$, the boolean value `l.isEmpty` is `false` if and only if $l$ is not the empty list, i.e., $l \neq []$.
List.isEmpty_eq_false_iff_exists_mem theorem
{xs : List α} : xs.isEmpty = false ↔ ∃ x, x ∈ xs
Full source
theorem isEmpty_eq_false_iff_exists_mem {xs : List α} :
    xs.isEmpty = false ↔ ∃ x, x ∈ xs := by
  cases xs <;> simp
Non-empty List Characterization: $\text{isEmpty}(xs) = \text{false} \leftrightarrow \exists x \in xs$
Informal description
For any list `xs` of elements of type `α`, the statement `xs.isEmpty = false` holds if and only if there exists an element `x` in `xs` (i.e., `x ∈ xs`).
List.isEmpty_iff_length_eq_zero theorem
{l : List α} : l.isEmpty ↔ l.length = 0
Full source
theorem isEmpty_iff_length_eq_zero {l : List α} : l.isEmpty ↔ l.length = 0 := by
  rw [isEmpty_iff, length_eq_zero_iff]
Empty List Characterization via Length Zero: $\text{isEmpty}(l) \leftrightarrow \text{length}(l) = 0$
Informal description
For any list $l$ of elements of type $\alpha$, the predicate $\text{isEmpty}(l)$ holds if and only if the length of $l$ is zero, i.e., $\text{length}(l) = 0$.
List.any_eq theorem
{l : List α} : l.any p = decide (∃ x, x ∈ l ∧ p x)
Full source
theorem any_eq {l : List α} : l.any p = decide (∃ x, x ∈ l ∧ p x) := by induction l <;> simp [*]
Equivalence of List Any and Existential Quantifier: $\text{any}(l, p) = \text{decide}(\exists x \in l, p(x))$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the boolean evaluation of `l.any p` is equal to the decision procedure for the proposition that there exists an element $x$ in $l$ such that $p(x)$ holds. That is, $\text{any}(l, p) = \text{decide}(\exists x \in l, p(x))$.
List.all_eq theorem
{l : List α} : l.all p = decide (∀ x, x ∈ l → p x)
Full source
theorem all_eq {l : List α} : l.all p = decide (∀ x, x ∈ l → p x) := by induction l <;> simp [*]
Equivalence of List.all and Universal Quantification over List Elements
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the boolean evaluation of `l.all p` is equal to the boolean evaluation of the proposition that for all elements $x$ in $l$, $p(x)$ holds. That is, $\text{all}(l, p) = \text{decide}(\forall x \in l, p(x))$.
List.decide_exists_mem theorem
{l : List α} {p : α → Prop} [DecidablePred p] : decide (∃ x, x ∈ l ∧ p x) = l.any p
Full source
theorem decide_exists_mem {l : List α} {p : α → Prop} [DecidablePred p] :
    decide (∃ x, x ∈ l ∧ p x) = l.any p := by
  simp [any_eq]
Decision Procedure for Existential Quantifier over List Elements Equals List Any
Informal description
For any list $l$ of elements of type $\alpha$ and any decidable predicate $p$ on $\alpha$, the decision procedure for the existence of an element $x$ in $l$ satisfying $p(x)$ is equal to the boolean evaluation of `l.any p`. That is, $\text{decide}(\exists x \in l, p(x)) = \text{any}(l, p)$.
List.decide_forall_mem theorem
{l : List α} {p : α → Prop} [DecidablePred p] : decide (∀ x, x ∈ l → p x) = l.all p
Full source
theorem decide_forall_mem {l : List α} {p : α → Prop} [DecidablePred p] :
    decide (∀ x, x ∈ l → p x) = l.all p := by
  simp [all_eq]
Equivalence of Universal Quantification and List.all for Decidable Predicates
Informal description
For any list $l$ of elements of type $\alpha$ and any decidable predicate $p$ on $\alpha$, the boolean decision of the proposition "for all $x$ in $l$, $p(x)$ holds" is equal to the result of applying the `all` operation to $l$ with predicate $p$. That is, $\text{decide}(\forall x \in l, p(x)) = \text{all}(l, p)$.
List.any_eq_true theorem
{l : List α} : l.any p = true ↔ ∃ x, x ∈ l ∧ p x
Full source
@[simp] theorem any_eq_true {l : List α} : l.any p = true ↔ ∃ x, x ∈ l ∧ p x := by
  simp only [any_eq, decide_eq_true_eq]
Existence in List Characterized by `any` Function
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the boolean function `any` applied to $l$ and $p$ returns `true` if and only if there exists an element $x$ in $l$ such that $p(x)$ holds. In other words, $\text{any}(l, p) = \texttt{true} \leftrightarrow \exists x \in l, p(x)$.
List.all_eq_true theorem
{l : List α} : l.all p = true ↔ ∀ x, x ∈ l → p x
Full source
@[simp] theorem all_eq_true {l : List α} : l.all p = true ↔ ∀ x, x ∈ l → p x := by
  simp only [all_eq, decide_eq_true_eq]
List All Elements Satisfy Predicate iff `all` is True
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the boolean evaluation `l.all p` is equal to `true` if and only if for every element $x$ in $l$, the predicate $p(x)$ holds. In other words: $$\text{all}(l, p) = \texttt{true} \leftrightarrow \forall x \in l, p(x)$$
List.any_eq_false theorem
{l : List α} : l.any p = false ↔ ∀ x, x ∈ l → ¬p x
Full source
@[simp] theorem any_eq_false {l : List α} : l.any p = false ↔ ∀ x, x ∈ l → ¬p x := by
  simp [any_eq]
Characterization of `any` returning false: $\text{any}(l, p) = \text{false} \leftrightarrow \forall x \in l, \neg p(x)$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the boolean expression `l.any p` evaluates to `false` if and only if for every element $x$ in $l$, the predicate $p(x)$ does not hold. In other words, $\text{any}(l, p) = \text{false} \leftrightarrow \forall x \in l, \neg p(x)$.
List.all_eq_false theorem
{l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x
Full source
@[simp] theorem all_eq_false {l : List α} : l.all p = false ↔ ∃ x, x ∈ l ∧ ¬p x := by
  simp [all_eq]
List All Predicate False iff Exists Counterexample
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p$ on $\alpha$, the boolean expression `l.all p` evaluates to `false` if and only if there exists an element $x \in l$ such that $\neg p(x)$ holds. In other words, $\text{all}(l, p) = \text{false} \leftrightarrow \exists x \in l, \neg p(x)$.
List.any_beq theorem
[BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a
Full source
theorem any_beq [BEq α] {l : List α} {a : α} : (l.any fun x => a == x) = l.contains a := by
  induction l <;> simp_all [contains_cons]
Equivalence of `any` and `contains` for List Membership
Informal description
For any type $\alpha$ with a boolean equality relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the boolean expression `l.any (fun x => a == x)` is equal to `l.contains a`. In other words, checking if any element in $l$ is equal to $a$ via `any` is equivalent to checking if $l$ contains $a$ via `contains`.
List.any_beq' theorem
[BEq α] [PartialEquivBEq α] {l : List α} : (l.any fun x => x == a) = l.contains a
Full source
/-- Variant of `any_beq` with `==` reversed. -/
theorem any_beq' [BEq α] [PartialEquivBEq α] {l : List α} :
    (l.any fun x => x == a) = l.contains a := by
  simp only [BEq.comm, any_beq]
Equivalence of Reversed Boolean Equality in `List.any` and `List.contains`
Informal description
For any type $\alpha$ with a boolean equality relation `==` that forms a partial equivalence relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the boolean expression `l.any (fun x => x == a)` is equal to `l.contains a`. In other words, checking if any element in $l$ is equal to $a$ via `any` (with the equality reversed) is equivalent to checking if $l$ contains $a$ via `contains`.
List.all_bne theorem
[BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a
Full source
theorem all_bne [BEq α] {l : List α} : (l.all fun x => a != x) = !l.contains a := by
  induction l <;> simp_all [bne]
Negation of List Containment via Universal Inequality: $\forall x \in l, a \neq x \leftrightarrow \neg (l \text{ contains } a)$
Informal description
For any type $\alpha$ with a boolean equality relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the boolean expression `l.all (fun x => a != x)` is equal to the negation of `l.contains a`. In other words, checking that all elements in $l$ are not equal to $a$ via `all` is equivalent to checking that $l$ does not contain $a$ via `contains`.
List.all_bne' theorem
[BEq α] [PartialEquivBEq α] {l : List α} : (l.all fun x => x != a) = !l.contains a
Full source
/-- Variant of `all_bne` with `!=` reversed. -/
theorem all_bne' [BEq α] [PartialEquivBEq α] {l : List α} :
    (l.all fun x => x != a) = !l.contains a := by
  simp only [bne_comm, all_bne]
Universal Inequality in List Equivalent to Non-Containment: $\forall x \in l, x \neq a \leftrightarrow \neg (l \text{ contains } a)$
Informal description
For any type $\alpha$ with a boolean equality relation `==` that forms a partial equivalence relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the boolean expression `l.all (fun x => x != a)` is equal to the negation of `l.contains a`. In other words, checking that all elements in $l$ are not equal to $a$ via `all` is equivalent to checking that $l$ does not contain $a$ via `contains`.
List.set_nil theorem
{i : Nat} {a : α} : [].set i a = []
Full source
@[simp] theorem set_nil {i : Nat} {a : α} : [].set i a = [] := rfl
Empty List Element Replacement Yields Empty List
Informal description
For any natural number index $i$ and any element $a$ of type $\alpha$, replacing the element at position $i$ in the empty list results in the empty list, i.e., $[\,].\text{set}(i, a) = [\,]$.
List.set_cons_zero theorem
{x : α} {xs : List α} {a : α} : (x :: xs).set 0 a = a :: xs
Full source
@[simp] theorem set_cons_zero {x : α} {xs : List α} {a : α} :
  (x :: xs).set 0 a = a :: xs := rfl
Replacement at Head of List: $(x :: xs).\text{set}\ 0\ a = a :: xs$
Informal description
For any element $x$ of type $\alpha$, any list $xs$ of elements of type $\alpha$, and any element $a$ of type $\alpha$, replacing the element at index $0$ in the list $x :: xs$ with $a$ results in the list $a :: xs$.
List.set_cons_succ theorem
{x : α} {xs : List α} {i : Nat} {a : α} : (x :: xs).set (i + 1) a = x :: xs.set i a
Full source
@[simp] theorem set_cons_succ {x : α} {xs : List α} {i : Nat} {a : α} :
  (x :: xs).set (i + 1) a = x :: xs.set i a := rfl
List Replacement at Successor Index: $(x :: xs).\text{set}(i+1, a) = x :: (xs.\text{set}(i, a))$
Informal description
For any element $x$ of type $\alpha$, any list $xs$ of elements of type $\alpha$, any natural number index $i$, and any element $a$ of type $\alpha$, replacing the element at index $i+1$ in the list $x :: xs$ with $a$ is equivalent to prepending $x$ to the list obtained by replacing the element at index $i$ in $xs$ with $a$. That is, $(x :: xs).\text{set}(i+1, a) = x :: (xs.\text{set}(i, a))$.
List.getElem_set_self theorem
{l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) : (l.set i a)[i] = a
Full source
@[simp] theorem getElem_set_self {l : List α} {i : Nat} {a : α} (h : i < (l.set i a).length) :
    (l.set i a)[i] = a :=
  match l, i with
  | [], _ => by
    simp at h
  | _ :: _, 0 => by simp
  | _ :: l, i + 1 => by simp [getElem_set_self]
List Element Replacement at Valid Index: $(l.\text{set}(i, a))[i] = a$
Informal description
For any list $l$ of elements of type $\alpha$, natural number index $i$, and element $a$ of type $\alpha$, if $i$ is a valid index for the list obtained by replacing the $i$-th element of $l$ with $a$ (i.e., $i < \text{length}(l.\text{set}(i, a))$), then the $i$-th element of the modified list equals $a$, i.e., $(l.\text{set}(i, a))[i] = a$.
List.getElem?_set_self theorem
{l : List α} {i : Nat} {a : α} (h : i < l.length) : (l.set i a)[i]? = some a
Full source
@[simp] theorem getElem?_set_self {l : List α} {i : Nat} {a : α} (h : i < l.length) :
    (l.set i a)[i]? = some a := by
  simp_all [getElem?_eq_some_iff]
Optional Indexing After List Replacement: $(l.\text{set}(i, a))[i]? = \text{some}(a)$ for Valid Indices
Informal description
For any list $l$ of elements of type $\alpha$, natural number index $i$, and element $a$ of type $\alpha$, if $i$ is a valid index for $l$ (i.e., $i < \text{length}(l)$), then the optional indexing operation on the modified list $(l.\text{set}(i, a))[i]?$ returns $\text{some}(a)$.
List.getElem?_set_self' theorem
{l : List α} {i : Nat} {a : α} : (set l i a)[i]? = Function.const _ a <$> l[i]?
Full source
/-- This differs from `getElem?_set_self` by monadically mapping `Function.const _ a` over the `Option`
returned by `l[i]?`. -/
theorem getElem?_set_self' {l : List α} {i : Nat} {a : α} :
    (set l i a)[i]? = Function.constFunction.const _ a <$> l[i]? := by
  by_cases h : i < l.length
  · simp [getElem?_set_self h, getElem?_eq_getElem h]
  · simp only [Nat.not_lt] at h
    simpa [getElem?_eq_none_iff.2 h]
Optional Indexing After List Replacement via Constant Function Mapping
Informal description
For any list $l$ of elements of type $\alpha$, natural number index $i$, and element $a$ of type $\alpha$, the optional indexing operation on the modified list $(l.\text{set}(i, a))[i]?$ is equal to applying the constant function $\text{const}_\alpha(a)$ to the result of the optional indexing operation $l[i]?$ (i.e., mapping $\text{const}_\alpha(a)$ over $l[i]?$).
List.getElem_set_ne theorem
{l : List α} {i j : Nat} (h : i ≠ j) {a : α} (hj : j < (l.set i a).length) : (l.set i a)[j] = l[j]'(by simp at hj; exact hj)
Full source
@[simp] theorem getElem_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}
    (hj : j < (l.set i a).length) :
    (l.set i a)[j] = l[j]'(by simp at hj; exact hj) :=
  match l, i, j with
  | [], _, _ => by simp
  | _ :: _, 0, 0 => by contradiction
  | _ :: _, 0, _ + 1 => by simp
  | _ :: _, _ + 1, 0 => by simp
  | _ :: l, i + 1, j + 1 => by
    have g : i ≠ j := h ∘ congrArg (· + 1)
    simp [getElem_set_ne g]
Preservation of List Elements Under Index-Mismatched Replacement
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$ with $i \neq j$, and element $a$ of type $\alpha$, if $j$ is a valid index for the list obtained by setting the $i$-th element of $l$ to $a$, then the $j$-th element of the modified list equals the $j$-th element of the original list. That is, $(l.\text{set}\ i\ a)[j] = l[j]$.
List.getElem?_set_ne theorem
{l : List α} {i j : Nat} (h : i ≠ j) {a : α} : (l.set i a)[j]? = l[j]?
Full source
@[simp] theorem getElem?_set_ne {l : List α} {i j : Nat} (h : i ≠ j) {a : α}  :
    (l.set i a)[j]? = l[j]? := by
  by_cases hj : j < (l.set i a).length
  · rw [getElem?_eq_getElem hj, getElem?_eq_getElem (by simp_all)]
    simp_all
  · rw [getElem?_eq_none (by simp_all), getElem?_eq_none (by simp_all)]
Preservation of Optional List Indexing Under Index-Mismatched Replacement: $(l.\text{set}(i, a))[j]? = l[j]?$ for $i \neq j$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$ with $i \neq j$, and element $a$ of type $\alpha$, the optional indexing operation $(l.\text{set}(i, a))[j]?$ equals $l[j]?$. That is, replacing an element at index $i$ does not affect the optional lookup at a different index $j$.
List.getElem_set theorem
{l : List α} {i j} {a} (h) : (set l i a)[j]'h = if i = j then a else l[j]'(length_set .. ▸ h)
Full source
theorem getElem_set {l : List α} {i j} {a} (h) :
    (set l i a)[j]'h = if i = j then a else l[j]'(length_set .. ▸ h) := by
  if h : i = j then
    subst h; simp only [getElem_set_self, ↓reduceIte]
  else
    simp [h]
Element Access After List Replacement: $(l.\text{set}(i, a))[j] = \text{if } i = j \text{ then } a \text{ else } l[j]$
Informal description
For any list $l$ of elements of type $\alpha$, indices $i$ and $j$, and element $a \in \alpha$, if $h$ is a proof that $j$ is a valid index for the modified list $\text{set}(l, i, a)$, then the $j$-th element of $\text{set}(l, i, a)$ equals $a$ if $i = j$, and otherwise equals the $j$-th element of the original list $l$.
List.getElem?_set theorem
{l : List α} {i j : Nat} {a : α} : (l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]?
Full source
theorem getElem?_set {l : List α} {i j : Nat} {a : α} :
    (l.set i a)[j]? = if i = j then if i < l.length then some a else none else l[j]? := by
  if h : i = j then
    subst h
    rw [if_pos rfl]
    split <;> rename_i h
    · simp only [getElem?_set_self (by simpa), h]
    · simp_all
  else
    simp [h]
Optional Indexing After List Replacement: $(l.\text{set}(i, a))[j]? = \text{if } i = j \text{ then } (\text{if } i < \text{length}(l) \text{ then } \text{some}(a) \text{ else } \text{none}) \text{ else } l[j]?$
Informal description
For any list $l$ of elements of type $\alpha$, indices $i$ and $j$, and element $a \in \alpha$, the optional indexing operation on the modified list $(l.\text{set}(i, a))[j]?$ satisfies: $$(l.\text{set}(i, a))[j]? = \begin{cases} \text{some}(a) & \text{if } i = j \text{ and } i < \text{length}(l), \\ \text{none} & \text{if } i = j \text{ and } i \geq \text{length}(l), \\ l[j]? & \text{otherwise.} \end{cases}$$
List.getElem?_set' theorem
{l : List α} {i j : Nat} {a : α} : (set l i a)[j]? = if i = j then Function.const _ a <$> l[j]? else l[j]?
Full source
/-- This differs from `getElem?_set` by monadically mapping `Function.const _ a`
over the `Option` returned by `l[j]`? -/
theorem getElem?_set' {l : List α} {i j : Nat} {a : α} :
    (set l i a)[j]? = if i = j then Function.const _ a <$> l[j]? else l[j]? := by
  by_cases i = j
  · simp only [getElem?_set_self', Option.map_eq_map, ↓reduceIte, *]
  · simp only [ne_eq, not_false_eq_true, getElem?_set_ne, ↓reduceIte, *]
Optional Indexing After List Replacement via Conditional Constant Mapping
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$, and element $a \in \alpha$, the optional indexing operation on the modified list $(l.\text{set}(i, a))[j]?$ equals: - The result of applying the constant function $\text{const}_\alpha(a)$ to $l[j]?$ (i.e., mapping $\text{const}_\alpha(a)$ over $l[j]?$) when $i = j$, - $l[j]?$ otherwise.
List.set_getElem_self theorem
{as : List α} {i : Nat} (h : i < as.length) : as.set i as[i] = as
Full source
@[simp] theorem set_getElem_self {as : List α} {i : Nat} (h : i < as.length) :
    as.set i as[i] = as := by
  apply ext_getElem
  · simp
  · intro n h₁ h₂
    rw [getElem_set]
    split <;> simp_all
List Invariance Under Self-Replacement at Valid Index
Informal description
For any list $as$ of elements of type $\alpha$ and any natural number index $i$ such that $i$ is a valid index for $as$ (i.e., $i < \text{length}(as)$), replacing the $i$-th element of $as$ with itself leaves the list unchanged, i.e., $as[i \mapsto as[i]] = as$.
List.set_eq_of_length_le theorem
{l : List α} {i : Nat} (h : l.length ≤ i) {a : α} : l.set i a = l
Full source
theorem set_eq_of_length_le {l : List α} {i : Nat} (h : l.length ≤ i) {a : α} :
    l.set i a = l := by
  induction l generalizing i with
  | nil => simp_all
  | cons a l ih =>
    induction i
    · simp_all
    · simp only [set_cons_succ, cons.injEq, true_and]
      rw [ih]
      exact Nat.succ_le_succ_iff.mp h
List Unchanged Under Replacement at Out-of-Bounds Index
Informal description
For any list $l$ of elements of type $\alpha$, if the index $i$ is greater than or equal to the length of $l$, then replacing the $i$-th element of $l$ with any element $a$ leaves the list unchanged, i.e., $l[i \mapsto a] = l$.
List.set_eq_nil_iff theorem
{l : List α} (i : Nat) (a : α) : l.set i a = [] ↔ l = []
Full source
@[simp] theorem set_eq_nil_iff {l : List α} (i : Nat) (a : α) : l.set i a = [] ↔ l = [] := by
  cases l <;> cases i <;> simp [set]
Empty List Preservation Under Element Replacement: $l[i \mapsto a] = [] \leftrightarrow l = []$
Informal description
For any list $l$ of elements of type $\alpha$, any natural number index $i$, and any element $a \in \alpha$, the list obtained by setting the $i$-th element of $l$ to $a$ is empty if and only if the original list $l$ is empty. In other words, $l[i \mapsto a] = [] \leftrightarrow l = []$.
List.set_comm theorem
(a b : α) : ∀ {i j : Nat} {l : List α}, i ≠ j → (l.set i a).set j b = (l.set j b).set i a
Full source
theorem set_comm (a b : α) : ∀ {i j : Nat} {l : List α}, i ≠ j →
    (l.set i a).set j b = (l.set j b).set i a
  | _, _, [], _ => by simp
  | _+1, 0, _ :: _, _ => by simp [set]
  | 0, _+1, _ :: _, _ => by simp [set]
  | _+1, _+1, _ :: t, h =>
    congrArg _ <| set_comm a b fun h' => h <| Nat.succ_inj'.mpr h'
Commutativity of List Updates at Distinct Indices: $(l[i \mapsto a])[j \mapsto b] = (l[j \mapsto b])[i \mapsto a]$ for $i \neq j$
Informal description
For any list $l$ of elements of type $\alpha$, any two distinct indices $i, j \in \mathbb{N}$, and any two elements $a, b \in \alpha$, updating the $i$-th element to $a$ followed by updating the $j$-th element to $b$ is equivalent to first updating the $j$-th element to $b$ and then updating the $i$-th element to $a$. That is, $(l[i \mapsto a])[j \mapsto b] = (l[j \mapsto b])[i \mapsto a]$.
List.set_set theorem
(a : α) {b : α} : ∀ {l : List α} {i : Nat}, (l.set i a).set i b = l.set i b
Full source
@[simp]
theorem set_set (a : α) {b : α} : ∀ {l : List α} {i : Nat}, (l.set i a).set i b = l.set i b
  | [], _ => by simp
  | _ :: _, 0 => by simp [set]
  | _ :: _, _+1 => by simp [set, set_set]
Double List Update at Same Index Simplifies to Single Update
Informal description
For any list $l$ of elements of type $\alpha$, any index $i \in \mathbb{N}$, and any elements $a, b \in \alpha$, updating the $i$-th element of $l$ to $a$ and then updating the same position to $b$ is equivalent to directly updating the $i$-th element to $b$. That is, $(l[i \mapsto a])[i \mapsto b] = l[i \mapsto b]$.
List.mem_set theorem
{l : List α} {i : Nat} (h : i < l.length) (a : α) : a ∈ l.set i a
Full source
theorem mem_set {l : List α} {i : Nat} (h : i < l.length) (a : α) :
    a ∈ l.set i a := by
  simp [mem_iff_getElem]
  exact ⟨i, (by simpa using h), by simp⟩
Element Membership After Replacement at Valid Index: $a \in l[i \mapsto a]$
Informal description
For any list $l$ of elements of type $\alpha$, any index $i$ such that $i < \text{length}(l)$, and any element $a$ of type $\alpha$, the element $a$ is contained in the list obtained by replacing the $i$-th element of $l$ with $a$, i.e., $a \in l.\text{set}(i, a)$.
List.mem_or_eq_of_mem_set theorem
: ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.set i b → a ∈ l ∨ a = b
Full source
theorem mem_or_eq_of_mem_set : ∀ {l : List α} {i : Nat} {a b : α}, a ∈ l.set i ba ∈ la ∈ l ∨ a = b
  | _ :: _, 0, _, _, h => ((mem_cons ..).1 h).symm.imp_left (.tail _)
  | _ :: _, _+1, _, _, .head .. => .inl (.head ..)
  | _ :: _, _+1, _, _, .tail _ h => (mem_or_eq_of_mem_set h).imp_left (.tail _)
Membership in Modified List Implies Original Membership or Equality
Informal description
For any list $l$ of elements of type $\alpha$, any index $i \in \mathbb{N}$, and any elements $a, b \in \alpha$, if $a$ is an element of the list obtained by setting the $i$-th element of $l$ to $b$, then either $a$ was already an element of $l$ or $a$ equals $b$. In other words, $a \in l[i \mapsto b] \rightarrow a \in l \lor a = b$.
List.beq_nil_iff theorem
[BEq α] {l : List α} : (l == []) = l.isEmpty
Full source
@[simp] theorem beq_nil_iff [BEq α] {l : List α} : (l == []) = l.isEmpty := by
  cases l <;> rfl
Boolean Equality of List with Empty List is Equivalent to List Emptiness Check
Informal description
For any list $l$ of elements of type $\alpha$ equipped with a boolean equality operation, the boolean equality comparison $l == \text{[]}$ is equivalent to checking whether $l$ is empty ($l.\text{isEmpty}$).
List.nil_beq_iff theorem
[BEq α] {l : List α} : ([] == l) = l.isEmpty
Full source
@[simp] theorem nil_beq_iff [BEq α] {l : List α} : ([] == l) = l.isEmpty := by
  cases l <;> rfl
Empty List Boolean Equality Equivalence to Emptiness Check
Informal description
For any list $l$ of elements of type $\alpha$ equipped with a boolean equality operation, the boolean equality comparison $\text{[]} == l$ is equivalent to checking whether $l$ is empty ($l.\text{isEmpty}$).
List.cons_beq_cons theorem
[BEq α] {a b : α} {l₁ l₂ : List α} : (a :: l₁ == b :: l₂) = (a == b && l₁ == l₂)
Full source
@[simp] theorem cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} :
    (a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl
Boolean Equality of Cons Lists Decomposes into Element and Tail Equality
Informal description
For any type $\alpha$ with a boolean equality operation, and for any elements $a, b \in \alpha$ and lists $l_1, l_2 \in \text{List } \alpha$, the boolean equality of the cons lists $(a :: l_1)$ and $(b :: l_2)$ is equivalent to the conjunction of the boolean equality of $a$ and $b$ and the boolean equality of $l_1$ and $l_2$. In symbols: $$(a :: l_1 == b :: l_2) = (a == b \ \&\& \ l_1 == l_2)$$
List.concat_beq_concat theorem
[BEq α] {a b : α} {l₁ l₂ : List α} : (l₁ ++ [a] == l₂ ++ [b]) = (l₁ == l₂ && a == b)
Full source
@[simp] theorem concat_beq_concat [BEq α] {a b : α} {l₁ l₂ : List α} :
    (l₁ ++ [a] == l₂ ++ [b]) = (l₁ == l₂ && a == b) := by
  induction l₁ generalizing l₂ with
  | nil => cases l₂ <;> simp
  | cons x l₁ ih =>
    cases l₂ with
    | nil => simp
    | cons y l₂ => simp [ih, Bool.and_assoc]
Boolean Equality of Concatenated Lists Decomposes into List and Element Equality
Informal description
For any type $\alpha$ with a boolean equality operation, and for any elements $a, b \in \alpha$ and lists $l_1, l_2 \in \text{List } \alpha$, the boolean equality of the concatenated lists $l_1 ++ [a]$ and $l_2 ++ [b]$ is equivalent to the conjunction of the boolean equality of $l_1$ and $l_2$ and the boolean equality of $a$ and $b$. In symbols: $$(l_1 ++ [a] == l_2 ++ [b]) = (l_1 == l_2 \ \&\& \ a == b)$$
List.length_eq_of_beq theorem
[BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length
Full source
theorem length_eq_of_beq [BEq α] {l₁ l₂ : List α} (h : l₁ == l₂) : l₁.length = l₂.length :=
  match l₁, l₂ with
  | [], [] => rfl
  | [], _ :: _ => by simp [beq_nil_iff] at h
  | _ :: _, [] => by simp [nil_beq_iff] at h
  | a :: l₁, b :: l₂ => by
    simp at h
    simpa [Nat.add_one_inj] using length_eq_of_beq h.2
Equal-length implication of boolean-equal lists
Informal description
For any type $\alpha$ with a boolean equality operation, if two lists $l_1$ and $l_2$ of type $\text{List } \alpha$ are boolean-equal (i.e., $l_1 == l_2$ evaluates to true), then their lengths are equal ($\text{length}(l_1) = \text{length}(l_2)$).
List.replicate_beq_replicate theorem
[BEq α] {a b : α} {n : Nat} : (replicate n a == replicate n b) = (n == 0 || a == b)
Full source
@[simp] theorem replicate_beq_replicate [BEq α] {a b : α} {n : Nat} :
    (replicate n a == replicate n b) = (n == 0 || a == b) := by
  cases n with
  | zero => simp
  | succ n =>
    rw [replicate_succ, replicate_succ, cons_beq_cons, replicate_beq_replicate]
    rw [Bool.eq_iff_iff]
    simp +contextual
Boolean Equality of Replicated Lists: $\text{replicate}(n, a) == \text{replicate}(n, b) \leftrightarrow (n = 0 \lor a == b)$
Informal description
For any type $\alpha$ with a boolean equality operation, and for any elements $a, b \in \alpha$ and natural number $n$, the boolean equality of the lists $\text{replicate}(n, a)$ and $\text{replicate}(n, b)$ (each containing $n$ copies of $a$ and $b$ respectively) is equivalent to the disjunction that either $n = 0$ or $a$ and $b$ are boolean-equal. In symbols: $$(\text{replicate}(n, a) == \text{replicate}(n, b)) = (n == 0 \lor a == b)$$
List.reflBEq_iff theorem
[BEq α] : ReflBEq (List α) ↔ ReflBEq α
Full source
@[simp] theorem reflBEq_iff [BEq α] : ReflBEqReflBEq (List α) ↔ ReflBEq α := by
  constructor
  · intro h
    constructor
    intro a
    suffices ([a] == [a]) = true by
      simpa only [List.instBEq, List.beq, Bool.and_true]
    simp
  · intro h
    constructor
    intro l
    induction l with
    | nil => simp only [List.instBEq, List.beq]
    | cons _ _ ih =>
      simp [List.instBEq, List.beq]
      exact ih
Reflexivity of List Boolean Equality iff Reflexivity of Element Boolean Equality
Informal description
For any type $\alpha$ with a boolean equality relation `==`, the boolean equality on lists of type `List α` is reflexive if and only if the boolean equality on $\alpha$ itself is reflexive. In other words, `ReflBEq (List α)` holds if and only if `ReflBEq α` holds.
List.lawfulBEq_iff theorem
[BEq α] : LawfulBEq (List α) ↔ LawfulBEq α
Full source
@[simp] theorem lawfulBEq_iff [BEq α] : LawfulBEqLawfulBEq (List α) ↔ LawfulBEq α := by
  constructor
  · intro h
    constructor
    · intro a b h
      apply singleton_inj.1
      apply eq_of_beq
      simp only [List.instBEq, List.beq]
      simpa
    · intro a
      suffices ([a] == [a]) = true by
        simpa only [List.instBEq, List.beq, Bool.and_true]
      simp
  · intro h
    constructor
    · intro _ _ h
      simpa using h
    · intro _
      simp
Lawfulness of List Boolean Equality iff Lawfulness of Element Boolean Equality
Informal description
For any type $\alpha$ with a boolean equality relation `==`, the boolean equality on lists of type `List\ \alpha` is lawful if and only if the boolean equality on $\alpha$ itself is lawful. In other words, `LawfulBEq (List\ \alpha)` holds if and only if `LawfulBEq\ \alpha` holds.
List.isEqv_eq theorem
[DecidableEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂)
Full source
@[simp] theorem isEqv_eq [DecidableEq α] {l₁ l₂ : List α} : l₁.isEqv l₂ (· == ·) = (l₁ = l₂) := by
  induction l₁ generalizing l₂ with
  | nil => cases l₂ <;> simp
  | cons a l₁ ih =>
    cases l₂ with
    | nil => simp
    | cons b l₂ => simp [isEqv, ih]
Equivalence of List Equality Tests: $\text{isEqv}\ l_1\ l_2\ (\cdot == \cdot) \leftrightarrow l_1 = l_2$
Informal description
For any type $\alpha$ with decidable equality and any two lists $l_1, l_2$ of type $\text{List}\ \alpha$, the boolean equality test `isEqv` between $l_1$ and $l_2$ using the boolean equality operator `==` is equivalent to the propositional equality $l_1 = l_2$.
List.getLast_eq_getElem theorem
: ∀ {l : List α} (h : l ≠ []), getLast l h = l[l.length - 1]'(by match l with | [] => contradiction | a :: l => exact Nat.le_refl _)
Full source
theorem getLast_eq_getElem : ∀ {l : List α} (h : l ≠ []),
    getLast l h = l[l.length - 1]'(by
      match l with
      | [] => contradiction
      | a :: l => exact Nat.le_refl _)
  | [_], _ => rfl
  | _ :: _ :: _, _ => by
    simp [getLast, Nat.succ_sub_succ, getLast_eq_getElem]
Last Element as Indexed Access: $\text{getLast}(l) = l[\text{length}(l) - 1]$ for Non-Empty Lists
Informal description
For any non-empty list $l$ of type $\text{List}\,\alpha$, the last element of $l$ is equal to the element at index $\text{length}(l) - 1$ of $l$, i.e., $\text{getLast}(l, h) = l[\text{length}(l) - 1]$, where $h$ is a proof that $l$ is non-empty.
List.getElem_length_sub_one_eq_getLast theorem
{l : List α} (h : l.length - 1 < l.length) : l[l.length - 1] = getLast l (by cases l; simp at h; simp)
Full source
theorem getElem_length_sub_one_eq_getLast {l : List α} (h : l.length - 1 < l.length) :
    l[l.length - 1] = getLast l (by cases l; simp at h; simp) := by
  rw [← getLast_eq_getElem]
Last Element as Indexed Access: $l[\text{length}(l) - 1] = \text{getLast}(l)$ for Valid Indices
Informal description
For any list $l$ of type $\text{List}\,\alpha$ such that $\text{length}(l) - 1$ is a valid index (i.e., $\text{length}(l) - 1 < \text{length}(l)$), the element at index $\text{length}(l) - 1$ is equal to the last element of $l$, i.e., $l[\text{length}(l) - 1] = \text{getLast}(l)$.
List.getLast_cons theorem
{a : α} {l : List α} : ∀ (h : l ≠ nil), getLast (a :: l) (cons_ne_nil a l) = getLast l h
Full source
theorem getLast_cons {a : α} {l : List α} : ∀ (h : l ≠ nil),
    getLast (a :: l) (cons_ne_nil a l) = getLast l h := by
  induction l <;> intros; {contradiction}; rfl
Last Element Preservation Under Cons Operation
Informal description
For any element $a$ of type $\alpha$ and any non-empty list $l$ of type $\text{List}\,\alpha$, the last element of the list $a :: l$ is equal to the last element of $l$, i.e., $\text{getLast}(a :: l, h) = \text{getLast}(l, h')$ where $h$ is a proof that $a :: l$ is non-empty and $h'$ is a proof that $l$ is non-empty.
List.getLast_eq_getLastD theorem
{a l} (h) : @getLast α (a :: l) h = getLastD l a
Full source
theorem getLast_eq_getLastD {a l} (h) : @getLast α (a::l) h = getLastD l a := by
  cases l <;> rfl
Equality of Last Element and Default Last Element for Cons List
Informal description
For any element $a$ of type $\alpha$ and any non-empty list $l$ of type $\text{List }\alpha$, the last element of the list $a :: l$ is equal to the default last element of $l$ with default value $a$, i.e., $\text{getLast}(a :: l, h) = \text{getLastD}(l, a)$, where $h$ is a proof that $a :: l$ is non-empty.
List.getLastD_eq_getLast? theorem
{a l} : @getLastD α l a = (getLast? l).getD a
Full source
@[simp] theorem getLastD_eq_getLast? {a l} : @getLastD α l a = (getLast? l).getD a := by
  cases l <;> rfl
Equality between default last element and optional last element with default
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the default last element $\text{getLastD}(l, a)$ is equal to the default value of the optional last element of $l$ with default $a$, i.e., $\text{getLastD}(l, a) = (\text{getLast?}\,l).\text{getD}\,a$.
List.getLast_singleton theorem
{a} (h) : @getLast α [a] h = a
Full source
@[simp] theorem getLast_singleton {a} (h) : @getLast α [a] h = a := rfl
Last Element of Singleton List is Its Only Element
Informal description
For any element $a$ of type $\alpha$ and a proof $h$ that the list $[a]$ is non-empty, the last element of the singleton list $[a]$ is equal to $a$, i.e., $\text{getLast}([a], h) = a$.
List.getLast!_cons_eq_getLastD theorem
[Inhabited α] : @getLast! α _ (a :: l) = getLastD l a
Full source
theorem getLast!_cons_eq_getLastD [Inhabited α] : @getLast! α _ (a::l) = getLastD l a := by
  simp [getLast!, getLast_eq_getLastD]
Equality of `getLast!` on Cons List and Default Last Element: $\text{getLast!}(a :: l) = \text{getLastD}(l, a)$
Informal description
For any inhabited type $\alpha$, the last element of the list $a :: l$ obtained via `getLast!` is equal to the default last element of $l$ with default value $a$, i.e., $\text{getLast!}(a :: l) = \text{getLastD}(l, a)$.
List.getLast_mem theorem
: ∀ {l : List α} (h : l ≠ []), getLast l h ∈ l
Full source
@[simp] theorem getLast_mem : ∀ {l : List α} (h : l ≠ []), getLastgetLast l h ∈ l
  | [], h => absurd rfl h
  | [_], _ => .head ..
  | _::a::l, _ => .tail _ <| getLast_mem (cons_ne_nil a l)
Last Element Belongs to List
Informal description
For any nonempty list $l$ of type $\alpha$, the last element of $l$ (obtained via $\text{getLast}(l, h)$ where $h$ is a proof that $l \neq []$) is an element of $l$.
List.getLast_mem_getLast? theorem
: ∀ {l : List α} (h : l ≠ []), getLast l h ∈ getLast? l
Full source
theorem getLast_mem_getLast? : ∀ {l : List α} (h : l ≠ []), getLastgetLast l h ∈ getLast? l
  | [], h => by contradiction
  | _ :: _, _ => rfl
Last Element is in Optional Result of `getLast?`
Informal description
For any nonempty list $l$ of type $\alpha$, the last element of $l$ (obtained via `getLast l h` where $h$ is a proof that $l \neq []$) is contained in the optional value returned by `getLast? l` (which is `some x` if $x$ is the last element of $l$, and `none` otherwise).
List.getLastD_mem_cons theorem
: ∀ {l : List α} {a : α}, getLastD l a ∈ a :: l
Full source
theorem getLastD_mem_cons : ∀ {l : List α} {a : α}, getLastDgetLastD l a ∈ a::l
  | [], _ => .head ..
  | _::_, _ => .tail _ <| getLast_mem _
Last Element or Default Belongs to Extended List
Informal description
For any list $l$ of type $\alpha$ and any element $a$ of type $\alpha$, the element obtained from $\text{getLastD}(l, a)$ (which returns the last element of $l$ if $l$ is nonempty, otherwise returns $a$) is an element of the list $a :: l$.
List.getElem_cons_length theorem
{x : α} {xs : List α} {i : Nat} (h : i = xs.length) : (x :: xs)[i]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs)
Full source
theorem getElem_cons_length {x : α} {xs : List α} {i : Nat} (h : i = xs.length) :
    (x :: xs)[i]'(by simp [h]) = (x :: xs).getLast (cons_ne_nil x xs) := by
  rw [getLast_eq_getElem]; cases h; rfl
Index at Length of Cons List Equals Last Element
Informal description
For any element $x$ of type $\alpha$, any list $xs$ of type $\text{List}\,\alpha$, and any natural number index $i$ such that $i = \text{length}(xs)$, the element at index $i$ of the list $x :: xs$ is equal to the last element of $x :: xs$.
List.getLast?_singleton theorem
{a : α} : getLast? [a] = a
Full source
@[simp] theorem getLast?_singleton {a : α} : getLast? [a] = a := rfl
Last Element of Singleton List
Informal description
For any element $a$ of type $\alpha$, the optional last element of the singleton list $[a]$ is equal to $a$, i.e., $\text{getLast?} [a] = a$.
List.getLast?_eq_getLast theorem
: ∀ {l : List α} h, l.getLast? = some (l.getLast h)
Full source
theorem getLast?_eq_getLast : ∀ {l : List α} h, l.getLast? = some (l.getLast h)
  | [], h => nomatch h rfl
  | _ :: _, _ => rfl
Equivalence of `getLast?` and `some` of `getLast` for Nonempty Lists
Informal description
For any nonempty list $l$ of elements 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 nonempty.
List.getLast?_eq_getElem? theorem
: ∀ {l : List α}, l.getLast? = l[l.length - 1]?
Full source
theorem getLast?_eq_getElem? : ∀ {l : List α}, l.getLast? = l[l.length - 1]?
  | [] => rfl
  | a::l => by
    rw [getLast?_eq_getLast (l := a :: l) nofun, getLast_eq_getElem, getElem?_eq_getElem]
Equivalence of Last Element and Optional Indexing: $\text{getLast?}(l) = l[\text{length}(l) - 1]?$
Informal description
For any list $l$ of type $\text{List}\,\alpha$, the optional last element $\text{getLast?}(l)$ is equal to the optional element at index $\text{length}(l) - 1$ of $l$, i.e., $\text{getLast?}(l) = l[\text{length}(l) - 1]?$.
List.getLast_eq_iff_getLast?_eq_some theorem
{xs : List α} (h) : xs.getLast h = a ↔ xs.getLast? = some a
Full source
theorem getLast_eq_iff_getLast?_eq_some {xs : List α} (h) :
    xs.getLast h = a ↔ xs.getLast? = some a := by
  rw [getLast?_eq_getLast h]
  simp
Equivalence of Last Element and Optional Last Element: $xs.\text{getLast}\ h = a \leftrightarrow xs.\text{getLast}? = \text{some}\ a$
Informal description
For any nonempty list $xs$ of elements of type $\alpha$ (with nonemptiness witness $h$), the last element $xs.\text{getLast}\ h$ is equal to $a$ if and only if the optional last element $xs.\text{getLast}?$ is equal to $\text{some}\ a$.
List.getLast?_cons theorem
{a : α} : (a :: l).getLast? = l.getLast?.getD a
Full source
theorem getLast?_cons {a : α} : (a::l).getLast? = l.getLast?.getD a := by
  cases l <;> simp [getLast?, getLast]
Last Element of Cons List with Default
Informal description
For any element $a$ of type $\alpha$ and list $l$ of type $\text{List }\alpha$, the last element of the list $a :: l$ (obtained via `getLast?`) is equal to the default value of the last element of $l$ (obtained via `getLast?`) with default $a$. In other words, $\text{getLast?}(a :: l) = \text{getD}(\text{getLast?}(l), a)$.
List.getLast?_cons_cons theorem
: (a :: b :: l).getLast? = (b :: l).getLast?
Full source
@[simp] theorem getLast?_cons_cons : (a :: b :: l).getLast? = (b :: l).getLast? := by
  simp [getLast?_cons]
Last Element of Double-Cons List Equals Last Element of Tail
Informal description
For any elements $a, b$ of type $\alpha$ and list $l$ of type $\text{List }\alpha$, the last element of the list $a :: b :: l$ (obtained via `getLast?`) is equal to the last element of the list $b :: l$ (obtained via `getLast?$).
List.getLast?_concat theorem
{l : List α} {a : α} : (l ++ [a]).getLast? = some a
Full source
theorem getLast?_concat {l : List α} {a : α} : (l ++ [a]).getLast? = some a := by
  simp [getLast?_eq_getElem?, Nat.succ_sub_succ]
Last Element of Concatenated List: $\text{getLast?}(l \mathbin{+\kern-0.5ex+} [a]) = \text{some}\,a$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and element $a$ of type $\alpha$, the optional last element of the concatenated list $l \mathbin{+\kern-0.5ex+} [a]$ is $\text{some}\,a$.
List.getLastD_concat theorem
{a b} {l : List α} : (l ++ [b]).getLastD a = b
Full source
theorem getLastD_concat {a b} {l : List α} : (l ++ [b]).getLastD a = b := by
  rw [getLastD_eq_getLast?, getLast?_concat]; rfl
Default Last Element of Concatenated List: $\text{getLastD}(l \mathbin{+\kern-0.5ex+} [b], a) = b$
Informal description
For any elements $a, b$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the default last element of the concatenated list $l \mathbin{+\kern-0.5ex+} [b]$ with default value $a$ is equal to $b$.
List.getLast!_nil theorem
[Inhabited α] : ([] : List α).getLast! = default
Full source
theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
Forced Last Element of Empty List is Default
Informal description
For any inhabited type $\alpha$, the forced last element of the empty list is the default element of $\alpha$, i.e., $\text{getLast!}\ [] = \text{default}$.
List.getLast!_eq_getLast?_getD theorem
[Inhabited α] {l : List α} : getLast! l = (getLast? l).getD default
Full source
@[simp] theorem getLast!_eq_getLast?_getD [Inhabited α] {l : List α} : getLast! l = (getLast? l).getD default := by
  cases l with
  | nil => simp [getLast!_nil]
  | cons _ _ => simp [getLast!, getLast?_eq_getLast]
Forced Last Element Equals Default of Optional Last Element
Informal description
For any inhabited type $\alpha$ and any list $l$ of elements of type $\alpha$, the forced last element $\text{getLast!}\ l$ is equal to the default value of $\alpha$ applied to the optional last element of $l$, i.e., $\text{getLast!}\ l = (\text{getLast?}\ l).\text{getD}\ \text{default}$.
List.getLast!_of_getLast? theorem
[Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
Full source
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
  | _ :: _, rfl => rfl
Forced Last Element Equals Last Element When Present
Informal description
For any inhabited type $\alpha$ and any list $l$ of elements of type $\alpha$, if the last element of $l$ exists (i.e., $\text{getLast?}\ l = \text{some}\ a$ for some $a \in \alpha$), then the forced last element $\text{getLast!}\ l$ equals $a$.
List.getLast!_eq_getElem! theorem
[Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]!
Full source
theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]! := by
  cases l with
  | nil => simp
  | cons _ _ =>
    apply getLast!_of_getLast?
    rw [getElem!_pos, getElem_cons_length (h := by simp)]
    rfl
Forced Last Element Equals Forced Access at Length Minus One: $\text{getLast!}\ l = l[\text{length}(l) - 1]!$
Informal description
For any inhabited type $\alpha$ and any list $l$ of elements of type $\alpha$, the forced last element operation $\text{getLast!}\ l$ is equal to the forced element access operation at index $\text{length}(l) - 1$, i.e., $l[\text{length}(l) - 1]!$.
List.head?_singleton theorem
{a : α} : head? [a] = some a
Full source
theorem head?_singleton {a : α} : head? [a] = some a := by simp
Head of Singleton List is Some Element
Informal description
For any element $a$ of type $\alpha$, the `head?` function applied to the singleton list $[a]$ returns `some a`.
List.head!_of_head? theorem
[Inhabited α] : ∀ {l : List α}, head? l = some a → head! l = a
Full source
theorem head!_of_head? [Inhabited α] : ∀ {l : List α}, head? l = some a → head! l = a
  | _ :: _, rfl => rfl
Equivalence of `head!` and `head?` for Nonempty Lists
Informal description
For any inhabited type $\alpha$ and any list $l$ of elements of type $\alpha$, if the `head?` function applied to $l$ returns `some a`, then the `head!` function applied to $l$ returns $a$.
List.head?_eq_head theorem
: ∀ {l : List α} h, l.head? = some (head l h)
Full source
theorem head?_eq_head : ∀ {l : List α} h, l.head? = some (head l h)
  | _ :: _, _ => rfl
Equivalence of Optional Head and Head with Nonempty Proof
Informal description
For any nonempty list $l$ of elements of type $\alpha$ and any proof $h$ that $l$ is nonempty, the optional head of $l$ (obtained via `head?`) is equal to `some` applied to the head of $l$ (obtained via `head` with proof $h$).
List.head?_eq_getElem? theorem
: ∀ {l : List α}, l.head? = l[0]?
Full source
theorem head?_eq_getElem? : ∀ {l : List α}, l.head? = l[0]?
  | [] => rfl
  | a :: l => by simp
Equivalence of Optional Head and Optional Zero Index Access: $\text{head?}(l) = l[0]?$
Informal description
For any list $l$ of elements of type $\alpha$, the optional head of $l$ (obtained via `head?`) is equal to the optional element at index $0$ of $l$ (obtained via `l[0]?`).
List.head_singleton theorem
{a : α} : head [a] (by simp) = a
Full source
theorem head_singleton {a : α} : head [a] (by simp) = a := by simp
Head of Singleton List Equals Its Element ($\text{head}[a] = a$)
Informal description
For any element $a$ of type $\alpha$, the head of the singleton list $[a]$ is equal to $a$.
List.head_eq_getElem theorem
{l : List α} (h : l ≠ []) : head l h = l[0]'(length_pos_iff.mpr h)
Full source
theorem head_eq_getElem {l : List α} (h : l ≠ []) : head l h = l[0]'(length_pos_iff.mpr h) := by
  cases l with
  | nil => simp at h
  | cons _ _ => simp
Head of Non-Empty List Equals First Element: $\text{head}(l) = l[0]$
Informal description
For any non-empty list $l$ of type $\alpha$ (i.e., $l \neq []$), the head of $l$ is equal to the element at index $0$ of $l$, where the proof that $0$ is a valid index is derived from the fact that $l$ is non-empty.
List.getElem_zero_eq_head theorem
{l : List α} (h : 0 < l.length) : l[0] = head l (by simpa [length_pos_iff] using h)
Full source
theorem getElem_zero_eq_head {l : List α} (h : 0 < l.length) :
    l[0] = head l (by simpa [length_pos_iff] using h) := by
  cases l with
  | nil => simp at h
  | cons _ _ => simp
First Element Equals Head in Non-Empty Lists: $l[0] = \text{head}(l)$
Informal description
For any non-empty list $l$ of type $\alpha$ (i.e., $0 < \text{length}(l)$), the first element $l[0]$ is equal to the head of $l$.
List.head_eq_iff_head?_eq_some theorem
{xs : List α} (h) : xs.head h = a ↔ xs.head? = some a
Full source
theorem head_eq_iff_head?_eq_some {xs : List α} (h) : xs.head h = a ↔ xs.head? = some a := by
  cases xs with
  | nil => simp at h
  | cons x xs => simp
Equivalence between List Head and Optional Head: $\text{head}\ xs\ h = a \leftrightarrow \text{head?}\ xs = \text{some}\ a$
Informal description
For a non-empty list `xs` of type `α` and an element `a : α`, the head of `xs` (with proof `h` that `xs` is non-empty) is equal to `a` if and only if the optional head of `xs` (which returns `some a` when `xs` is non-empty) equals `some a`.
List.head?_eq_none_iff theorem
: l.head? = none ↔ l = []
Full source
@[simp] theorem head?_eq_none_iff : l.head? = none ↔ l = [] := by
  cases l <;> simp
Empty List Characterization via Head Option: $l.\text{head?} = \text{none} \leftrightarrow l = []$
Informal description
For any list $l$ of type $\alpha$, the head option of $l$ is `none` if and only if $l$ is the empty list. In other words, $l.\text{head?} = \text{none} \leftrightarrow l = []$.
List.head?_eq_some_iff theorem
{xs : List α} {a : α} : xs.head? = some a ↔ ∃ ys, xs = a :: ys
Full source
theorem head?_eq_some_iff {xs : List α} {a : α} : xs.head? = some a ↔ ∃ ys, xs = a :: ys := by
  cases xs <;> simp_all
Head Option Characterization: $\text{head?}(xs) = \text{some }a \leftrightarrow \exists ys, xs = a :: ys$
Informal description
For any list $xs$ of type $\alpha$ and any element $a \in \alpha$, the head option of $xs$ equals `some a` if and only if there exists a list $ys$ such that $xs = a :: ys$.
List.isSome_head? theorem
: l.head?.isSome ↔ l ≠ []
Full source
@[simp] theorem isSome_head? : l.head?.isSome ↔ l ≠ [] := by
  cases l <;> simp
Non-Empty List Characterization via Head Option: $\text{isSome}(l.\text{head?}) \leftrightarrow l \neq []$
Informal description
For any list $l$ of type $\alpha$, the head option of $l$ is `some` (i.e., `l.head?.isSome` is true) if and only if $l$ is not the empty list (i.e., $l \neq []$).
List.head?_isSome abbrev
Full source
@[deprecated isSome_head? (since := "2025-03-18")]
abbrev head?_isSome := @isSome_head?
Non-Empty List Characterization via Head Option: $\text{isSome}(l.\text{head?}) \leftrightarrow l \neq []$
Informal description
For any list $l$ of type $\alpha$, the head option of $l$ is `some` (i.e., `l.head?.isSome` is true) if and only if $l$ is not the empty list (i.e., $l \neq []$).
List.head_mem theorem
: ∀ {l : List α} (h : l ≠ []), head l h ∈ l
Full source
@[simp] theorem head_mem : ∀ {l : List α} (h : l ≠ []), headhead l h ∈ l
  | [], h => absurd rfl h
  | _::_, _ => .head ..
Head Element is Member of Non-Empty List
Informal description
For any non-empty list $l$ of type $\alpha$, the head element of $l$ (denoted $\text{head}(l)$) is a member of $l$.
List.mem_of_mem_head? theorem
: ∀ {l : List α} {a : α}, a ∈ l.head? → a ∈ l
Full source
theorem mem_of_mem_head? : ∀ {l : List α} {a : α}, a ∈ l.head?a ∈ l := by
  intro l a h
  cases l with
  | nil => simp at h
  | cons b l =>
    simp at h
    cases h
    exact mem_cons_self
Membership in Optional Head Implies Membership in List
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, if $a$ is in the optional head of $l$ (i.e., $a \in l.\text{head?}$), then $a$ is a member of $l$ (i.e., $a \in l$).
List.head_mem_head? theorem
: ∀ {l : List α} (h : l ≠ []), head l h ∈ head? l
Full source
theorem head_mem_head? : ∀ {l : List α} (h : l ≠ []), headhead l h ∈ head? l
  | [], h => by contradiction
  | _ :: _, _ => rfl
Head Element Belongs to Optional Head
Informal description
For any non-empty list $l$ of elements of type $\alpha$, the head element of $l$ (denoted $\text{head}(l, h)$ where $h$ is a proof that $l \neq []$) is contained in the optional head element $\text{head?}(l)$ (which is $\text{some}(\text{head}(l, h))$ when $l$ is non-empty).
List.head?_concat theorem
{a : α} : (l ++ [a]).head? = l.head?.getD a
Full source
theorem head?_concat {a : α} : (l ++ [a]).head? = l.head?.getD a := by
  cases l <;> simp
Head of Concatenated List with Singleton
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the head of the concatenated list $l \mathbin{+\!\!+} [a]$ is equal to the head of $l$ if $l$ is non-empty, and is equal to $a$ otherwise. Formally, this is expressed as: $$(l \mathbin{+\!\!+} [a]).\text{head?} = l.\text{head?}.\text{getD} a$$
List.head?_concat_concat theorem
: (l ++ [a, b]).head? = (l ++ [a]).head?
Full source
theorem head?_concat_concat : (l ++ [a, b]).head? = (l ++ [a]).head? := by
  cases l <;> simp
Head Preservation in Double Concatenation
Informal description
For any list $l$ of elements of type $\alpha$ and any elements $a, b \in \alpha$, the head of the concatenated list $l \mathbin{+\!\!+} [a, b]$ is equal to the head of the concatenated list $l \mathbin{+\!\!+} [a]$. In other words, when concatenating a list with two elements, the head of the resulting list depends only on the first concatenated element (if the original list is empty) or the original list's head (if non-empty).
List.headD_eq_head?_getD theorem
{l : List α} : headD l a = (head? l).getD a
Full source
/-- `simp` unfolds `headD` in terms of `head?` and `Option.getD`. -/
@[simp] theorem headD_eq_head?_getD {l : List α} : headD l a = (head? l).getD a := by
  cases l <;> simp [headD]
Equivalence of Default Head Function and Optional Head with Default
Informal description
For any list $l$ of elements of type $\alpha$ and any default value $a \in \alpha$, the default head function $\text{headD}$ applied to $l$ with default $a$ is equal to the result of applying the $\text{getD}$ function to the optional head $\text{head?}(l)$ with the same default value $a$. In other words, $\text{headD}(l, a) = \text{getD}(\text{head?}(l), a)$.
List.tailD_eq_tail? theorem
{l l' : List α} : tailD l l' = (tail? l).getD l'
Full source
/-- `simp` unfolds `tailD` in terms of `tail?` and `Option.getD`. -/
@[simp] theorem tailD_eq_tail? {l l' : List α} : tailD l l' = (tail? l).getD l' := by
  cases l <;> rfl
Equivalence of Default Tail Function and Optional Tail with Default
Informal description
For any list $l$ of elements of type $\alpha$ and any default list $l'$ of elements of type $\alpha$, the default tail operation $\text{tailD}(l, l')$ is equal to the result of applying the default value operation $\text{getD}$ to the optional tail $\text{tail?}(l)$ with default value $l'$. In other words, $\text{tailD}(l, l') = \text{getD}(\text{tail?}(l), l')$.
List.length_tail theorem
{l : List α} : l.tail.length = l.length - 1
Full source
@[simp] theorem length_tail {l : List α} : l.tail.length = l.length - 1 := by cases l <;> rfl
Length of Tail Equals Length Minus One
Informal description
For any list $l$ of elements of type $\alpha$, the length of the tail of $l$ is equal to the length of $l$ minus one, i.e., $\text{length}(\text{tail}(l)) = \text{length}(l) - 1$.
List.tail_eq_tailD theorem
{l : List α} : l.tail = tailD l []
Full source
theorem tail_eq_tailD {l : List α} : l.tail = tailD l [] := by cases l <;> rfl
Tail of List Equals Default Tail Operation with Empty List
Informal description
For any list $l$ of elements of type $\alpha$, the tail of $l$ (denoted $l.\text{tail}$) is equal to the default tail operation applied to $l$ with the empty list as the default value (denoted $\text{tailD}\ l\ []$).
List.tail_eq_tail? theorem
{l : List α} : l.tail = (tail? l).getD []
Full source
theorem tail_eq_tail? {l : List α} : l.tail = (tail? l).getD [] := by simp [tail_eq_tailD]
Tail Equals Default Optional Tail with Empty List
Informal description
For any list $l$ of elements of type $\alpha$, the tail of $l$ is equal to the default value operation applied to the optional tail of $l$ with the empty list as the default value, i.e., $\text{tail}(l) = \text{getD}(\text{tail?}(l), [])$.
List.mem_of_mem_tail theorem
{a : α} {l : List α} (h : a ∈ tail l) : a ∈ l
Full source
theorem mem_of_mem_tail {a : α} {l : List α} (h : a ∈ tail l) : a ∈ l := by
  induction l <;> simp_all
Membership in Tail Implies Membership in List
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, if $a$ is a member of the tail of $l$, then $a$ is a member of $l$.
List.ne_nil_of_tail_ne_nil theorem
{l : List α} : l.tail ≠ [] → l ≠ []
Full source
theorem ne_nil_of_tail_ne_nil {l : List α} : l.tail ≠ []l ≠ [] := by
  cases l <;> simp
Non-empty tail implies non-empty list
Informal description
For any list $l$ of elements of type $\alpha$, if the tail of $l$ is not the empty list, then $l$ itself is not the empty list.
List.getElem_tail theorem
{l : List α} {i : Nat} (h : i < l.tail.length) : (tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h))
Full source
@[simp] theorem getElem_tail {l : List α} {i : Nat} (h : i < l.tail.length) :
    (tail l)[i] = l[i + 1]'(add_lt_of_lt_sub (by simpa using h)) := by
  cases l with
  | nil => simp at h
  | cons _ l => simp
Tail Index Shift for List Elements
Informal description
For any list $l$ of elements of type $\alpha$ and natural number index $i$ such that $i < \text{length}(\text{tail}(l))$, the element at position $i$ in the tail of $l$ is equal to the element at position $i+1$ in $l$. That is: $$ (\text{tail } l)[i] = l[i+1] $$
List.getElem?_tail theorem
{l : List α} {i : Nat} : (tail l)[i]? = l[i + 1]?
Full source
@[simp] theorem getElem?_tail {l : List α} {i : Nat} :
    (tail l)[i]? = l[i + 1]? := by
  cases l <;> simp
Tail Index Shift for Optional List Lookup
Informal description
For any list $l$ of elements of type $\alpha$ and natural number index $i$, the optional lookup operation on the tail of $l$ at position $i$ is equal to the optional lookup operation on $l$ at position $i+1$. In other words: $$ (\text{tail } l)[i]? = l[i+1]? $$
List.set_tail theorem
{l : List α} {i : Nat} {a : α} : l.tail.set i a = (l.set (i + 1) a).tail
Full source
@[simp] theorem set_tail {l : List α} {i : Nat} {a : α} :
    l.tail.set i a = (l.set (i + 1) a).tail := by
  cases l <;> simp
Tail-Preserving List Element Replacement: $\text{tail}(l).\text{set}(i, a) = \text{tail}(l.\text{set}(i+1, a))$
Informal description
For any list $l$ of elements of type $\alpha$, natural number index $i$, and element $a \in \alpha$, setting the element at position $i$ in the tail of $l$ to $a$ is equivalent to first setting the element at position $i+1$ in $l$ to $a$ and then taking the tail of the resulting list. In other words: $$ \text{tail}(l).\text{set}(i, a) = \text{tail}(l.\text{set}(i+1, a)) $$
List.one_lt_length_of_tail_ne_nil theorem
{l : List α} (h : l.tail ≠ []) : 1 < l.length
Full source
theorem one_lt_length_of_tail_ne_nil {l : List α} (h : l.tail ≠ []) : 1 < l.length := by
  cases l with
  | nil => simp at h
  | cons _ l =>
    simp only [tail_cons, ne_eq] at h
    exact Nat.lt_add_of_pos_left (length_pos_iff.mpr h)
Non-empty tail implies list length > 1
Informal description
For any list $l$ of elements of type $\alpha$, if the tail of $l$ is not the empty list, then the length of $l$ is strictly greater than 1, i.e., $1 < \text{length}(l)$.
List.head_tail theorem
{l : List α} (h : l.tail ≠ []) : (tail l).head h = l[1]'(one_lt_length_of_tail_ne_nil h)
Full source
@[simp] theorem head_tail {l : List α} (h : l.tail ≠ []) :
    (tail l).head h = l[1]'(one_lt_length_of_tail_ne_nil h) := by
  cases l with
  | nil => simp at h
  | cons _ l => simp [head_eq_getElem]
Head of Tail Equals Second Element: $\text{head}(\text{tail } l) = l[1]$
Informal description
For any non-empty list $l$ of elements of type $\alpha$ such that the tail of $l$ is also non-empty, the head of the tail of $l$ is equal to the element at index $1$ of $l$.
List.head?_tail theorem
{l : List α} : (tail l).head? = l[1]?
Full source
@[simp] theorem head?_tail {l : List α} : (tail l).head? = l[1]? := by
  simp [head?_eq_getElem?]
Tail Head Equals Second Element: $\text{head?}(\text{tail } l) = l[1]?$
Informal description
For any list $l$ of elements of type $\alpha$, the optional head of the tail of $l$ is equal to the optional element at index $1$ of $l$. In other words: $$ \text{head?}(\text{tail } l) = l[1]? $$
List.getLast_tail theorem
{l : List α} (h : l.tail ≠ []) : (tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h)
Full source
@[simp] theorem getLast_tail {l : List α} (h : l.tail ≠ []) :
    (tail l).getLast h = l.getLast (ne_nil_of_tail_ne_nil h) := by
  simp only [getLast_eq_getElem, length_tail, getElem_tail]
  congr
  match l with
  | _ :: _ :: l => simp
Last Element Invariance Under Tail Operation: $\text{getLast}(\text{tail } l) = \text{getLast}(l)$ for Lists with Non-Empty Tail
Informal description
For any non-empty list $l$ of elements of type $\alpha$ such that the tail of $l$ is also non-empty, the last element of the tail of $l$ is equal to the last element of $l$ itself. That is: $$ \text{getLast}(\text{tail } l, h) = \text{getLast}(l, h') $$ where $h$ is a proof that $\text{tail } l \neq []$ and $h'$ is the derived proof that $l \neq []$.
List.getLast?_tail theorem
{l : List α} : (tail l).getLast? = if l.length = 1 then none else l.getLast?
Full source
theorem getLast?_tail {l : List α} : (tail l).getLast? = if l.length = 1 then none else l.getLast? := by
  match l with
  | [] => simp
  | [a] => simp
  | _ :: _ :: l =>
    simp only [tail_cons, length_cons, getLast?_cons_cons]
    rw [if_neg]
    rintro ⟨⟩
Tail's Last Element Condition: $\text{getLast?}(\text{tail } l) = \text{if } |l| = 1 \text{ then none else getLast?}(l)$
Informal description
For any list $l$ of elements of type $\alpha$, the optional last element of the tail of $l$ is equal to: - $\text{none}$ if the length of $l$ is 1, - otherwise it equals the optional last element of $l$ itself. In other words: $$ \text{getLast?}(\text{tail } l) = \begin{cases} \text{none} & \text{if } \text{length}(l) = 1 \\ \text{getLast?}(l) & \text{otherwise} \end{cases} $$
List.length_map theorem
{as : List α} (f : α → β) : (as.map f).length = as.length
Full source
@[simp] theorem length_map {as : List α} (f : α → β) : (as.map f).length = as.length := by
  induction as with
  | nil => simp [List.map]
  | cons _ as ih => simp [List.map, ih]
Length Preservation under List Mapping
Informal description
For any list $as$ of elements of type $\alpha$ and any function $f : \alpha \to \beta$, the length of the mapped list $as.\text{map}(f)$ is equal to the length of the original list $as$, i.e., $\text{length}(as.\text{map}(f)) = \text{length}(as)$.
List.getElem?_map theorem
{f : α → β} : ∀ {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
Full source
@[simp] theorem getElem?_map {f : α → β} : ∀ {l : List α} {i : Nat}, (map f l)[i]? = Option.map f l[i]?
  | [], _ => rfl
  | _ :: _, 0 => by simp
  | _ :: l, i+1 => by simp [getElem?_map]
Commutativity of Mapping and Optional Indexing: $(l.\text{map}\,f)[i]? = \text{Option.map}\,f\,(l[i]?)$
Informal description
For any function $f : \alpha \to \beta$, list $l$ of type $\text{List}\,\alpha$, and natural number index $i$, the optional indexing operation $(l.\text{map}\,f)[i]?$ is equal to $\text{Option.map}\,f\,(l[i]?)$. In other words, mapping a function over a list and then optionally indexing at position $i$ is equivalent to optionally indexing at position $i$ first and then mapping the function over the result (if any).
List.getElem_map theorem
(f : α → β) {l} {i : Nat} {h : i < (map f l).length} : (map f l)[i] = f (l[i]'(length_map f ▸ h))
Full source
@[simp] theorem getElem_map (f : α → β) {l} {i : Nat} {h : i < (map f l).length} :
    (map f l)[i] = f (l[i]'(length_map f ▸ h)) :=
  Option.some.inj <| by rw [← getElem?_eq_getElem, getElem?_map, getElem?_eq_getElem]; rfl
Element-wise Mapping Preserves Indexing: $(l.\text{map}\,f)[i] = f(l[i])$
Informal description
For any function $f : \alpha \to \beta$, list $l$ of type $\text{List}\,\alpha$, and natural number index $i$ such that $i < \text{length}\,(l.\text{map}\,f)$, the element at position $i$ in the mapped list $(l.\text{map}\,f)[i]$ is equal to $f$ applied to the element at position $i$ in the original list $l[i]$.
List.map_id_fun theorem
: map (id : α → α) = id
Full source
@[simp] theorem map_id_fun : map (id : α → α) = id := by
  funext l
  induction l <;> simp_all
Identity Mapping on Lists: $\text{map}\ \text{id} = \text{id}$
Informal description
The map operation on lists, when applied with the identity function $\text{id} : \alpha \to \alpha$, is equal to the identity function on lists.
List.map_id_fun' theorem
: map (fun (a : α) => a) = id
Full source
/-- `map_id_fun'` differs from `map_id_fun` by representing the identity function as a lambda, rather than `id`. -/
@[simp] theorem map_id_fun' : map (fun (a : α) => a) = id := map_id_fun
Identity Mapping on Lists via Anonymous Function: $\text{map}\ (\lambda a. a) = \text{id}$
Informal description
The map operation on lists, when applied with the anonymous identity function $\lambda (a : \alpha), a$, is equal to the identity function on lists.
List.map_id theorem
(l : List α) : map (id : α → α) l = l
Full source
theorem map_id (l : List α) : map (id : α → α) l = l := by
  induction l <;> simp_all
Identity Mapping Preserves List: $\text{map}\ \text{id}\ l = l$
Informal description
For any list $l$ of elements of type $\alpha$, applying the identity function $\text{id}$ to each element of $l$ via the `map` operation returns $l$ itself, i.e., $\text{map}\ \text{id}\ l = l$.
List.map_id' theorem
(l : List α) : map (fun (a : α) => a) l = l
Full source
/-- `map_id'` differs from `map_id` by representing the identity function as a lambda, rather than `id`. -/
-- This is not a `@[simp]` lemma because `map_id_fun'` will apply.
-- The argument `l : List α` is explicit to allow rewriting from right to left.
theorem map_id' (l : List α) : map (fun (a : α) => a) l = l := map_id l
Identity Mapping Preserves List via Anonymous Function: $\text{map}\, (\lambda a. a)\, l = l$
Informal description
For any list $l$ of elements of type $\alpha$, applying the identity function $\lambda (a : \alpha) \mapsto a$ to each element of $l$ via the `map` operation returns $l$ itself, i.e., $\text{map}\, (\lambda a. a)\, l = l$.
List.map_id'' theorem
{f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l = l
Full source
/-- Variant of `map_id`, with a side condition that the function is pointwise the identity. -/
-- The argument `l : List α` is explicit to allow rewriting from right to left.
theorem map_id'' {f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l = l := by
  simp [show f = id from funext h]
Identity Mapping on Lists: $\text{map}\, f\, l = l$ when $f$ is pointwise identity
Informal description
For any function $f : \alpha \to \alpha$ satisfying $f(x) = x$ for all $x \in \alpha$, and for any list $l$ of elements of type $\alpha$, the mapped list $\text{map}\, f\, l$ is equal to $l$.
List.map_singleton theorem
{f : α → β} {a : α} : map f [a] = [f a]
Full source
theorem map_singleton {f : α → β} {a : α} : map f [a] = [f a] := rfl
Mapping a Function Over a Singleton List Yields Singleton of Function Application
Informal description
For any function $f : \alpha \to \beta$ and any element $a \in \alpha$, the map of $f$ applied to the singleton list $[a]$ equals the singleton list $[f(a)]$. In other words, $\text{map}\, f\, [a] = [f(a)]$.
List.mem_map theorem
{f : α → β} : ∀ {l : List α}, b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
Full source
@[simp 500] theorem mem_map {f : α → β} : ∀ {l : List α}, b ∈ l.map fb ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
  | [] => by simp
  | _ :: l => by simp [mem_map (l := l), eq_comm (a := b)]
Membership in Mapped List: $b \in \text{map}\, f\, l \leftrightarrow \exists a \in l, f(a) = b$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, an element $b \in \beta$ is in the mapped list $\text{map}\, f\, l$ if and only if there exists an element $a \in \alpha$ such that $a \in l$ and $f(a) = b$. In other words: $$ b \in \text{map}\, f\, l \leftrightarrow \exists a \in l, f(a) = b. $$
List.exists_of_mem_map theorem
(h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b
Full source
theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h
Existence of Preimage in Mapped List: $b \in \text{map}\, f\, l \implies \exists a \in l, f(a) = b$
Informal description
For any function $f : \alpha \to \beta$ and list $l$ of elements of type $\alpha$, if an element $b \in \beta$ belongs to the mapped list $\text{map}\, f\, l$, then there exists an element $a \in \alpha$ such that $a \in l$ and $f(a) = b$.
List.mem_map_of_mem theorem
{f : α → β} (h : a ∈ l) : f a ∈ map f l
Full source
theorem mem_map_of_mem {f : α → β} (h : a ∈ l) : f a ∈ map f l := mem_map.2 ⟨_, h, rfl⟩
Image of List Element under Mapping Belongs to Mapped List
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, if an element $a$ is in $l$, then $f(a)$ is in the mapped list $\text{map}\, f\, l$.
List.forall_mem_map theorem
{f : α → β} {l : List α} {P : β → Prop} : (∀ (i) (_ : i ∈ l.map f), P i) ↔ ∀ (j) (_ : j ∈ l), P (f j)
Full source
theorem forall_mem_map {f : α → β} {l : List α} {P : β → Prop} :
    (∀ (i) (_ : i ∈ l.map f), P i) ↔ ∀ (j) (_ : j ∈ l), P (f j) := by
  simp
Universal Quantification over Mapped List Elements
Informal description
For any function $f : \alpha \to \beta$, list $l : \text{List } \alpha$, and predicate $P : \beta \to \text{Prop}$, the following equivalence holds: \[ (\forall i \in \text{map } f \ l, P(i)) \leftrightarrow (\forall j \in l, P(f j)) \] This states that a predicate $P$ holds for all elements in the mapped list $\text{map } f \ l$ if and only if $P$ holds for the image under $f$ of all elements in the original list $l$.
List.map_eq_nil_iff theorem
{f : α → β} {l : List α} : map f l = [] ↔ l = []
Full source
@[simp] theorem map_eq_nil_iff {f : α → β} {l : List α} : mapmap f l = [] ↔ l = [] := by
  constructor <;> exact fun _ => match l with | [] => rfl
Mapped List is Empty if and only if Original List is Empty
Informal description
For any function $f : \alpha \to \beta$ and list $l : \text{List } \alpha$, the mapped list $\text{map } f \ l$ is empty if and only if $l$ is empty. In other words, $\text{map } f \ l = [] \leftrightarrow l = []$.
List.map_eq_nil abbrev
Full source
@[deprecated map_eq_nil_iff (since := "2024-09-05")] abbrev map_eq_nil := @map_eq_nil_iff
Mapped List is Empty if and only if Original List is Empty
Informal description
For any function $f : \alpha \to \beta$ and list $l : \text{List } \alpha$, the mapped list $\text{map } f \ l$ is empty if and only if $l$ is empty. In other words, $\text{map } f \ l = [] \leftrightarrow l = []$.
List.map_inj_left theorem
{f g : α → β} : map f l = map g l ↔ ∀ a ∈ l, f a = g a
Full source
@[simp] theorem map_inj_left {f g : α → β} : mapmap f l = map g l ↔ ∀ a ∈ l, f a = g a := by
  induction l <;> simp_all
Equality of Mapped Lists via Pointwise Function Equality
Informal description
For any functions $f, g : \alpha \to \beta$ and list $l : \text{List } \alpha$, the mapped lists $\text{map } f \ l$ and $\text{map } g \ l$ are equal if and only if for every element $a$ in $l$, $f(a) = g(a)$. That is, \[ \text{map } f \ l = \text{map } g \ l \leftrightarrow \forall a \in l, f(a) = g(a). \]
List.map_inj_right theorem
{f : α → β} (w : ∀ x y, f x = f y → x = y) : map f l = map f l' ↔ l = l'
Full source
theorem map_inj_right {f : α → β} (w : ∀ x y, f x = f y → x = y) : mapmap f l = map f l' ↔ l = l' := by
  induction l generalizing l' with
  | nil => simp
  | cons a l ih =>
    simp only [map_cons]
    cases l' with
    | nil => simp
    | cons a' l' =>
      simp only [map_cons, cons.injEq, ih, and_congr_left_iff]
      intro h
      constructor
      · apply w
      · simp +contextual
Injectivity of List Mapping under Injective Functions: $\text{map}\ f\ l = \text{map}\ f\ l' \leftrightarrow l = l'$
Informal description
Let $f : \alpha \to \beta$ be an injective function (i.e., for any $x, y \in \alpha$, if $f(x) = f(y)$ then $x = y$). Then for any lists $l, l'$ of elements in $\alpha$, the mapped lists $\text{map}\ f\ l$ and $\text{map}\ f\ l'$ are equal if and only if $l = l'$.
List.map_congr_left theorem
(h : ∀ a ∈ l, f a = g a) : map f l = map g l
Full source
theorem map_congr_left (h : ∀ a ∈ l, f a = g a) : map f l = map g l :=
  map_inj_left.2 h
Pointwise Function Equality Implies List Map Equality
Informal description
For any functions $f, g : \alpha \to \beta$ and list $l : \text{List } \alpha$, if $f(a) = g(a)$ for every element $a$ in $l$, then the mapped lists $\text{map } f \ l$ and $\text{map } g \ l$ are equal.
List.map_inj theorem
: map f = map g ↔ f = g
Full source
theorem map_inj : mapmap f = map g ↔ f = g := by
  constructor
  · intro h; ext a; replace h := congrFun h [a]; simpa using h
  · intro h; subst h; rfl
Injectivity of List Map: $\text{map}\, f = \text{map}\, g \leftrightarrow f = g$
Informal description
For any two functions $f, g : \alpha \to \beta$, the map operations on lists satisfy $\text{map}\, f = \text{map}\, g$ if and only if $f = g$.
List.map_eq_cons_iff theorem
{f : α → β} {l : List α} : map f l = b :: l₂ ↔ ∃ a l₁, l = a :: l₁ ∧ f a = b ∧ map f l₁ = l₂
Full source
theorem map_eq_cons_iff {f : α → β} {l : List α} :
    mapmap f l = b :: l₂ ↔ ∃ a l₁, l = a :: l₁ ∧ f a = b ∧ map f l₁ = l₂ := by
  cases l
  case nil => simp
  case cons a l₁ =>
    simp only [map_cons, cons.injEq]
    constructor
    · rintro ⟨rfl, rfl⟩
      exact ⟨a, l₁, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
    · rintro ⟨a, l₁, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
      constructor <;> rfl
Characterization of Mapped List as Cons: $\text{map } f\ l = b :: l_2 \leftrightarrow \exists a\ l_1, l = a :: l_1 \land f(a) = b \land \text{map } f\ l_1 = l_2$
Informal description
For any function $f : \alpha \to \beta$ and list $l$ of type $\text{List } \alpha$, the mapped list $\text{map } f\ l$ equals a cons list $b :: l_2$ if and only if there exists an element $a \in \alpha$ and a sublist $l_1$ such that $l = a :: l_1$, $f(a) = b$, and $\text{map } f\ l_1 = l_2$.
List.map_eq_cons abbrev
Full source
@[deprecated map_eq_cons_iff (since := "2024-09-05")] abbrev map_eq_cons := @map_eq_cons_iff
Mapped List Equals Cons Implies Existence of Preimage
Informal description
For any function $f : \alpha \to \beta$ and list $l$ of type $\text{List } \alpha$, if the mapped list $\text{map } f\ l$ equals a cons list $b :: l_2$, then there exists an element $a \in \alpha$ and a sublist $l_1$ such that $l = a :: l_1$, $f(a) = b$, and $\text{map } f\ l_1 = l_2$.
List.map_eq_cons_iff' theorem
{f : α → β} {l : List α} : map f l = b :: l₂ ↔ l.head?.map f = some b ∧ l.tail?.map (map f) = some l₂
Full source
theorem map_eq_cons_iff' {f : α → β} {l : List α} :
    mapmap f l = b :: l₂ ↔ l.head?.map f = some b ∧ l.tail?.map (map f) = some l₂ := by
  induction l <;> simp_all
Characterization of Mapped Lists as Cons Lists via Head and Tail Conditions
Informal description
For any function $f : \alpha \to \beta$ and list $l$ of type $\text{List } \alpha$, the mapped list $\text{map } f \ l$ equals the cons list $b :: l_2$ if and only if the following two conditions hold: 1. The result of applying $f$ to the head of $l$ (if it exists) is $\text{some } b$. 2. The result of mapping $f$ over the tail of $l$ (if it exists) is $\text{some } l_2$. In other words, $\text{map } f \ l = b :: l_2 \leftrightarrow (\text{head? } l).\text{map } f = \text{some } b \land (\text{tail? } l).\text{map } (\text{map } f) = \text{some } l_2$.
List.map_eq_cons' abbrev
Full source
@[deprecated map_eq_cons' (since := "2024-09-05")] abbrev map_eq_cons' := @map_eq_cons_iff'
Characterization of Mapped Lists as Cons Lists via Decomposition
Informal description
For any function $f : \alpha \to \beta$ and list $l$ of type $\text{List } \alpha$, the mapped list $\text{map } f \ l$ equals the cons list $b :: l_2$ if and only if there exists an element $a \in \alpha$ and a list $l'$ such that $l = a :: l'$, $f(a) = b$, and $\text{map } f \ l' = l_2$.
List.map_eq_singleton_iff theorem
{f : α → β} {l : List α} {b : β} : map f l = [b] ↔ ∃ a, l = [a] ∧ f a = b
Full source
@[simp] theorem map_eq_singleton_iff {f : α → β} {l : List α} {b : β} :
    mapmap f l = [b] ↔ ∃ a, l = [a] ∧ f a = b := by
  simp [map_eq_cons_iff]
Characterization of Singleton Mapped Lists: $\text{map } f \ l = [b] \leftrightarrow \exists a, l = [a] \land f(a) = b$
Informal description
For any function $f : \alpha \to \beta$, list $l$ of type $\text{List } \alpha$, and element $b$ of type $\beta$, the mapped list $\text{map } f \ l$ equals the singleton list $[b]$ if and only if there exists an element $a \in \alpha$ such that $l = [a]$ and $f(a) = b$.
List.map_eq_map_iff theorem
: map f l = map g l ↔ ∀ a ∈ l, f a = g a
Full source
theorem map_eq_map_iff : mapmap f l = map g l ↔ ∀ a ∈ l, f a = g a := by
  induction l <;> simp
Equality of Mapped Lists via Pointwise Function Equality
Informal description
For any functions $f, g : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the mapped lists $\text{map } f \ l$ and $\text{map } g \ l$ are equal if and only if for every element $a$ in $l$, $f(a) = g(a)$.
List.map_eq_iff theorem
: map f l = l' ↔ ∀ i : Nat, l'[i]? = l[i]?.map f
Full source
theorem map_eq_iff : mapmap f l = l' ↔ ∀ i : Nat, l'[i]? = l[i]?.map f := by
  constructor
  · rintro rfl i
    simp
  · intro h
    ext1 i
    simp_all
Characterization of List Mapping via Optional Indexing: $\text{map}\,f\,l = l' \leftrightarrow \forall i, l'[i]? = f(l[i]?)$
Informal description
For any function $f : \alpha \to \beta$ and any lists $l$ of type $\text{List}\,\alpha$ and $l'$ of type $\text{List}\,\beta$, the equality $\text{map}\,f\,l = l'$ holds if and only if for every natural number index $i$, the optional indexing operations satisfy $l'[i]? = \text{Option.map}\,f\,(l[i]?)$.
List.map_eq_foldr theorem
{f : α → β} {l : List α} : map f l = foldr (fun a bs => f a :: bs) [] l
Full source
theorem map_eq_foldr {f : α → β} {l : List α} : map f l = foldr (fun a bs => f a :: bs) [] l := by
  induction l <;> simp [*]
Map as Right Fold of Cons Operation
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the map of $f$ over $l$ is equal to the right fold of the function $\lambda a\ bs \mapsto f(a) :: bs$ over $l$ with initial value the empty list. In symbols: $$\text{map}\ f\ l = \text{foldr}\ (\lambda a\ bs \mapsto f(a) :: bs)\ []\ l$$
List.map_set theorem
{f : α → β} {l : List α} {i : Nat} {a : α} : (l.set i a).map f = (l.map f).set i (f a)
Full source
@[simp] theorem map_set {f : α → β} {l : List α} {i : Nat} {a : α} :
    (l.set i a).map f = (l.map f).set i (f a) := by
  induction l generalizing i with
  | nil => simp
  | cons b l ih => cases i <;> simp_all
Commutativity of Map and Set: $\text{map}\ f \circ \text{set}\ i\ a = \text{set}\ i\ (f\ a) \circ \text{map}\ f$
Informal description
For any function $f : \alpha \to \beta$, any list $l$ of elements of type $\alpha$, any natural number index $i$, and any element $a \in \alpha$, the following equality holds: $$(l.\text{set}\ i\ a).\text{map}\ f = (l.\text{map}\ f).\text{set}\ i\ (f\ a)$$ where $\text{set}$ modifies the $i$-th element of a list (leaving it unchanged if $i$ is out of bounds), and $\text{map}$ applies $f$ to each element of the list.
List.set_map theorem
{f : α → β} {l : List α} {i : Nat} {a : α} : (map f l).set i (f a) = map f (l.set i a)
Full source
@[deprecated "Use the reverse direction of `map_set`." (since := "2024-09-20")]
theorem set_map {f : α → β} {l : List α} {i : Nat} {a : α} :
    (map f l).set i (f a) = map f (l.set i a) := by
  simp
Commutativity of Map and Set: $\text{map}\ f \circ \text{set}\ i\ a = \text{set}\ i\ (f\ a) \circ \text{map}\ f$
Informal description
For any function $f : \alpha \to \beta$, any list $l$ of elements of type $\alpha$, any natural number index $i$, and any element $a \in \alpha$, the following equality holds: $$(l.\text{map}\ f).\text{set}\ i\ (f\ a) = (l.\text{set}\ i\ a).\text{map}\ f$$ where $\text{set}$ modifies the $i$-th element of a list (leaving it unchanged if $i$ is out of bounds), and $\text{map}$ applies $f$ to each element of the list.
List.head_map theorem
{f : α → β} {l : List α} (w) : (map f l).head w = f (l.head (by simpa using w))
Full source
@[simp] theorem head_map {f : α → β} {l : List α} (w) :
    (map f l).head w = f (l.head (by simpa using w)) := by
  cases l
  · simp at w
  · simp_all
Mapping Preserves Head: $(\text{map } f\ l).\text{head} = f(l.\text{head})$
Informal description
For any function $f : \alpha \to \beta$ and any non-empty list $l$ of elements of type $\alpha$, the head of the mapped list $\text{map } f\ l$ is equal to $f$ applied to the head of $l$. Here, $w$ is a proof that $\text{map } f\ l$ is non-empty (which implies $l$ is non-empty).
List.head?_map theorem
{f : α → β} {l : List α} : (map f l).head? = l.head?.map f
Full source
@[simp] theorem head?_map {f : α → β} {l : List α} : (map f l).head? = l.head?.map f := by
  cases l <;> rfl
Mapping Preserves Optional Head: $(\text{map } f\ l).\text{head?} = f <$> l.\text{head?}$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the optional head of the mapped list $\text{map } f\ l$ is equal to the result of mapping $f$ over the optional head of $l$. In other words, $(\text{map } f\ l).\text{head?} = \text{Option.map } f\ (l.\text{head?})$.
List.map_tail? theorem
{f : α → β} {l : List α} : (tail? l).map (map f) = tail? (map f l)
Full source
@[simp] theorem map_tail? {f : α → β} {l : List α} : (tail? l).map (map f) = tail? (map f l) := by
  cases l <;> rfl
Mapping Preserves Optional Tail: $\text{tail?}(\text{map } f\ l) = \text{map } f\ (\text{tail? } l)$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the optional tail of the mapped list $\text{map } f\ l$ is equal to the result of mapping $f$ over the optional tail of $l$. In other words, $\text{tail?}(\text{map } f\ l) = \text{Option.map } (\text{map } f) (\text{tail? } l)$.
List.map_tail theorem
{f : α → β} {l : List α} : map f l.tail = (map f l).tail
Full source
@[simp] theorem map_tail {f : α → β} {l : List α} :
    map f l.tail = (map f l).tail := by
  cases l <;> simp_all
Mapping Preserves Tail: $\text{map } f\ (\text{tail } l) = \text{tail } (\text{map } f\ l)$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the result of applying $f$ to the tail of $l$ is equal to the tail of the list obtained by applying $f$ to each element of $l$. In other words, $\text{map } f\ (\text{tail } l) = \text{tail } (\text{map } f\ l)$.
List.headD_map theorem
{f : α → β} {l : List α} {a : α} : (map f l).headD (f a) = f (l.headD a)
Full source
theorem headD_map {f : α → β} {l : List α} {a : α} : (map f l).headD (f a) = f (l.headD a) := by
  cases l <;> rfl
Mapping Preserves Default Head: $(\text{map } f\ l).\text{headD}(f a) = f(l.\text{headD} a)$
Informal description
For any function $f : \alpha \to \beta$, any list $l$ of elements of type $\alpha$, and any default value $a \in \alpha$, the default head of the mapped list $\text{map } f\ l$ with default value $f(a)$ is equal to $f$ applied to the default head of $l$ with default value $a$. In other words, $(\text{map } f\ l).\text{headD}(f a) = f(l.\text{headD} a)$.
List.tailD_map theorem
{f : α → β} {l l' : List α} : tailD (map f l) (map f l') = map f (tailD l l')
Full source
theorem tailD_map {f : α → β} {l l' : List α} :
    tailD (map f l) (map f l') = map f (tailD l l') := by simp [← map_tail?]
Mapping Preserves Default Tail: $\text{tailD}(\text{map } f\ l, \text{map } f\ l') = \text{map } f\ (\text{tailD}(l, l'))$
Informal description
For any function $f : \alpha \to \beta$ and any lists $l, l'$ of elements of type $\alpha$, the default tail of the mapped list $\text{map } f\ l$ with default value $\text{map } f\ l'$ is equal to the map of $f$ applied to the default tail of $l$ with default value $l'$. In other words: $$\text{tailD}(\text{map } f\ l, \text{map } f\ l') = \text{map } f\ (\text{tailD}(l, l'))$$
List.getLast_map theorem
{f : α → β} {l : List α} (h) : getLast (map f l) h = f (getLast l (by simpa using h))
Full source
@[simp] theorem getLast_map {f : α → β} {l : List α} (h) :
    getLast (map f l) h = f (getLast l (by simpa using h)) := by
  cases l
  · simp at h
  · simp only [← getElem_cons_length rfl]
    simp only [map_cons]
    simp only [← getElem_cons_length rfl]
    simp only [← map_cons, getElem_map]
    simp
Mapping Preserves Last Element: $\text{getLast}\,(\text{map}\,f\,l) = f\,(\text{getLast}\,l)$
Informal description
For any function $f : \alpha \to \beta$ and any non-empty list $l$ of type $\text{List}\,\alpha$, the last element of the mapped list $\text{map}\,f\,l$ is equal to $f$ applied to the last element of $l$. That is, $\text{getLast}\,(\text{map}\,f\,l) = f\,(\text{getLast}\,l)$.
List.getLast?_map theorem
{f : α → β} {l : List α} : (map f l).getLast? = l.getLast?.map f
Full source
@[simp] theorem getLast?_map {f : α → β} {l : List α} : (map f l).getLast? = l.getLast?.map f := by
  cases l
  · simp
  · rw [getLast?_eq_getLast, getLast?_eq_getLast, getLast_map] <;> simp
Mapping Preserves Optional Last Element: $(\text{map}\,f\,l).\text{getLast?} = l.\text{getLast?}.\text{map}\,f$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the optional last element of the mapped list $\text{map}\,f\,l$ is equal to the result of applying $f$ to the optional last element of $l$. That is, $(\text{map}\,f\,l).\text{getLast?} = l.\text{getLast?}.\text{map}\,f$.
List.getLastD_map theorem
{f : α → β} {l : List α} {a : α} : (map f l).getLastD (f a) = f (l.getLastD a)
Full source
theorem getLastD_map {f : α → β} {l : List α} {a : α} : (map f l).getLastD (f a) = f (l.getLastD a) := by
  simp
Mapping Commutes with Default Last Element: $(\text{map}\,f\,l).\text{getLastD}\,(f\,a) = f\,(l.\text{getLastD}\,a)$
Informal description
For any function $f : \alpha \to \beta$, any list $l$ of elements of type $\alpha$, and any default value $a \in \alpha$, the default last element of the mapped list $\text{map}\,f\,l$ with default value $f(a)$ is equal to $f$ applied to the default last element of $l$ with default value $a$. That is, $$(\text{map}\,f\,l).\text{getLastD}\,(f\,a) = f\,(l.\text{getLastD}\,a).$$
List.map_map theorem
{g : β → γ} {f : α → β} {l : List α} : map g (map f l) = map (g ∘ f) l
Full source
@[simp] theorem map_map {g : β → γ} {f : α → β} {l : List α} :
    map g (map f l) = map (g ∘ f) l := by induction l <;> simp_all
Composition of List Maps Equals Map of Compositions
Informal description
For any functions $f : \alpha \to \beta$ and $g : \beta \to \gamma$, and any list $l$ of elements of type $\alpha$, applying $g$ to each element of the list obtained by applying $f$ to each element of $l$ is equivalent to applying the composition $g \circ f$ to each element of $l$ directly. That is, $\text{map}\ g\ (\text{map}\ f\ l) = \text{map}\ (g \circ f)\ l$.
List.filter_cons_of_pos theorem
{p : α → Bool} {a : α} {l} (pa : p a) : filter p (a :: l) = a :: filter p l
Full source
@[simp] theorem filter_cons_of_pos {p : α → Bool} {a : α} {l} (pa : p a) :
    filter p (a :: l) = a :: filter p l := by rw [filter, pa]
Filtering Preserves Head Element When Predicate Holds
Informal description
For any predicate $p : \alpha \to \text{Bool}$, element $a \in \alpha$, and list $l$ of elements of type $\alpha$, if $p(a)$ evaluates to $\text{true}$, then filtering the list $a :: l$ with $p$ yields $a$ followed by the result of filtering $l$ with $p$. That is, $\text{filter}\ p\ (a :: l) = a :: \text{filter}\ p\ l$.
List.filter_cons_of_neg theorem
{p : α → Bool} {a : α} {l} (pa : ¬p a) : filter p (a :: l) = filter p l
Full source
@[simp] theorem filter_cons_of_neg {p : α → Bool} {a : α} {l} (pa : ¬ p a) :
    filter p (a :: l) = filter p l := by rw [filter, eq_false_of_ne_true pa]
Filtering a Cons List with False Predicate on Head
Informal description
For any predicate `p : α → Bool`, element `a : α`, and list `l : List α`, if `p a` evaluates to `false`, then filtering the list `a :: l` with predicate `p` is equal to filtering the list `l` with predicate `p`. That is, $\text{filter}\ p\ (a :: l) = \text{filter}\ p\ l$ when $\neg (p\ a)$ holds.
List.filter_cons theorem
: (x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p
Full source
theorem filter_cons :
    (x :: xs : List α).filter p = if p x then x :: (xs.filter p) else xs.filter p := by
  split <;> simp [*]
Filtering a Cons List: $\text{filter}\ p\ (x :: xs) = \text{if}\ p\ x\ \text{then}\ x :: \text{filter}\ p\ xs\ \text{else}\ \text{filter}\ p\ xs$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $x :: xs$ of elements of type $\alpha$, filtering the list with $p$ is equal to: - $x :: \text{filter}\ p\ xs$ if $p(x)$ evaluates to $\text{true}$, - $\text{filter}\ p\ xs$ otherwise.
List.length_filter_le theorem
(p : α → Bool) (l : List α) : (l.filter p).length ≤ l.length
Full source
theorem length_filter_le (p : α → Bool) (l : List α) :
    (l.filter p).length ≤ l.length := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [filter_cons, length_cons, succ_eq_add_one]
    split
    · simp only [length_cons, succ_eq_add_one]
      exact Nat.succ_le_succ ih
    · exact Nat.le_trans ih (Nat.le_add_right _ _)
Filtered List Length Bound: $|\text{filter}\ p\ l| \leq |l|$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l$ of elements of type $\alpha$, the length of the filtered list $\text{filter}\ p\ l$ is less than or equal to the length of $l$. That is, $|\text{filter}\ p\ l| \leq |l|$.
List.filter_eq_self theorem
{l} : filter p l = l ↔ ∀ a ∈ l, p a
Full source
@[simp]
theorem filter_eq_self {l} : filterfilter p l = l ↔ ∀ a ∈ l, p a := by
  induction l with simp
  | cons a l ih =>
    cases h : p a <;> simp [*]
    intro h; exact Nat.lt_irrefl _ (h ▸ length_filter_le p l)
Filtered List Equals Original List if and only if All Elements Satisfy Predicate
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l$ of elements of type $\alpha$, the filtered list $\text{filter}\ p\ l$ is equal to $l$ if and only if every element $a$ in $l$ satisfies $p(a)$. That is, $\text{filter}\ p\ l = l \leftrightarrow \forall a \in l, p(a)$.
List.length_filter_eq_length_iff theorem
{l} : (filter p l).length = l.length ↔ ∀ a ∈ l, p a
Full source
@[simp]
theorem length_filter_eq_length_iff {l} : (filter p l).length = l.length ↔ ∀ a ∈ l, p a := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [filter_cons, length_cons, succ_eq_add_one, mem_cons, forall_eq_or_imp]
    split <;> rename_i h
    · simp_all [Nat.add_one_inj] -- Why does the simproc not fire here?
    · have := Nat.ne_of_lt (Nat.lt_succ.mpr (length_filter_le p l))
      simp_all
Filtered List Length Equals Original Length if and only if All Elements Satisfy Predicate
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l$ of elements of type $\alpha$, the length of the filtered list $\text{filter}\ p\ l$ is equal to the length of $l$ if and only if every element $a$ in $l$ satisfies $p(a)$. That is: $$|\text{filter}\ p\ l| = |l| \leftrightarrow \forall a \in l, p(a)$$
List.filter_length_eq_length abbrev
Full source
@[deprecated length_filter_eq_length_iff (since := "2024-09-05")]
abbrev filter_length_eq_length := @length_filter_eq_length_iff
Filtered List Length Equals Original Length if and only if All Elements Satisfy Predicate
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l$ of elements of type $\alpha$, the length of the filtered list $\text{filter}\ p\ l$ is equal to the length of $l$ if and only if every element $a$ in $l$ satisfies $p(a)$. That is: $$|\text{filter}\ p\ l| = |l| \leftrightarrow \forall a \in l, p(a)$$
List.mem_filter theorem
: x ∈ filter p as ↔ x ∈ as ∧ p x
Full source
@[simp] theorem mem_filter : x ∈ filter p asx ∈ filter p as ↔ x ∈ as ∧ p x := by
  induction as with
  | nil => simp [filter]
  | cons a as ih =>
    by_cases h : p a
    · simp_all [or_and_left]
    · simp_all [or_and_right]
Membership in Filtered List: $x \in \mathrm{filter}\, p\, as \leftrightarrow x \in as \land p(x)$
Informal description
For any element $x$, predicate $p$, and list $as$, the element $x$ belongs to the filtered list $\mathrm{filter}\, p\, as$ if and only if $x$ belongs to $as$ and the predicate $p(x)$ holds. That is: $$x \in \mathrm{filter}\, p\, as \leftrightarrow x \in as \land p(x)$$
List.filter_eq_nil_iff theorem
{l} : filter p l = [] ↔ ∀ a, a ∈ l → ¬p a
Full source
@[simp] theorem filter_eq_nil_iff {l} : filterfilter p l = [] ↔ ∀ a, a ∈ l → ¬p a := by
  simp only [eq_nil_iff_forall_not_mem, mem_filter, not_and]
Empty Filter Condition: $\mathrm{filter}\, p\, l = [] \leftrightarrow \forall a \in l,\, \neg p(a)$
Informal description
For any list $l$ and predicate $p$, the filtered list $\mathrm{filter}\, p\, l$ is empty if and only if for every element $a$ in $l$, the predicate $p(a)$ does not hold. In other words: $$\mathrm{filter}\, p\, l = [] \leftrightarrow \forall a \in l,\, \neg p(a)$$
List.filter_eq_nil abbrev
Full source
@[deprecated filter_eq_nil_iff (since := "2024-09-05")] abbrev filter_eq_nil := @filter_eq_nil_iff
Empty Filter Condition: $\mathrm{filter}\, p\, l = [] \leftrightarrow \forall a \in l,\, \neg p(a)$
Informal description
For any list $l$ and predicate $p$, the filtered list $\mathrm{filter}\, p\, l$ is empty if and only if for every element $a$ in $l$, the predicate $p(a)$ does not hold. In other words: $$\mathrm{filter}\, p\, l = [] \leftrightarrow \forall a \in l,\, \neg p(a)$$
List.forall_mem_filter theorem
{l : List α} {p : α → Bool} {P : α → Prop} : (∀ (i) (_ : i ∈ l.filter p), P i) ↔ ∀ (j) (_ : j ∈ l), p j → P j
Full source
theorem forall_mem_filter {l : List α} {p : α → Bool} {P : α → Prop} :
    (∀ (i) (_ : i ∈ l.filter p), P i) ↔ ∀ (j) (_ : j ∈ l), p j → P j := by
  simp
Universal Property of Filtered Lists: $\forall i \in \text{filter}\, p\, l,\, P(i) \leftrightarrow \forall j \in l,\, p(j) \to P(j)$
Informal description
For any list $l$, predicate $p : \alpha \to \text{Bool}$, and property $P : \alpha \to \text{Prop}$, the following are equivalent: 1. For every element $i$ in the filtered list $\text{filter}\, p\, l$, the property $P(i)$ holds. 2. For every element $j$ in the original list $l$, if $p(j)$ is true, then $P(j)$ holds. In symbols: $$(\forall i \in \text{filter}\, p\, l,\, P(i)) \leftrightarrow (\forall j \in l,\, p(j) \to P(j))$$
List.filter_filter theorem
: ∀ {l}, filter p (filter q l) = filter (fun a => p a && q a) l
Full source
@[simp] theorem filter_filter : ∀ {l}, filter p (filter q l) = filter (fun a => p a && q a) l
  | [] => rfl
  | a :: l => by by_cases hp : p a <;> by_cases hq : q a <;> simp [hp, hq, filter_filter]
Composition of Filters via Conjunction: $\text{filter}\, p \circ \text{filter}\, q = \text{filter}\, (p \land q)$
Informal description
For any list $l$ and predicates $p, q : \alpha \to \text{Bool}$, filtering $l$ with $p$ and then filtering the result with $q$ is equivalent to filtering $l$ with the conjunction of $p$ and $q$. That is, $$\text{filter}\, p\, (\text{filter}\, q\, l) = \text{filter}\, (\lambda a,\, p(a) \land q(a))\, l.$$
List.foldl_filter theorem
{p : α → Bool} {f : β → α → β} {l : List α} {init : β} : (l.filter p).foldl f init = l.foldl (fun x y => if p y then f x y else x) init
Full source
theorem foldl_filter {p : α → Bool} {f : β → α → β} {l : List α} {init : β} :
    (l.filter p).foldl f init = l.foldl (fun x y => if p y then f x y else x) init := by
  induction l generalizing init with
  | nil => rfl
  | cons a l ih =>
    simp only [filter_cons, foldl_cons]
    split <;> simp [ih]
Left Fold over Filtered List Equals Conditional Fold over Original List
Informal description
For any predicate $p : \alpha \to \text{Bool}$, function $f : \beta \to \alpha \to \beta$, list $l$ of elements of type $\alpha$, and initial value $\text{init} : \beta$, the left fold of $f$ over the filtered list $\text{filter}\, p\, l$ with initial value $\text{init}$ is equal to the left fold of the function $\lambda x\, y,\, \text{if}\, p(y)\, \text{then}\, f\, x\, y\, \text{else}\, x$ over the original list $l$ with the same initial value $\text{init}$. In symbols: \[ \text{foldl}\, f\, \text{init}\, (\text{filter}\, p\, l) = \text{foldl}\, (\lambda x\, y,\, \text{if}\, p(y)\, \text{then}\, f\, x\, y\, \text{else}\, x)\, \text{init}\, l \]
List.foldr_filter theorem
{p : α → Bool} {f : α → β → β} {l : List α} {init : β} : (l.filter p).foldr f init = l.foldr (fun x y => if p x then f x y else y) init
Full source
theorem foldr_filter {p : α → Bool} {f : α → β → β} {l : List α} {init : β} :
    (l.filter p).foldr f init = l.foldr (fun x y => if p x then f x y else y) init := by
  induction l generalizing init with
  | nil => rfl
  | cons a l ih =>
    simp only [filter_cons, foldr_cons]
    split <;> simp [ih]
Right Fold of Filtered List Equals Conditional Right Fold
Informal description
For any predicate $p : \alpha \to \text{Bool}$, function $f : \alpha \to \beta \to \beta$, list $l$ of elements of type $\alpha$, and initial value $\text{init} : \beta$, the right fold of the filtered list $\text{filter}\ p\ l$ with $f$ and $\text{init}$ is equal to the right fold of the original list $l$ with the function $\lambda x\ y,\ \text{if}\ p(x)\ \text{then}\ f\ x\ y\ \text{else}\ y$ and the same initial value $\text{init}$. In symbols: $$ \text{foldr}\ f\ \text{init}\ (\text{filter}\ p\ l) = \text{foldr}\ (\lambda x\ y,\ \text{if}\ p(x)\ \text{then}\ f\ x\ y\ \text{else}\ y)\ \text{init}\ l $$
List.filter_map theorem
{f : β → α} {p : α → Bool} {l : List β} : filter p (map f l) = map f (filter (p ∘ f) l)
Full source
theorem filter_map {f : β → α} {p : α → Bool} {l : List β} :
    filter p (map f l) = map f (filter (p ∘ f) l) := by
  induction l with
  | nil => rfl
  | cons a l IH => by_cases h : p (f a) <;> simp [*]
Filter-Map Commutation: $\text{filter}\ p \circ \text{map}\ f = \text{map}\ f \circ \text{filter}\ (p \circ f)$
Informal description
For any function $f \colon \beta \to \alpha$, predicate $p \colon \alpha \to \text{Bool}$, and list $l$ of elements of type $\beta$, filtering the mapped list $\text{map}\ f\ l$ with $p$ is equivalent to mapping $f$ over the list obtained by filtering $l$ with the composition $p \circ f$. In symbols: \[ \text{filter}\ p\ (\text{map}\ f\ l) = \text{map}\ f\ (\text{filter}\ (p \circ f)\ l) \]
List.map_filter_eq_foldr theorem
{f : α → β} {p : α → Bool} {as : List α} : map f (filter p as) = foldr (fun a bs => bif p a then f a :: bs else bs) [] as
Full source
theorem map_filter_eq_foldr {f : α → β} {p : α → Bool} {as : List α} :
    map f (filter p as) = foldr (fun a bs => bif p a then f a :: bs else bs) [] as := by
  induction as with
  | nil => rfl
  | cons head _ ih =>
    simp only [foldr]
    cases hp : p head <;> simp [filter, *]
Map-Filter Equals Conditional Fold
Informal description
For any function $f \colon \alpha \to \beta$, predicate $p \colon \alpha \to \text{Bool}$, and list $as$ of elements of type $\alpha$, the result of mapping $f$ over the elements of $as$ that satisfy $p$ is equal to folding the list $as$ with the operation that appends $f(a)$ to the accumulator if $p(a)$ holds, and leaves the accumulator unchanged otherwise, starting from the empty list. In symbols: \[ \text{map } f (\text{filter } p \ as) = \text{foldr } (\lambda a \ bs, \text{if } p(a) \text{ then } f(a) :: bs \text{ else } bs) \ [] \ as \]
List.filter_append theorem
{p : α → Bool} : ∀ (l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
Full source
@[simp] theorem filter_append {p : α → Bool} :
    ∀ (l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
  | [], _ => rfl
  | a :: l₁, l₂ => by simp only [cons_append, filter]; split <;> simp [filter_append l₁]
Filter Distributes Over List Concatenation
Informal description
For any predicate $p \colon \alpha \to \text{Bool}$ and any two lists $l_1, l_2$ of elements of type $\alpha$, the result of filtering the concatenation $l_1 ++ l_2$ with $p$ is equal to the concatenation of the filtered lists $(\text{filter } p \ l_1) ++ (\text{filter } p \ l_2)$. In symbols: \[ \text{filter } p (l_1 ++ l_2) = \text{filter } p \ l_1 ++ \text{filter } p \ l_2 \]
List.filter_eq_cons_iff theorem
{l} {a} {as} : filter p l = a :: as ↔ ∃ l₁ l₂, l = l₁ ++ a :: l₂ ∧ (∀ x, x ∈ l₁ → ¬p x) ∧ p a ∧ filter p l₂ = as
Full source
theorem filter_eq_cons_iff {l} {a} {as} :
    filterfilter p l = a :: as ↔
      ∃ l₁ l₂, l = l₁ ++ a :: l₂ ∧ (∀ x, x ∈ l₁ → ¬p x) ∧ p a ∧ filter p l₂ = as := by
  constructor
  · induction l with
    | nil => simp
    | cons x l ih =>
      intro h
      simp only [filter_cons] at h
      split at h <;> rename_i w
      · simp only [cons.injEq] at h
        obtain ⟨rfl, rfl⟩ := h
        refine ⟨[], l, ?_⟩
        simp [w]
      · specialize ih h
        obtain ⟨l₁, l₂, rfl, w₁, w₂, w₃⟩ := ih
        refine ⟨x :: l₁, l₂, ?_⟩
        simp_all
  · rintro ⟨l₁, l₂, rfl, h₁, h, h₂⟩
    simp [h₂, filter_cons, filter_eq_nil_iff.mpr h₁, h]
Characterization of Filtered List as Cons: $\mathrm{filter}\, p\, l = a :: as$
Informal description
For any list $l$, element $a$, and list $as$, the filtered list $\mathrm{filter}\, p\, l$ equals $a :: as$ if and only if there exist sublists $l_1$ and $l_2$ such that: 1. $l = l_1 ++ (a :: l_2)$, 2. For all $x \in l_1$, $\neg p(x)$, 3. $p(a)$ holds, and 4. $\mathrm{filter}\, p\, l_2 = as$. In symbols: \[ \mathrm{filter}\, p\, l = a :: as \leftrightarrow \exists l_1\, l_2,\ l = l_1 ++ (a :: l_2) \land (\forall x \in l_1,\, \neg p(x)) \land p(a) \land \mathrm{filter}\, p\, l_2 = as \]
List.filter_eq_cons abbrev
Full source
@[deprecated filter_eq_cons_iff (since := "2024-09-05")] abbrev filter_eq_cons := @filter_eq_cons_iff
Characterization of when a filtered list equals a cons cell
Informal description
For any predicate $p : \alpha \to \text{Bool}$, list $l : \text{List } \alpha$, element $a : \alpha$, and list $as : \text{List } \alpha$, the filtered list $\text{filter } p l$ equals $a :: as$ if and only if there exist sublists $l_1, l_2 : \text{List } \alpha$ such that: 1. $l = l_1 ++ (a :: l_2)$, 2. For all $x \in l_1$, $\neg p(x)$, 3. $p(a)$ holds, and 4. $\text{filter } p l_2 = as$. In symbols: \[ \text{filter } p l = a :: as \leftrightarrow \exists l_1 l_2,\ l = l_1 ++ (a :: l_2) \land (\forall x \in l_1,\, \neg p(x)) \land p(a) \land \text{filter } p l_2 = as \]
List.filter_congr theorem
{p q : α → Bool} : ∀ {l : List α}, (∀ x ∈ l, p x = q x) → filter p l = filter q l
Full source
theorem filter_congr {p q : α → Bool} :
    ∀ {l : List α}, (∀ x ∈ l, p x = q x) → filter p l = filter q l
  | [], _ => rfl
  | a :: l, h => by
    rw [forall_mem_cons] at h; by_cases pa : p a
    · simp [pa, h.1 ▸ pa, filter_congr h.2]
    · simp [pa, h.1 ▸ pa, filter_congr h.2]
Filter Congruence: $\forall x \in l, p(x) = q(x) \Rightarrow \text{filter } p l = \text{filter } q l$
Informal description
For any predicates $p, q : \alpha \to \text{Bool}$ and any list $l$ of elements in $\alpha$, if $p(x) = q(x)$ for all $x \in l$, then the filtered lists $\text{filter } p l$ and $\text{filter } q l$ are equal.
List.head_filter_of_pos theorem
{p : α → Bool} {l : List α} (w : l ≠ []) (h : p (l.head w)) : (filter p l).head ((ne_nil_of_mem (mem_filter.2 ⟨head_mem w, h⟩))) = l.head w
Full source
theorem head_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p (l.head w)) :
    (filter p l).head ((ne_nil_of_mem (mem_filter.2 ⟨head_mem w, h⟩))) = l.head w := by
  cases l with
  | nil => simp
  | cons =>
    simp only [head_cons] at h
    simp [filter_cons, h]
Head Preservation Under Filtering When Predicate Holds
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and non-empty list $l$ of type $\alpha$, if $p$ holds for the head element of $l$, then the head element of the filtered list $\text{filter } p l$ equals the head element of $l$. That is: $$(\text{filter } p l).\text{head} = l.\text{head}$$ where the non-emptiness conditions are satisfied as follows: 1. $l \neq []$ (given by $w$) 2. $\text{filter } p l \neq []$ (since $l.\text{head} \in l$ by $\text{head\_mem}$ and $p(l.\text{head})$ holds by $h$, implying $l.\text{head} \in \text{filter } p l$ by $\text{mem\_filter}$)
List.filter_sublist theorem
{p : α → Bool} : ∀ {l : List α}, filter p l <+ l
Full source
@[simp] theorem filter_sublist {p : α → Bool} : ∀ {l : List α}, filterfilter p l <+ l
  | [] => .slnil
  | a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons₂, filter_sublist]
Filtered List is Sublist of Original List
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any list $l$ of elements in $\alpha$, the filtered list $\text{filter } p l$ is a sublist of $l$.
List.filterMap_cons_none theorem
{f : α → Option β} {a : α} {l : List α} (h : f a = none) : filterMap f (a :: l) = filterMap f l
Full source
@[simp] theorem filterMap_cons_none {f : α → Option β} {a : α} {l : List α} (h : f a = none) :
    filterMap f (a :: l) = filterMap f l := by simp only [filterMap, h]
Filter-Map of Cons with None Result: $\text{filterMap } f (a :: l) = \text{filterMap } f l$ when $f(a) = \text{none}$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, element $a \in \alpha$, and list $l$ of elements in $\alpha$, if $f(a) = \text{none}$, then the result of applying `filterMap` to $f$ and the list $a :: l$ is equal to the result of applying `filterMap` to $f$ and $l$.
List.filterMap_cons_some theorem
{f : α → Option β} {a : α} {l : List α} {b : β} (h : f a = some b) : filterMap f (a :: l) = b :: filterMap f l
Full source
@[simp] theorem filterMap_cons_some {f : α → Option β} {a : α} {l : List α} {b : β} (h : f a = some b) :
    filterMap f (a :: l) = b :: filterMap f l := by simp only [filterMap, h]
Filter-Map of Cons with Some Result: $\text{filterMap } f (a :: l) = b :: \text{filterMap } f l$ when $f(a) = \text{some } b$
Informal description
For any function $f : \alpha \to \text{Option } \beta$, element $a \in \alpha$, list $l$ of elements in $\alpha$, and element $b \in \beta$, if $f(a) = \text{some } b$, then the result of applying `filterMap` to $f$ and the list $a :: l$ is equal to $b$ prepended to the result of applying `filterMap` to $f$ and $l$.
List.filterMap_eq_map theorem
{f : α → β} : filterMap (some ∘ f) = map f
Full source
@[simp]
theorem filterMap_eq_map {f : α → β} : filterMap (somesome ∘ f) = map f := by
  funext l; induction l <;> simp [*, filterMap_cons]
Equivalence of Filter-Map and Map via Some Composition: $\text{filterMap} (\text{some} \circ f) = \text{map} f$
Informal description
For any function $f : \alpha \to \beta$, the operation `filterMap` applied to the composition of `some` with $f$ is equal to the `map` operation applied to $f$. In other words, $\text{filterMap} (\text{some} \circ f) = \text{map} f$.
List.filterMap_eq_map' theorem
{f : α → β} : filterMap (fun x => some (f x)) = map f
Full source
/-- Variant of `filterMap_eq_map` with `some ∘ f` expanded out to a lambda. -/
@[simp]
theorem filterMap_eq_map' {f : α → β} : filterMap (fun x => some (f x)) = map f :=
  filterMap_eq_map
Equivalence of Filter-Map and Map via Explicit Some Construction: $\text{filterMap} (\lambda x, \text{some}(f(x))) = \text{map} f$
Informal description
For any function $f : \alpha \to \beta$, the operation `filterMap` applied to the function $\lambda x, \text{some}(f(x))$ is equal to the `map` operation applied to $f$. In other words, $\text{filterMap} (\lambda x, \text{some}(f(x))) = \text{map} f$.
List.filterMap_some_fun theorem
: filterMap (some : α → Option α) = id
Full source
@[simp] theorem filterMap_some_fun : filterMap (some : α → Option α) = id := by
  funext l
  erw [filterMap_eq_map]
  simp
Identity Property of Filter-Map with Some Constructor: $\text{filterMap}\ \text{some} = \text{id}$
Informal description
The `filterMap` operation applied to the `some` constructor (viewed as a function from $\alpha$ to $\text{Option}\ \alpha$) is equal to the identity function on lists. That is, $\text{filterMap}\ \text{some} = \text{id}$.
List.filterMap_some theorem
{l : List α} : filterMap some l = l
Full source
theorem filterMap_some {l : List α} : filterMap some l = l := by
  rw [filterMap_some_fun, id]
Identity Property of Filter-Map with Some Constructor on Lists: $\text{filterMap}\ \text{some}\ l = l$
Informal description
For any list $l$ of elements of type $\alpha$, applying the `filterMap` operation with the `some` constructor (viewed as a function from $\alpha$ to $\text{Option}\ \alpha$) returns the original list $l$, i.e., $\text{filterMap}\ \text{some}\ l = l$.
List.map_filterMap_some_eq_filter_map_isSome theorem
{f : α → Option β} {l : List α} : (l.filterMap f).map some = (l.map f).filter fun b => b.isSome
Full source
theorem map_filterMap_some_eq_filter_map_isSome {f : α → Option β} {l : List α} :
    (l.filterMap f).map some = (l.map f).filter fun b => b.isSome := by
  induction l <;> simp [filterMap_cons]; split <;> simp [*]
Equivalence of map-filterMap and filter-map for optional values: $(\text{filterMap}\ f\ l).\text{map some} = (l.\text{map}\ f).\text{filter isSome}$
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and list $l$ of elements of type $\alpha$, mapping the `some` constructor over the result of `filterMap f l` is equal to filtering the list obtained by mapping $f$ over $l$ to retain only those elements that are `some` values. In mathematical notation: $$(\text{filterMap}\ f\ l).\text{map some} = (l.\text{map}\ f).\text{filter}\ (\lambda b \Rightarrow b.\text{isSome})$$
List.length_filterMap_le theorem
(f : α → Option β) (l : List α) : (filterMap f l).length ≤ l.length
Full source
theorem length_filterMap_le (f : α → Option β) (l : List α) :
    (filterMap f l).length ≤ l.length := by
  rw [← length_map some, map_filterMap_some_eq_filter_map_isSome, ← length_map f]
  apply length_filter_le
Length Bound for Filter-Mapped Lists: $|\text{filterMap}\ f\ l| \leq |l|$
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any list $l$ of elements of type $\alpha$, the length of the list obtained by applying $\text{filterMap}\ f$ to $l$ is less than or equal to the length of $l$, i.e., $|\text{filterMap}\ f\ l| \leq |l|$.
List.filterMap_length_eq_length theorem
{l} : (filterMap f l).length = l.length ↔ ∀ a ∈ l, (f a).isSome
Full source
@[simp]
theorem filterMap_length_eq_length {l} :
    (filterMap f l).length = l.length ↔ ∀ a ∈ l, (f a).isSome := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [filterMap_cons, length_cons, succ_eq_add_one, mem_cons, forall_eq_or_imp]
    split <;> rename_i h
    · have := Nat.ne_of_lt (Nat.lt_succ.mpr (length_filterMap_le f l))
      simp_all
    · simp_all [Nat.add_one_inj]
Length Preservation in Filter-Mapping: $|\text{filterMap } f l| = |l| \leftrightarrow \forall a \in l, \text{isSome } (f a)$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any list $l$ of elements of type $\alpha$, the length of the filtered list $\text{filterMap } f l$ is equal to the length of $l$ if and only if for every element $a \in l$, the option $f a$ is of the form $\text{some } b$ for some $b \in \beta$. In mathematical notation: $$|\text{filterMap } f l| = |l| \leftrightarrow \forall a \in l, \text{isSome } (f a)$$
List.filterMap_eq_filter theorem
{p : α → Bool} : filterMap (Option.guard (p ·)) = filter p
Full source
@[simp]
theorem filterMap_eq_filter {p : α → Bool} :
    filterMap (Option.guard (p ·)) = filter p := by
  funext l
  induction l with
  | nil => rfl
  | cons a l IH => by_cases pa : p a <;> simp [filterMap_cons, Option.guard, pa, ← IH]
Equivalence of Filter-Map with Guard and Filter Operations
Informal description
For any predicate $p : \alpha \to \text{Bool}$, the operation $\text{filterMap}$ with the function $\text{Option.guard} \circ p$ is equivalent to the $\text{filter}$ operation with predicate $p$. That is, \[ \text{filterMap} (\text{Option.guard} \circ p) = \text{filter } p \]
List.filterMap_filterMap theorem
{f : α → Option β} {g : β → Option γ} {l : List α} : filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l
Full source
theorem filterMap_filterMap {f : α → Option β} {g : β → Option γ} {l : List α} :
    filterMap g (filterMap f l) = filterMap (fun x => (f x).bind g) l := by
  induction l with
  | nil => rfl
  | cons a l IH => cases h : f a <;> simp [filterMap_cons, *]
Composition of Filter-Maps via Option Binding
Informal description
For any functions $f : \alpha \to \text{Option } \beta$ and $g : \beta \to \text{Option } \gamma$, and any list $l$ of elements in $\alpha$, the composition of filter-maps satisfies: \[ \text{filterMap } g (\text{filterMap } f l) = \text{filterMap } (x \mapsto (f x).\text{bind } g) l \]
List.map_filterMap theorem
{f : α → Option β} {g : β → γ} {l : List α} : map g (filterMap f l) = filterMap (fun x => (f x).map g) l
Full source
theorem map_filterMap {f : α → Option β} {g : β → γ} {l : List α} :
    map g (filterMap f l) = filterMap (fun x => (f x).map g) l := by
  simp only [← filterMap_eq_map, filterMap_filterMap, Option.map_eq_bind]
Commutativity of Map and FilterMap via Option Mapping
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any function $g : \beta \to \gamma$, and any list $l$ of elements in $\alpha$, the following equality holds: \[ \text{map } g (\text{filterMap } f l) = \text{filterMap } (x \mapsto (f x).\text{map } g) l \]
List.filterMap_map theorem
{f : α → β} {g : β → Option γ} {l : List α} : filterMap g (map f l) = filterMap (g ∘ f) l
Full source
@[simp]
theorem filterMap_map {f : α → β} {g : β → Option γ} {l : List α} :
    filterMap g (map f l) = filterMap (g ∘ f) l := by
  rw [← filterMap_eq_map, filterMap_filterMap]; rfl
Composition of Filter-Map and Map: $\text{filterMap } g \circ \text{map } f = \text{filterMap } (g \circ f)$
Informal description
For any functions $f : \alpha \to \beta$ and $g : \beta \to \text{Option } \gamma$, and any list $l$ of elements in $\alpha$, the following equality holds: \[ \text{filterMap } g (\text{map } f l) = \text{filterMap } (g \circ f) l \]
List.filter_filterMap theorem
{f : α → Option β} {p : β → Bool} {l : List α} : filter p (filterMap f l) = filterMap (fun x => (f x).filter p) l
Full source
theorem filter_filterMap {f : α → Option β} {p : β → Bool} {l : List α} :
    filter p (filterMap f l) = filterMap (fun x => (f x).filter p) l := by
  rw [← filterMap_eq_filter, filterMap_filterMap]
  congr; funext x; cases f x <;> simp [Option.filter, Option.guard]
Commutativity of Filter and FilterMap via Option Filtering
Informal description
For any function $f : \alpha \to \text{Option } \beta$, predicate $p : \beta \to \text{Bool}$, and list $l : \text{List } \alpha$, the following equality holds: \[ \text{filter } p (\text{filterMap } f l) = \text{filterMap } (x \mapsto (f x).\text{filter } p) l \]
List.filterMap_filter theorem
{p : α → Bool} {f : α → Option β} {l : List α} : filterMap f (filter p l) = filterMap (fun x => if p x then f x else none) l
Full source
theorem filterMap_filter {p : α → Bool} {f : α → Option β} {l : List α} :
    filterMap f (filter p l) = filterMap (fun x => if p x then f x else none) l := by
  rw [← filterMap_eq_filter, filterMap_filterMap]
  congr; funext x; by_cases h : p x <;> simp [Option.guard, h]
Filter-Map after Filter Equals Conditional Filter-Map
Informal description
For any predicate $p : \alpha \to \text{Bool}$, function $f : \alpha \to \text{Option } \beta$, and list $l : \text{List } \alpha$, the following equality holds: \[ \text{filterMap } f (\text{filter } p l) = \text{filterMap } (x \mapsto \text{if } p(x) \text{ then } f(x) \text{ else none}) l \]
List.mem_filterMap theorem
{f : α → Option β} {l : List α} {b : β} : b ∈ filterMap f l ↔ ∃ a, a ∈ l ∧ f a = some b
Full source
@[simp] theorem mem_filterMap {f : α → Option β} {l : List α} {b : β} :
    b ∈ filterMap f lb ∈ filterMap f l ↔ ∃ a, a ∈ l ∧ f a = some b := by
  induction l <;> simp [filterMap_cons]; split <;> simp [*, eq_comm]
Membership in Filtered Map via Original List Elements
Informal description
For any function $f : \alpha \to \text{Option } \beta$, list $l : \text{List } \alpha$, and element $b : \beta$, the element $b$ belongs to the filtered map $\text{filterMap } f l$ if and only if there exists an element $a \in l$ such that $f(a) = \text{some } b$. In other words: $$b \in \text{filterMap } f l \leftrightarrow \exists a \in l, f(a) = \text{some } b$$
List.forall_mem_filterMap theorem
{f : α → Option β} {l : List α} {P : β → Prop} : (∀ (i) (_ : i ∈ filterMap f l), P i) ↔ ∀ (j) (_ : j ∈ l) (b), f j = some b → P b
Full source
theorem forall_mem_filterMap {f : α → Option β} {l : List α} {P : β → Prop} :
    (∀ (i) (_ : i ∈ filterMap f l), P i) ↔ ∀ (j) (_ : j ∈ l) (b), f j = some b → P b := by
  simp only [mem_filterMap, forall_exists_index, and_imp]
  rw [forall_comm]
  apply forall_congr'
  intro a
  rw [forall_comm]
Universal Quantification over Filtered Map Elements
Informal description
For any function $f : \alpha \to \text{Option } \beta$, list $l : \text{List } \alpha$, and predicate $P : \beta \to \text{Prop}$, the following are equivalent: 1. For every element $i$ in the filtered map $\text{filterMap } f l$, the predicate $P(i)$ holds. 2. For every element $j$ in $l$ and every $b : \beta$, if $f(j) = \text{some } b$, then $P(b)$ holds. In other words: $$(\forall i \in \text{filterMap } f l, P(i)) \leftrightarrow (\forall j \in l, \forall b, f(j) = \text{some } b \to P(b))$$
List.filterMap_append theorem
{l l' : List α} {f : α → Option β} : filterMap f (l ++ l') = filterMap f l ++ filterMap f l'
Full source
@[simp] theorem filterMap_append {l l' : List α} {f : α → Option β} :
    filterMap f (l ++ l') = filterMap f l ++ filterMap f l' := by
  induction l <;> simp [filterMap_cons]; split <;> simp [*]
Concatenation Commutes with `filterMap`
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any two lists $l, l' : \text{List } \alpha$, the result of applying `filterMap f` to the concatenation of $l$ and $l'$ is equal to the concatenation of `filterMap f l` and `filterMap f l'$. That is, $$\text{filterMap } f (l \mathbin{+\kern-1.5ex+} l') = \text{filterMap } f l \mathbin{+\kern-1.5ex+} \text{filterMap } f l'$$ where $\mathbin{+\kern-1.5ex+}$ denotes list concatenation.
List.map_filterMap_of_inv theorem
{f : α → Option β} {g : β → α} (H : ∀ x : α, (f x).map g = some x) {l : List α} : map g (filterMap f l) = l
Full source
theorem map_filterMap_of_inv
    {f : α → Option β} {g : β → α} (H : ∀ x : α, (f x).map g = some x) {l : List α} :
    map g (filterMap f l) = l := by simp only [map_filterMap, H, filterMap_some, id]
Inverse Property of Filter-Map Composition: $\text{map } g \circ \text{filterMap } f = \text{id}$ when $(f x).\text{map } g = \text{some } x$ for all $x$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any function $g : \beta \to \alpha$ such that for every $x \in \alpha$, $(f x).\text{map } g = \text{some } x$, it holds that for any list $l$ of elements in $\alpha$, the map of $g$ over the filterMap of $f$ applied to $l$ equals $l$ itself, i.e., \[ \text{map } g (\text{filterMap } f l) = l. \]
List.head_filterMap_of_eq_some theorem
{f : α → Option β} {l : List α} (w : l ≠ []) {b : β} (h : f (l.head w) = some b) : (filterMap f l).head ((ne_nil_of_mem (mem_filterMap.2 ⟨_, head_mem w, h⟩))) = b
Full source
theorem head_filterMap_of_eq_some {f : α → Option β} {l : List α} (w : l ≠ []) {b : β} (h : f (l.head w) = some b) :
    (filterMap f l).head ((ne_nil_of_mem (mem_filterMap.2 ⟨_, head_mem w, h⟩))) =
      b := by
  cases l with
  | nil => simp at w
  | cons a l =>
    simp only [head_cons] at h
    simp [filterMap_cons, h]
Head of Filtered Map When Head Maps to Some Value: $\text{head}(\text{filterMap } f l) = b$ when $f(\text{head } l) = \text{some } b$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and non-empty list $l : \text{List } \alpha$, if $f$ applied to the head of $l$ equals $\text{some } b$ for some $b : \beta$, then the head of the filtered map $\text{filterMap } f l$ is equal to $b$.
List.forall_none_of_filterMap_eq_nil theorem
(h : filterMap f xs = []) : ∀ x ∈ xs, f x = none
Full source
theorem forall_none_of_filterMap_eq_nil (h : filterMap f xs = []) : ∀ x ∈ xs, f x = none := by
  intro x hx
  induction xs with
  | nil => contradiction
  | cons y ys ih =>
    simp only [filterMap_cons] at h
    split at h
    · cases hx with
      | head => assumption
      | tail _ hmem => exact ih h hmem
    · contradiction
Empty `filterMap` Implies All `none`
Informal description
For any list `xs` and function `f : α → Option β`, if `filterMap f xs` is the empty list, then for every element `x` in `xs`, `f x` is `none`.
List.filterMap_eq_nil_iff theorem
{l} : filterMap f l = [] ↔ ∀ a ∈ l, f a = none
Full source
@[simp] theorem filterMap_eq_nil_iff {l} : filterMapfilterMap f l = [] ↔ ∀ a ∈ l, f a = none := by
  constructor
  · exact forall_none_of_filterMap_eq_nil
  · intro h
    induction l with
    | nil => rfl
    | cons a l ih =>
      simp only [filterMap_cons]
      split
      · apply ih
        simp_all
      · simp_all
Empty Filtered Map Characterization: $\text{filterMap } f \ l = [] \leftrightarrow \forall a \in l, f(a) = \text{none}$
Informal description
For any list $l$ and function $f : \alpha \to \text{Option } \beta$, the filtered map $\text{filterMap } f \ l$ is the empty list if and only if for every element $a$ in $l$, $f(a) = \text{none}$.
List.filterMap_eq_nil abbrev
Full source
@[deprecated filterMap_eq_nil_iff (since := "2024-09-05")] abbrev filterMap_eq_nil := @filterMap_eq_nil_iff
Empty Filtered Map Characterization: $\text{filterMap } f \ l = [] \leftrightarrow \forall a \in l, f(a) = \text{none}$
Informal description
For any list $l$ and function $f : \alpha \to \text{Option } \beta$, the filtered map $\text{filterMap } f \ l$ is the empty list if and only if for every element $a$ in $l$, $f(a) = \text{none}$.
List.filterMap_eq_cons_iff theorem
{l} {b} {bs} : filterMap f l = b :: bs ↔ ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ (∀ x, x ∈ l₁ → f x = none) ∧ f a = some b ∧ filterMap f l₂ = bs
Full source
theorem filterMap_eq_cons_iff {l} {b} {bs} :
    filterMapfilterMap f l = b :: bs ↔
      ∃ l₁ a l₂, l = l₁ ++ a :: l₂ ∧ (∀ x, x ∈ l₁ → f x = none) ∧ f a = some b ∧
        filterMap f l₂ = bs := by
  constructor
  · induction l with
    | nil => simp
    | cons a l ih =>
      cases h : f a with
      | none =>
        simp only [filterMap_cons_none h]
        intro w
        specialize ih w
        obtain ⟨l₁, a', l₂, rfl, w₁, w₂, w₃⟩ := ih
        exact ⟨a :: l₁, a', l₂, by simp_all⟩
      | some b =>
        simp only [filterMap_cons_some h, cons.injEq, and_imp]
        rintro rfl rfl
        refine ⟨[], a, l, by simp [h]⟩
  · rintro ⟨l₁, a, l₂, rfl, h₁, h₂, h₃⟩
    simp_all [filterMap_eq_nil_iff.mpr h₁, filterMap_cons_some h₂]
Characterization of Non-Empty Filtered Map: $\text{filterMap}\, f\, l = b :: bs$
Informal description
For any list $l$, element $b$, and list $bs$, the filtered map $\text{filterMap}\, f\, l$ equals $b :: bs$ if and only if there exist sublists $l_1$, $l_2$ and an element $a$ such that: 1. $l = l_1 \mathbin{+\!\!+} (a :: l_2)$, 2. For all $x \in l_1$, $f(x) = \text{none}$, 3. $f(a) = \text{some}\, b$, 4. $\text{filterMap}\, f\, l_2 = bs$.
List.filterMap_eq_cons abbrev
Full source
@[deprecated filterMap_eq_cons_iff (since := "2024-09-05")] abbrev filterMap_eq_cons := @filterMap_eq_cons_iff
Non-Empty Filtered Map Decomposition: $\text{filterMap}\, f\, l = b :: bs$
Informal description
For any list $l$, element $b$, and list $bs$, if the filtered map $\text{filterMap}\, f\, l$ equals $b :: bs$, then there exist sublists $l_1$, $l_2$ and an element $a$ such that: 1. $l = l_1 \mathbin{+\!\!+} (a :: l_2)$, 2. For all $x \in l_1$, $f(x) = \text{none}$, 3. $f(a) = \text{some}\, b$, 4. $\text{filterMap}\, f\, l_2 = bs$.
List.nil_append_fun theorem
: (([] : List α) ++ ·) = id
Full source
@[simp] theorem nil_append_fun : (([] : List α) ++ ·) = id := rfl
Empty List Append is Identity Function
Informal description
The function that appends the empty list `[]` to any list is equal to the identity function, i.e., $(\mathtt{[]} \mathbin{+\!\!+} \cdot) = \mathrm{id}$.
List.cons_append_fun theorem
{a : α} {as : List α} : (fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs)
Full source
@[simp] theorem cons_append_fun {a : α} {as : List α} :
    (fun bs => ((a :: as) ++ bs)) = fun bs => a :: (as ++ bs) := rfl
Cons-Append Function Equality
Informal description
For any element $a$ of type $\alpha$ and any list $as$ of type $\alpha$, the function that appends the list $(a :: as)$ to another list $bs$ is equal to the function that prepends $a$ to the result of appending $as$ to $bs$. In other words, the following equality holds for all $bs$: $$(a :: as) \mathbin{+\!\!+} bs = a :: (as \mathbin{+\!\!+} bs)$$
List.mem_append theorem
{a : α} {s t : List α} : a ∈ s ++ t ↔ a ∈ s ∨ a ∈ t
Full source
@[simp] theorem mem_append {a : α} {s t : List α} : a ∈ s ++ ta ∈ s ++ t ↔ a ∈ s ∨ a ∈ t := by
  induction s <;> simp_all [or_assoc]
Membership in Concatenated List: $a \in s \mathbin{+\!\!+} t \leftrightarrow a \in s \lor a \in t$
Informal description
For any element $a$ of type $\alpha$ and any two lists $s$ and $t$ of type $\alpha$, the element $a$ belongs to the concatenated list $s \mathbin{+\!\!+} t$ if and only if $a$ belongs to $s$ or $a$ belongs to $t$.
List.not_mem_append theorem
{a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t
Full source
theorem not_mem_append {a : α} {s t : List α} (h₁ : a ∉ s) (h₂ : a ∉ t) : a ∉ s ++ t :=
  mt mem_append.1 $ not_or.mpr ⟨h₁, h₂⟩
Non-membership in Concatenated List: $a \notin s \mathbin{+\!\!+} t$ from $a \notin s$ and $a \notin t$
Informal description
For any element $a$ of type $\alpha$ and any two lists $s$ and $t$ of type $\alpha$, if $a$ is not a member of $s$ ($a \notin s$) and $a$ is not a member of $t$ ($a \notin t$), then $a$ is not a member of the concatenated list $s \mathbin{+\!\!+} t$ ($a \notin s \mathbin{+\!\!+} t$).
List.mem_append_eq theorem
{a : α} {s t : List α} : (a ∈ s ++ t) = (a ∈ s ∨ a ∈ t)
Full source
@[deprecated mem_append (since := "2025-01-13")]
theorem mem_append_eq {a : α} {s t : List α} : (a ∈ s ++ t) = (a ∈ sa ∈ s ∨ a ∈ t) :=
  propext mem_append
Propositional Equality of Membership in Concatenated List: $(a \in s \mathbin{+\!\!+} t) = (a \in s \lor a \in t)$
Informal description
For any element $a$ of type $\alpha$ and any two lists $s$ and $t$ of type $\alpha$, the proposition that $a$ is a member of the concatenated list $s \mathbin{+\!\!+} t$ is equal to the proposition that $a$ is a member of $s$ or $a$ is a member of $t$. In other words, $(a \in s \mathbin{+\!\!+} t) = (a \in s \lor a \in t)$.
List.mem_append_of_mem_left abbrev
Full source
@[deprecated mem_append_left (since := "2024-11-20")] abbrev mem_append_of_mem_left := @mem_append_left
Membership Preservation in Left Append
Informal description
For any element $a$ of type $\alpha$ and any lists $s$ and $t$ of type $\alpha$, if $a$ is a member of $s$, then $a$ is also a member of the concatenated list $s ++ t$.
List.mem_append_of_mem_right abbrev
Full source
@[deprecated mem_append_right (since := "2024-11-20")] abbrev mem_append_of_mem_right := @mem_append_right
Membership Preservation in Right Append
Informal description
For any element $a$ of type $\alpha$ and any lists $s$ and $t$ of type $\alpha$, if $a$ is a member of $t$, then $a$ is also a member of the concatenated list $s ++ t$.
List.append_of_mem theorem
{a : α} {l : List α} : a ∈ l → ∃ s t : List α, l = s ++ a :: t
Full source
/--
See also `eq_append_cons_of_mem`, which proves a stronger version
in which the initial list must not contain the element.
-/
theorem append_of_mem {a : α} {l : List α} : a ∈ l∃ s t : List α, l = s ++ a :: t
  | .head l => ⟨[], l, rfl⟩
  | .tail b h => let ⟨s, t, h'⟩ := append_of_mem h; ⟨b::s, t, by rw [h', cons_append]⟩
Decomposition of List Containing Element into Prefix and Suffix
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\alpha$, if $a$ is a member of $l$, then there exist lists $s$ and $t$ such that $l$ can be expressed as the concatenation $s ++ (a :: t)$.
List.mem_iff_append theorem
{a : α} {l : List α} : a ∈ l ↔ ∃ s t : List α, l = s ++ a :: t
Full source
theorem mem_iff_append {a : α} {l : List α} : a ∈ la ∈ l ↔ ∃ s t : List α, l = s ++ a :: t :=
  ⟨append_of_mem, fun ⟨s, t, e⟩ => e ▸ by simp⟩
Characterization of List Membership via Concatenation
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\alpha$, $a$ is a member of $l$ if and only if there exist lists $s$ and $t$ such that $l$ can be expressed as the concatenation $s$ followed by $a$ followed by $t$, i.e., $l = s ++ (a :: t)$.
List.forall_mem_append theorem
{p : α → Prop} {l₁ l₂ : List α} : (∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x)
Full source
theorem forall_mem_append {p : α → Prop} {l₁ l₂ : List α} :
    (∀ (x) (_ : x ∈ l₁ ++ l₂), p x) ↔ (∀ (x) (_ : x ∈ l₁), p x) ∧ (∀ (x) (_ : x ∈ l₂), p x) := by
  simp only [mem_append, or_imp, forall_and]
Universal Quantification over Concatenated Lists is Equivalent to Conjunction of Quantifications over Each List
Informal description
For any predicate $p$ on elements of type $\alpha$ and any two lists $l_1$ and $l_2$ of type $\alpha$, the following are equivalent: 1. Every element in the concatenated list $l_1 ++ l_2$ satisfies $p$. 2. Every element in $l_1$ satisfies $p$ and every element in $l_2$ satisfies $p$.
List.getElem_append theorem
{l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) : (l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h)
Full source
theorem getElem_append {l₁ l₂ : List α} {i : Nat} (h : i < (l₁ ++ l₂).length) :
    (l₁ ++ l₂)[i] = if h' : i < l₁.length then l₁[i] else l₂[i - l₁.length]'(by simp at h h'; exact Nat.sub_lt_left_of_lt_add h' h) := by
  split <;> rename_i h'
  · rw [getElem_append_left h']
  · rw [getElem_append_right (by simpa using h')]
Indexing of Concatenated Lists: $(l_1 ++ l_2)[i] = \text{if } i < \text{length}(l_1) \text{ then } l_1[i] \text{ else } l_2[i - \text{length}(l_1)]$
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$ and any natural number index $i$ such that $i < \text{length}(l_1 ++ l_2)$, the element at position $i$ in the concatenated list $l_1 ++ l_2$ is equal to: - The element at position $i$ in $l_1$ if $i < \text{length}(l_1)$ - The element at position $i - \text{length}(l_1)$ in $l_2$ otherwise
List.getElem?_append_left theorem
{l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) : (l₁ ++ l₂)[i]? = l₁[i]?
Full source
theorem getElem?_append_left {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :
    (l₁ ++ l₂)[i]? = l₁[i]? := by
  have hn' : i < (l₁ ++ l₂).length := Nat.lt_of_lt_of_le hn <|
    length_append .. ▸ Nat.le_add_right ..
  simp_all [getElem?_eq_getElem, getElem_append]
Optional Indexing Preserved Under List Concatenation for Left List Indices
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$ and any natural number index $i$ such that $i < \text{length}(l_1)$, the optional indexing operation on the concatenated list $(l_1 ++ l_2)[i]?$ returns the same result as the optional indexing operation on $l_1[i]?$.
List.getElem?_append_right theorem
: ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length ≤ i → (l₁ ++ l₂)[i]? = l₂[i - l₁.length]?
Full source
theorem getElem?_append_right : ∀ {l₁ l₂ : List α} {i : Nat}, l₁.length ≤ i →
  (l₁ ++ l₂)[i]? = l₂[i - l₁.length]?
| [], _, _, _ => rfl
| a :: l, _, i+1, h₁ => by
  rw [cons_append]
  simp [Nat.succ_sub_succ_eq_sub, getElem?_append_right (Nat.lt_succ.1 h₁)]
Optional Indexing in Concatenated List for Right List Indices: $(l_1 ++ l_2)[i]? = l_2[i - \text{length}(l_1)]?$ when $\text{length}(l_1) \leq i$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number index $i$ such that the length of $l_1$ is less than or equal to $i$, the optional indexing operation on the concatenated list $(l_1 ++ l_2)[i]?$ equals the optional indexing operation on $l_2$ at position $i - \text{length}(l_1)$.
List.getElem?_append theorem
{l₁ l₂ : List α} {i : Nat} : (l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]?
Full source
theorem getElem?_append {l₁ l₂ : List α} {i : Nat} :
    (l₁ ++ l₂)[i]? = if i < l₁.length then l₁[i]? else l₂[i - l₁.length]? := by
  split <;> rename_i h
  · exact getElem?_append_left h
  · exact getElem?_append_right (by simpa using h)
Optional Indexing in Concatenated List: $(l_1 ++ l_2)[i]? = \text{if } i < \text{length}(l_1) \text{ then } l_1[i]? \text{ else } l_2[i - \text{length}(l_1)]?$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any natural number index $i$, the optional indexing operation on the concatenated list $(l_1 ++ l_2)[i]?$ equals $l_1[i]?$ if $i < \text{length}(l_1)$, and equals $l_2[i - \text{length}(l_1)]?$ otherwise.
List.getElem_append_left' theorem
{l₁ : List α} {i : Nat} (hi : i < l₁.length) (l₂ : List α) : l₁[i] = (l₁ ++ l₂)[i]'(by simpa using Nat.lt_add_right l₂.length hi)
Full source
/-- Variant of `getElem_append_left` useful for rewriting from the small list to the big list. -/
theorem getElem_append_left' {l₁ : List α} {i : Nat} (hi : i < l₁.length) (l₂ : List α) :
    l₁[i] = (l₁ ++ l₂)[i]'(by simpa using Nat.lt_add_right l₂.length hi) := by
  rw [getElem_append_left] <;> simp
Element Preservation in Left List Concatenation: $l_1[i] = (l_1 ++ l_2)[i]$
Informal description
For any list $l_1$ of type $\alpha$, natural number index $i$ such that $i < \text{length}(l_1)$, and any list $l_2$ of type $\alpha$, the $i$-th element of $l_1$ is equal to the $i$-th element of the concatenated list $l_1 ++ l_2$.
List.getElem_append_right' theorem
(l₁ : List α) {l₂ : List α} {i : Nat} (hi : i < l₂.length) : l₂[i] = (l₁ ++ l₂)[i + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _)
Full source
/-- Variant of `getElem_append_right` useful for rewriting from the small list to the big list. -/
theorem getElem_append_right' (l₁ : List α) {l₂ : List α} {i : Nat} (hi : i < l₂.length) :
    l₂[i] = (l₁ ++ l₂)[i + l₁.length]'(by simpa [Nat.add_comm] using Nat.add_lt_add_left hi _) := by
  rw [getElem_append_right] <;> simp [*, le_add_left]
Element Preservation in Right List Concatenation: $l_2[i] = (l_1 \mathbin{+\kern-0.5ex+} l_2)[i + \text{length}(l_1)]$
Informal description
For any lists $l_1$ and $l_2$ of elements of type $\alpha$, and any natural number index $i$ such that $i < \text{length}(l_2)$, the $i$-th element of $l_2$ is equal to the $(i + \text{length}(l_1))$-th element of the concatenated list $l_1 \mathbin{+\kern-0.5ex+} l_2$.
List.getElem_of_append theorem
{l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) : l[i]'(eq ▸ h ▸ by simp +arith) = a
Full source
theorem getElem_of_append {l : List α} (eq : l = l₁ ++ a :: l₂) (h : l₁.length = i) :
    l[i]'(eq ▸ h ▸ by simp +arith) = a := Option.some.inj <| by
  rw [← getElem?_eq_getElem, eq, getElem?_append_right (h ▸ Nat.le_refl _), h]
  simp
Indexing in Concatenated List at Split Point Yields Middle Element
Informal description
Given a list $l$ of elements of type $\alpha$ that decomposes as $l = l_1 \mathbin{+\kern-0.5ex+} (a :: l_2)$, where $l_1$ and $l_2$ are lists and $a$ is an element, if the length of $l_1$ equals $i$, then the $i$-th element of $l$ is $a$.
List.singleton_append theorem
: [x] ++ l = x :: l
Full source
@[simp] theorem singleton_append : [x] ++ l = x :: l := rfl
Concatenation of Singleton List Equals Cons Operation
Informal description
For any element $x$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the concatenation of the singleton list $[x]$ with $l$ is equal to the list constructed by prepending $x$ to $l$, i.e., $[x] \mathbin{+\kern-0.5ex+} l = x :: l$.
List.append_inj theorem
: ∀ {s₁ s₂ t₁ t₂ : List α}, s₁ ++ t₁ = s₂ ++ t₂ → length s₁ = length s₂ → s₁ = s₂ ∧ t₁ = t₂
Full source
theorem append_inj :
    ∀ {s₁ s₂ t₁ t₂ : List α}, s₁ ++ t₁ = s₂ ++ t₂ → length s₁ = length s₂ → s₁ = s₂ ∧ t₁ = t₂
  | [], [], _, _, h, _ => ⟨rfl, h⟩
  | _ :: _, _ :: _, _, _, h, hl => by
    simp [append_inj (cons.inj h).2 (Nat.succ.inj hl)] at h ⊢; exact h
Injectivity of List Concatenation with Equal Prefix Lengths
Informal description
For any lists $s_1, s_2, t_1, t_2$ of elements of type $\alpha$, if $s_1 \mathbin{+\kern-0.5ex+} t_1 = s_2 \mathbin{+\kern-0.5ex+} t_2$ and the lengths of $s_1$ and $s_2$ are equal, then $s_1 = s_2$ and $t_1 = t_2$.
List.append_inj_right theorem
(h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length s₁ = length s₂) : t₁ = t₂
Full source
theorem append_inj_right (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length s₁ = length s₂) : t₁ = t₂ :=
  (append_inj h hl).right
Right Cancellation Property of List Concatenation with Equal Prefix Lengths
Informal description
For any lists $s_1, s_2, t_1, t_2$ of elements of type $\alpha$, if $s_1 \mathbin{+\kern-0.5ex+} t_1 = s_2 \mathbin{+\kern-0.5ex+} t_2$ and the lengths of $s_1$ and $s_2$ are equal, then $t_1 = t_2$.
List.append_inj_left theorem
(h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length s₁ = length s₂) : s₁ = s₂
Full source
theorem append_inj_left (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length s₁ = length s₂) : s₁ = s₂ :=
  (append_inj h hl).left
Equality of Prefixes in List Concatenation with Equal Lengths
Informal description
For any lists $s_1, s_2, t_1, t_2$ of elements of type $\alpha$, if the concatenation $s_1 \mathbin{+\kern-0.5ex+} t_1$ equals $s_2 \mathbin{+\kern-0.5ex+} t_2$ and the lengths of $s_1$ and $s_2$ are equal, then $s_1 = s_2$.
List.append_inj' theorem
(h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : s₁ = s₂ ∧ t₁ = t₂
Full source
/-- Variant of `append_inj` instead requiring equality of the lengths of the second lists. -/
theorem append_inj' (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : s₁ = s₂ ∧ t₁ = t₂ :=
  append_inj h <| @Nat.add_right_cancel _ t₁.length _ <| by
    let hap := congrArg length h; simp only [length_append, ← hl] at hap; exact hap
List Concatenation Injectivity with Equal Suffix Lengths
Informal description
For any lists $s_1, s_2, t_1, t_2$ of elements of type $\alpha$, if $s_1 \mathbin{+\kern-0.5ex+} t_1 = s_2 \mathbin{+\kern-0.5ex+} t_2$ and the lengths of $t_1$ and $t_2$ are equal, then $s_1 = s_2$ and $t_1 = t_2$.
List.append_inj_right' theorem
(h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : t₁ = t₂
Full source
/-- Variant of `append_inj_right` instead requiring equality of the lengths of the second lists. -/
theorem append_inj_right' (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : t₁ = t₂ :=
  (append_inj' h hl).right
Equality of Suffixes in List Concatenation with Equal Lengths
Informal description
For any lists $s_1, s_2, t_1, t_2$ of elements of type $\alpha$, if the concatenation $s_1 \mathbin{+\kern-0.5ex+} t_1$ equals $s_2 \mathbin{+\kern-0.5ex+} t_2$ and the lengths of $t_1$ and $t_2$ are equal, then $t_1 = t_2$.
List.append_inj_left' theorem
(h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : s₁ = s₂
Full source
/-- Variant of `append_inj_left` instead requiring equality of the lengths of the second lists. -/
theorem append_inj_left' (h : s₁ ++ t₁ = s₂ ++ t₂) (hl : length t₁ = length t₂) : s₁ = s₂ :=
  (append_inj' h hl).left
Left Prefix Equality in List Concatenation with Equal Suffix Lengths
Informal description
For any lists $s_1, s_2, t_1, t_2$ of elements of type $\alpha$, if $s_1 \mathbin{+\kern-0.5ex+} t_1 = s_2 \mathbin{+\kern-0.5ex+} t_2$ and the lengths of $t_1$ and $t_2$ are equal, then $s_1 = s_2$.
List.append_right_inj theorem
{t₁ t₂ : List α} (s) : s ++ t₁ = s ++ t₂ ↔ t₁ = t₂
Full source
theorem append_right_inj {t₁ t₂ : List α} (s) : s ++ t₁ = s ++ t₂ ↔ t₁ = t₂ :=
  ⟨fun h => append_inj_right h rfl, congrArg _⟩
Right Cancellation Property of List Concatenation: $s \mathbin{+\kern-0.5ex+} t_1 = s \mathbin{+\kern-0.5ex+} t_2 \leftrightarrow t_1 = t_2$
Informal description
For any list $s$ and any two lists $t_1, t_2$ of elements of type $\alpha$, the concatenation $s \mathbin{+\kern-0.5ex+} t_1$ is equal to $s \mathbin{+\kern-0.5ex+} t_2$ if and only if $t_1 = t_2$.
List.append_left_inj theorem
{s₁ s₂ : List α} (t) : s₁ ++ t = s₂ ++ t ↔ s₁ = s₂
Full source
theorem append_left_inj {s₁ s₂ : List α} (t) : s₁ ++ t = s₂ ++ t ↔ s₁ = s₂ :=
  ⟨fun h => append_inj_left' h rfl, congrArg (· ++ _)⟩
Left Cancellation Property of List Concatenation: $s_1 \mathbin{+\kern-0.5ex+} t = s_2 \mathbin{+\kern-0.5ex+} t \leftrightarrow s_1 = s_2$
Informal description
For any two lists $s_1, s_2$ and any list $t$ of elements of type $\alpha$, the concatenation $s_1 \mathbin{+\kern-0.5ex+} t$ is equal to $s_2 \mathbin{+\kern-0.5ex+} t$ if and only if $s_1 = s_2$.
List.append_left_eq_self theorem
{xs ys : List α} : xs ++ ys = ys ↔ xs = []
Full source
@[simp] theorem append_left_eq_self {xs ys : List α} : xs ++ ys = ys ↔ xs = [] := by
  rw [← append_left_inj (s₁ := xs), nil_append]
Left Concatenation Identity: $xs \mathbin{+\kern-0.5ex+} ys = ys \leftrightarrow xs = []$
Informal description
For any two lists $xs$ and $ys$ of elements of type $\alpha$, the concatenation $xs \mathbin{+\kern-0.5ex+} ys$ equals $ys$ if and only if $xs$ is the empty list.
List.self_eq_append_left theorem
{xs ys : List α} : ys = xs ++ ys ↔ xs = []
Full source
@[simp] theorem self_eq_append_left {xs ys : List α} : ys = xs ++ ys ↔ xs = [] := by
  rw [eq_comm, append_left_eq_self]
Left Concatenation Identity: $ys = xs \mathbin{+\kern-0.5ex+} ys \leftrightarrow xs = []$
Informal description
For any two lists $xs$ and $ys$ of elements of type $\alpha$, the equality $ys = xs \mathbin{+\kern-0.5ex+} ys$ holds if and only if $xs$ is the empty list.
List.self_eq_append_right theorem
{xs ys : List α} : xs = xs ++ ys ↔ ys = []
Full source
@[simp] theorem self_eq_append_right {xs ys : List α} : xs = xs ++ ys ↔ ys = [] := by
  rw [eq_comm, append_right_eq_self]
Right Concatenation Identity: $xs = xs \mathbin{+\kern-0.5ex+} ys \leftrightarrow ys = []$
Informal description
For any two lists $xs$ and $ys$ of elements of type $\alpha$, the equality $xs = xs \mathbin{+\kern-0.5ex+} ys$ holds if and only if $ys$ is the empty list.
List.getLast_concat theorem
{a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp) = a
Full source
theorem getLast_concat {a : α} : ∀ {l : List α}, getLast (l ++ [a]) (by simp) = a
  | [] => rfl
  | a::t => by
    simp [getLast_cons _, getLast_concat]
Last Element of Concatenated List: $\text{getLast}(l ++ [a]) = a$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of type $\text{List}\,\alpha$, the last element of the concatenated list $l ++ [a]$ is equal to $a$.
List.append_eq_nil_iff theorem
: p ++ q = [] ↔ p = [] ∧ q = []
Full source
@[simp] theorem append_eq_nil_iff : p ++ q = [] ↔ p = [] ∧ q = [] := by
  cases p <;> simp
Concatenation of Lists is Empty if and only if Both Lists are Empty: $p ++ q = [] \leftrightarrow p = [] \land q = []$
Informal description
For any two lists $p$ and $q$ of type $\text{List}\,\alpha$, the concatenation $p ++ q$ is equal to the empty list $[]$ if and only if both $p$ and $q$ are empty lists.
List.append_eq_nil abbrev
Full source
@[deprecated append_eq_nil_iff (since := "2025-01-13")] abbrev append_eq_nil := @append_eq_nil_iff
Concatenation of Lists is Empty if and only if Both Lists are Empty: $p ++ q = [] \leftrightarrow p = [] \land q = []$
Informal description
For any two lists $p$ and $q$ of type $\text{List}\,\alpha$, the concatenation $p ++ q$ is equal to the empty list $[]$ if and only if both $p$ and $q$ are empty lists.
List.nil_eq_append_iff theorem
: [] = a ++ b ↔ a = [] ∧ b = []
Full source
@[simp] theorem nil_eq_append_iff : [][] = a ++ b ↔ a = [] ∧ b = [] := by
  rw [eq_comm, append_eq_nil_iff]
Empty List Equals Concatenation if and only if Both Lists are Empty: $[] = a ++ b \leftrightarrow a = [] \land b = []$
Informal description
For any two lists $a$ and $b$ of type $\text{List}\,\alpha$, the empty list $[]$ is equal to the concatenation $a ++ b$ if and only if both $a$ and $b$ are empty lists.
List.append_ne_nil_of_left_ne_nil theorem
{s : List α} (h : s ≠ []) (t : List α) : s ++ t ≠ []
Full source
theorem append_ne_nil_of_left_ne_nil {s : List α} (h : s ≠ []) (t : List α) : s ++ t ≠ [] := by simp_all
Concatenation with Non-Empty List is Non-Empty (Left Case)
Informal description
For any non-empty list $s$ (i.e., $s \neq []$) and any list $t$, the concatenation $s ++ t$ is also non-empty.
List.append_ne_nil_of_right_ne_nil theorem
(s : List α) : t ≠ [] → s ++ t ≠ []
Full source
theorem append_ne_nil_of_right_ne_nil (s : List α) : t ≠ []s ++ t ≠ [] := by simp_all
Concatenation with Non-Empty List is Non-Empty (Right Case)
Informal description
For any list $s$ and any non-empty list $t$ (i.e., $t \neq []$), the concatenation $s ++ t$ is also non-empty.
List.append_eq_cons_iff theorem
: as ++ bs = x :: c ↔ (as = [] ∧ bs = x :: c) ∨ (∃ as', as = x :: as' ∧ c = as' ++ bs)
Full source
theorem append_eq_cons_iff :
    as ++ bs = x :: c ↔ (as = [] ∧ bs = x :: c) ∨ (∃ as', as = x :: as' ∧ c = as' ++ bs) := by
  cases as with simp | cons a as => ?_
  exact ⟨fun h => ⟨as, by simp [h]⟩, fun ⟨as', ⟨aeq, aseq⟩, h⟩ => ⟨aeq, by rw [aseq, h]⟩⟩
Characterization of When List Concatenation Equals a Cons Cell
Informal description
For any lists `as`, `bs`, and `c`, and any element `x`, the concatenation `as ++ bs` equals the list `x :: c` if and only if either: 1. `as` is empty and `bs` equals `x :: c`, or 2. There exists a list `as'` such that `as` equals `x :: as'` and `c` equals `as' ++ bs`.
List.cons_eq_append_iff theorem
: x :: cs = as ++ bs ↔ (as = [] ∧ bs = x :: cs) ∨ (∃ as', as = x :: as' ∧ cs = as' ++ bs)
Full source
theorem cons_eq_append_iff :
    x :: csx :: cs = as ++ bs ↔ (as = [] ∧ bs = x :: cs) ∨ (∃ as', as = x :: as' ∧ cs = as' ++ bs) := by
  rw [eq_comm, append_eq_cons_iff]
Characterization of Cons as List Concatenation: $x :: cs = as ++ bs \leftrightarrow (as = [] \land bs = x :: cs) \lor (\exists as', as = x :: as' \land cs = as' ++ bs)$
Informal description
For any element $x$, list $cs$, and lists $as$ and $bs$, the list $x :: cs$ is equal to the concatenation $as ++ bs$ if and only if either: 1. $as$ is empty and $bs$ equals $x :: cs$, or 2. There exists a list $as'$ such that $as$ equals $x :: as'$ and $cs$ equals $as' ++ bs$.
List.append_eq_singleton_iff theorem
: a ++ b = [x] ↔ (a = [] ∧ b = [x]) ∨ (a = [x] ∧ b = [])
Full source
theorem append_eq_singleton_iff :
    a ++ b = [x] ↔ (a = [] ∧ b = [x]) ∨ (a = [x] ∧ b = []) := by
  cases a <;> cases b <;> simp
Characterization of Singleton Lists as Concatenations: $a ++ b = [x] \leftrightarrow (a = [] \land b = [x]) \lor (a = [x] \land b = [])$
Informal description
For any lists $a$ and $b$ and any element $x$, the concatenation $a ++ b$ equals the singleton list $[x]$ if and only if either: 1. $a$ is the empty list and $b$ is $[x]$, or 2. $a$ is $[x]$ and $b$ is the empty list.
List.singleton_eq_append_iff theorem
: [x] = a ++ b ↔ (a = [] ∧ b = [x]) ∨ (a = [x] ∧ b = [])
Full source
theorem singleton_eq_append_iff :
    [x][x] = a ++ b ↔ (a = [] ∧ b = [x]) ∨ (a = [x] ∧ b = []) := by
  cases a <;> cases b <;> simp [eq_comm]
Characterization of Singleton as List Concatenation: $[x] = a ++ b \leftrightarrow (a = [] \land b = [x]) \lor (a = [x] \land b = [])$
Informal description
A singleton list $[x]$ is equal to the concatenation of two lists $a$ and $b$ if and only if either: 1. $a$ is the empty list and $b$ is the singleton list $[x]$, or 2. $a$ is the singleton list $[x]$ and $b$ is the empty list.
List.append_eq_append_iff theorem
{ws xs ys zs : List α} : ws ++ xs = ys ++ zs ↔ (∃ as, ys = ws ++ as ∧ xs = as ++ zs) ∨ ∃ bs, ws = ys ++ bs ∧ zs = bs ++ xs
Full source
theorem append_eq_append_iff {ws xs ys zs : List α} :
    ws ++ xs = ys ++ zs ↔ (∃ as, ys = ws ++ as ∧ xs = as ++ zs) ∨ ∃ bs, ws = ys ++ bs ∧ zs = bs ++ xs := by
  induction ws generalizing ys with
  | nil => simp_all
  | cons a as ih => cases ys <;> simp [eq_comm, and_assoc, ih, and_or_left]
Characterization of List Concatenation Equality: $ws ++ xs = ys ++ zs$
Informal description
For any lists $ws, xs, ys, zs$ of elements of type $\alpha$, the concatenation $ws ++ xs$ equals $ys ++ zs$ if and only if either: 1. There exists a list $as$ such that $ys = ws ++ as$ and $xs = as ++ zs$, or 2. There exists a list $bs$ such that $ws = ys ++ bs$ and $zs = bs ++ xs$.
List.head_append_of_ne_nil theorem
{l : List α} {w₁} (w₂) : head (l ++ l') w₁ = head l w₂
Full source
@[simp] theorem head_append_of_ne_nil {l : List α} {w₁} (w₂) :
    head (l ++ l') w₁ = head l w₂ := by
  match l, w₂ with
  | a :: l, _ => rfl
Head of Concatenated List Equals Head of First List
Informal description
For any list $l$ of type $\alpha$ and any default values $w_1$ and $w_2$, the head of the concatenated list $l ++ l'$ with default value $w_1$ is equal to the head of $l$ with default value $w_2$.
List.head_append theorem
{l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) : head (l₁ ++ l₂) w = if h : l₁.isEmpty then head l₂ (by simp_all [isEmpty_iff]) else head l₁ (by simp_all [isEmpty_iff])
Full source
theorem head_append {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) :
    head (l₁ ++ l₂) w =
      if h : l₁.isEmpty then
        head l₂ (by simp_all [isEmpty_iff])
      else
        head l₁ (by simp_all [isEmpty_iff]) := by
  split <;> rename_i h
  · simp [isEmpty_iff] at h
    subst h
    simp
  · simp [isEmpty_iff] at h
    simp [h]
Head of Concatenated List Depends on Emptiness of First List
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$ such that their concatenation $l_1 ++ l_2$ is non-empty, the head of the concatenated list with witness $w$ is equal to: - the head of $l_2$ (with an automatically generated witness) if $l_1$ is empty, or - the head of $l_1$ (with an automatically generated witness) otherwise. Here, the witness $w$ is a proof that the concatenated list is non-empty, and the condition $l_1.\text{isEmpty}$ checks whether $l_1$ is empty.
List.head_append_left theorem
{l₁ l₂ : List α} (h : l₁ ≠ []) : head (l₁ ++ l₂) (fun h => by simp_all) = head l₁ h
Full source
theorem head_append_left {l₁ l₂ : List α} (h : l₁ ≠ []) :
    head (l₁ ++ l₂) (fun h => by simp_all) = head l₁ h := by
  rw [head_append, dif_neg (by simp_all)]
Head of Concatenated List Equals Head of First List When Non-Empty
Informal description
For any non-empty list $l_1$ of type $\alpha$ and any list $l_2$ of type $\alpha$, the head of the concatenated list $l_1 \mathbin{+\!\!+} l_2$ (with a proof that it is non-empty) is equal to the head of $l_1$ (with the given proof that $l_1$ is non-empty).
List.head_append_right theorem
{l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) (h : l₁ = []) : head (l₁ ++ l₂) w = head l₂ (by simp_all)
Full source
theorem head_append_right {l₁ l₂ : List α} (w : l₁ ++ l₂ ≠ []) (h : l₁ = []) :
    head (l₁ ++ l₂) w = head l₂ (by simp_all) := by
  rw [head_append, dif_pos (by simp_all)]
Head of Concatenated List Equals Head of Second List When First is Empty
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$ such that their concatenation $l_1 \mathbin{+\!\!+} l_2$ is non-empty, if $l_1$ is empty, then the head of $l_1 \mathbin{+\!\!+} l_2$ (with witness $w$) equals the head of $l_2$ (with an automatically generated witness).
List.head?_append theorem
{l : List α} : (l ++ l').head? = l.head?.or l'.head?
Full source
@[simp] theorem head?_append {l : List α} : (l ++ l').head? = l.head?.or l'.head? := by
  cases l <;> rfl
Head of List Concatenation as Optional Value
Informal description
For any list $l$ of elements of type $\alpha$, the head of the concatenated list $l \mathbin{+\!\!+} l'$ (as an optional value) is equal to the first non-`none` value between $\text{head?}(l)$ and $\text{head?}(l')$. More precisely, $\text{head?}(l \mathbin{+\!\!+} l') = \text{head?}(l) \mathbin{\text{or}} \text{head?}(l')$.
List.tail?_append theorem
{l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail?
Full source
theorem tail?_append {l l' : List α} : (l ++ l').tail? = (l.tail?.map (· ++ l')).or l'.tail? := by
  cases l <;> simp
Tail of List Concatenation as Optional Value
Informal description
For any two lists $l$ and $l'$ of elements of type $\alpha$, the tail of their concatenation $l \mathbin{+\!\!+} l'$ (as an optional value) is equal to either: 1. The result of appending $l'$ to the tail of $l$ (if $l$ has a tail), or 2. The tail of $l'$ (if $l$ is empty). More precisely, $\text{tail?}(l \mathbin{+\!\!+} l') = \text{tail?}(l).\text{map}(\cdot \mathbin{+\!\!+} l') \mathbin{\text{or}} \text{tail?}(l')$.
List.tail?_append_of_ne_nil theorem
{l l' : List α} (_ : l ≠ []) : (l ++ l').tail? = some (l.tail ++ l')
Full source
theorem tail?_append_of_ne_nil {l l' : List α} (_ : l ≠ []) : (l ++ l').tail? = some (l.tail ++ l') :=
  match l with
  | _ :: _ => by simp
Tail of Concatenated Non-Empty List as Some of Concatenated Tails
Informal description
For any two lists $l$ and $l'$ of elements of type $\alpha$, if $l$ is non-empty, then the tail of the concatenated list $l \mathbin{+\!\!+} l'$ (as an optional value) is equal to `some` of the concatenation of the tail of $l$ with $l'$. That is, $\text{tail?}(l \mathbin{+\!\!+} l') = \text{some}(\text{tail}(l) \mathbin{+\!\!+} l')$ when $l \neq []$.
List.tail_append theorem
{l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l'
Full source
theorem tail_append {l l' : List α} : (l ++ l').tail = if l.isEmpty then l'.tail else l.tail ++ l' := by
  cases l <;> simp
Tail of Concatenated Lists: $\text{tail}(l \mathbin{+\!\!+} l') = \text{if } l = [] \text{ then } l'.\text{tail} \text{ else } l.\text{tail} \mathbin{+\!\!+} l'$
Informal description
For any two lists $l$ and $l'$ of elements of type $\alpha$, the tail of their concatenation $l \mathbin{+\!\!+} l'$ is equal to: - $l'.\text{tail}$ if $l$ is empty, or - $l.\text{tail} \mathbin{+\!\!+} l'$ otherwise.
List.tail_append_of_ne_nil theorem
{xs ys : List α} (h : xs ≠ []) : (xs ++ ys).tail = xs.tail ++ ys
Full source
@[simp] theorem tail_append_of_ne_nil {xs ys : List α} (h : xs ≠ []) :
    (xs ++ ys).tail = xs.tail ++ ys := by
  simp_all [tail_append]
Tail of Concatenated Non-Empty List Equals Concatenated Tails
Informal description
For any two lists $xs$ and $ys$ of elements of type $\alpha$, if $xs$ is non-empty, then the tail of the concatenated list $xs \mathbin{+\!\!+} ys$ is equal to the concatenation of the tail of $xs$ with $ys$, i.e., $\text{tail}(xs \mathbin{+\!\!+} ys) = \text{tail}(xs) \mathbin{+\!\!+} ys$.
List.set_append theorem
{s t : List α} : (s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x
Full source
theorem set_append {s t : List α} :
    (s ++ t).set i x = if i < s.length then s.set i x ++ t else s ++ t.set (i - s.length) x := by
  induction s generalizing i with
  | nil => simp
  | cons a as ih => cases i with
    | zero => simp
    | succ i =>
      simp [Nat.add_one_lt_add_one_iff, ih]
      split
      · rfl
      · congr 3; rw [Nat.add_sub_add_right]
Element Replacement in Concatenated Lists: $\text{set}(s \mathbin{+\!\!+} t, i, x) = \text{if } i < \text{length}(s) \text{ then } \text{set}(s, i, x) \mathbin{+\!\!+} t \text{ else } s \mathbin{+\!\!+} \text{set}(t, i - \text{length}(s), x)$
Informal description
For any two lists $s$ and $t$ of elements of type $\alpha$, a natural number index $i$, and an element $x$ of type $\alpha$, the operation of setting the $i$-th element of the concatenated list $s \mathbin{+\!\!+} t$ to $x$ is equal to: - $s.\text{set}(i, x) \mathbin{+\!\!+} t$ if $i$ is less than the length of $s$, or - $s \mathbin{+\!\!+} t.\text{set}(i - \text{length}(s), x)$ otherwise.
List.set_append_left theorem
{s t : List α} (i : Nat) (x : α) (h : i < s.length) : (s ++ t).set i x = s.set i x ++ t
Full source
@[simp] theorem set_append_left {s t : List α} (i : Nat) (x : α) (h : i < s.length) :
    (s ++ t).set i x = s.set i x ++ t := by
  simp [set_append, h]
Element Replacement in Concatenated List When Index in First List: $(s \mathbin{+\!\!+} t).\text{set}(i, x) = s.\text{set}(i, x) \mathbin{+\!\!+} t$ when $i < \text{length}(s)$
Informal description
For any two lists $s$ and $t$ of elements of type $\alpha$, a natural number index $i$, and an element $x$ of type $\alpha$, if $i$ is less than the length of $s$, then replacing the $i$-th element of the concatenated list $s \mathbin{+\!\!+} t$ with $x$ is equal to the concatenation of the modified list $s.\text{set}(i, x)$ with $t$.
List.set_append_right theorem
{s t : List α} (i : Nat) (x : α) (h : s.length ≤ i) : (s ++ t).set i x = s ++ t.set (i - s.length) x
Full source
@[simp] theorem set_append_right {s t : List α} (i : Nat) (x : α) (h : s.length ≤ i) :
    (s ++ t).set i x = s ++ t.set (i - s.length) x := by
  rw [set_append, if_neg (by simp_all)]
Element Replacement in Concatenated Lists Beyond First List's Length: $(s \mathbin{+\!\!+} t).\text{set}(i, x) = s \mathbin{+\!\!+} t.\text{set}(i - \text{length}(s), x)$ when $\text{length}(s) ≤ i$
Informal description
For any two lists $s$ and $t$ of elements of type $\alpha$, a natural number index $i$, and an element $x$ of type $\alpha$, if the length of $s$ is less than or equal to $i$, then replacing the $i$-th element of the concatenated list $s \mathbin{+\!\!+} t$ with $x$ is equal to the concatenation of $s$ with the list obtained by replacing the $(i - \text{length}(s))$-th element of $t$ with $x$.
List.filterMap_eq_append_iff theorem
{f : α → Option β} : filterMap f l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filterMap f l₁ = L₁ ∧ filterMap f l₂ = L₂
Full source
theorem filterMap_eq_append_iff {f : α → Option β} :
    filterMapfilterMap f l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filterMap f l₁ = L₁ ∧ filterMap f l₂ = L₂ := by
  constructor
  · induction l generalizing L₁ with
    | nil =>
      simp only [filterMap_nil, nil_eq_append_iff, and_imp]
      rintro rfl rfl
      exact ⟨[], [], by simp⟩
    | cons x l ih =>
      simp only [filterMap_cons]
      split
      · intro h
        obtain ⟨l₁, l₂, rfl, rfl, rfl⟩ := ih h
        refine ⟨x :: l₁, l₂, ?_⟩
        simp_all
      · rename_i b w
        intro h
        rcases cons_eq_append_iff.mp h with (⟨rfl, rfl⟩ | ⟨_, ⟨rfl, h⟩⟩)
        · refine ⟨[], x :: l, ?_⟩
          simp [filterMap_cons, w]
        · obtain ⟨l₁, l₂, rfl, rfl, rfl⟩ := ih ‹_›
          refine ⟨x :: l₁, l₂, ?_⟩
          simp [filterMap_cons, w]
  · rintro ⟨l₁, l₂, rfl, rfl, rfl⟩
    simp
Characterization of filterMap as List Concatenation: $\text{filterMap } f l = L_1 \mathbin{+\kern-1.5ex+} L_2 \leftrightarrow \exists l_1 l_2, l = l_1 \mathbin{+\kern-1.5ex+} l_2 \land \text{filterMap } f l_1 = L_1 \land \text{filterMap } f l_2 = L_2$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and lists $L_1, L_2 : \text{List } \beta$, the result of applying $\text{filterMap } f$ to a list $l : \text{List } \alpha$ equals the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ if and only if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filterMap } f l_1 = L_1$, and $\text{filterMap } f l_2 = L_2$.
List.filterMap_eq_append abbrev
Full source
@[deprecated filterMap_eq_append_iff (since := "2024-09-05")] abbrev filterMap_eq_append := @filterMap_eq_append_iff
FilterMap Preserves List Concatenation: $\text{filterMap } f l = L_1 \mathbin{+\kern-1.5ex+} L_2$ under Decomposition
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and lists $L_1, L_2 : \text{List } \beta$, if there exist sublists $l_1, l_2$ of $l : \text{List } \alpha$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filterMap } f l_1 = L_1$, and $\text{filterMap } f l_2 = L_2$, then $\text{filterMap } f l = L_1 \mathbin{+\kern-1.5ex+} L_2$.
List.append_eq_filterMap_iff theorem
{f : α → Option β} : L₁ ++ L₂ = filterMap f l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filterMap f l₁ = L₁ ∧ filterMap f l₂ = L₂
Full source
theorem append_eq_filterMap_iff {f : α → Option β} :
    L₁ ++ L₂ = filterMap f l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filterMap f l₁ = L₁ ∧ filterMap f l₂ = L₂ := by
  rw [eq_comm, filterMap_eq_append_iff]
Characterization of List Concatenation via filterMap: $L_1 \mathbin{+\kern-1.5ex+} L_2 = \text{filterMap } f l \leftrightarrow \exists l_1 l_2, l = l_1 \mathbin{+\kern-1.5ex+} l_2 \land \text{filterMap } f l_1 = L_1 \land \text{filterMap } f l_2 = L_2$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and lists $L_1, L_2 : \text{List } \beta$, the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ equals the result of applying $\text{filterMap } f$ to a list $l : \text{List } \alpha$ if and only if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filterMap } f l_1 = L_1$, and $\text{filterMap } f l_2 = L_2$.
List.append_eq_filterMap abbrev
Full source
@[deprecated append_eq_filterMap (since := "2024-09-05")] abbrev append_eq_filterMap := @append_eq_filterMap_iff
Concatenation of filterMap Results: $L_1 \mathbin{+\kern-1.5ex+} L_2 = \text{filterMap } f l$ under Decomposition
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and lists $L_1, L_2 : \text{List } \beta$, if there exist sublists $l_1, l_2$ of $l : \text{List } \alpha$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filterMap } f l_1 = L_1$, and $\text{filterMap } f l_2 = L_2$, then $L_1 \mathbin{+\kern-1.5ex+} L_2 = \text{filterMap } f l$.
List.filter_eq_append_iff theorem
{p : α → Bool} : filter p l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filter p l₁ = L₁ ∧ filter p l₂ = L₂
Full source
theorem filter_eq_append_iff {p : α → Bool} :
    filterfilter p l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filter p l₁ = L₁ ∧ filter p l₂ = L₂ := by
  rw [← filterMap_eq_filter, filterMap_eq_append_iff]
Characterization of Filter as List Concatenation
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and lists $L_1, L_2 : \text{List } \alpha$, the filtered list $\text{filter } p l$ equals the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ if and only if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filter } p l_1 = L_1$, and $\text{filter } p l_2 = L_2$.
List.append_eq_filter_iff theorem
{p : α → Bool} : L₁ ++ L₂ = filter p l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filter p l₁ = L₁ ∧ filter p l₂ = L₂
Full source
theorem append_eq_filter_iff {p : α → Bool} :
    L₁ ++ L₂ = filter p l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ filter p l₁ = L₁ ∧ filter p l₂ = L₂ := by
  rw [eq_comm, filter_eq_append_iff]
Concatenation Equals Filter if and only if Decomposition Exists
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and lists $L_1, L_2 : \text{List } \alpha$, the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ equals the filtered list $\text{filter } p l$ if and only if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filter } p l_1 = L_1$, and $\text{filter } p l_2 = L_2$.
List.append_eq_filter abbrev
Full source
@[deprecated append_eq_filter_iff (since := "2024-09-05")] abbrev append_eq_filter := @append_eq_filter_iff
Concatenation Equals Filter When Decomposition Exists
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and lists $L_1, L_2 : \text{List } \alpha$, the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ equals the filtered list $\text{filter } p l$ if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{filter } p l_1 = L_1$, and $\text{filter } p l_2 = L_2$.
List.map_append theorem
{f : α → β} : ∀ {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂
Full source
@[simp] theorem map_append {f : α → β} : ∀ {l₁ l₂}, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
  intro l₁; induction l₁ <;> intros <;> simp_all
Map Distributes Over List Concatenation: $\text{map } f (l_1 ++ l_2) = \text{map } f l_1 ++ \text{map } f l_2$
Informal description
For any function $f : \alpha \to \beta$ and any two lists $l_1, l_2$ of elements of type $\alpha$, the map of $f$ over the concatenation $l_1 ++ l_2$ is equal to the concatenation of the maps of $f$ over $l_1$ and $l_2$ respectively. That is, $$ \text{map } f (l_1 ++ l_2) = (\text{map } f l_1) ++ (\text{map } f l_2). $$
List.map_eq_append_iff theorem
{f : α → β} : map f l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂
Full source
theorem map_eq_append_iff {f : α → β} :
    mapmap f l = L₁ ++ L₂ ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂ := by
  rw [← filterMap_eq_map, filterMap_eq_append_iff]
Characterization of Map as List Concatenation: $\text{map } f l = L_1 \mathbin{+\kern-1.5ex+} L_2 \leftrightarrow \exists l_1 l_2, l = l_1 \mathbin{+\kern-1.5ex+} l_2 \land \text{map } f l_1 = L_1 \land \text{map } f l_2 = L_2$
Informal description
For any function $f : \alpha \to \beta$ and lists $L_1, L_2 : \text{List } \beta$, the map of $f$ over a list $l : \text{List } \alpha$ equals the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ if and only if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{map } f l_1 = L_1$, and $\text{map } f l_2 = L_2$.
List.append_eq_map_iff theorem
{f : α → β} : L₁ ++ L₂ = map f l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂
Full source
theorem append_eq_map_iff {f : α → β} :
    L₁ ++ L₂ = map f l ↔ ∃ l₁ l₂, l = l₁ ++ l₂ ∧ map f l₁ = L₁ ∧ map f l₂ = L₂ := by
  rw [eq_comm, map_eq_append_iff]
Concatenation Equals Map if and only if Lists Split Accordingly
Informal description
For any function $f : \alpha \to \beta$ and lists $L_1, L_2 \in \text{List}(\beta)$, the concatenation $L_1 \mathbin{+\kern-1.5ex+} L_2$ equals the map of $f$ over a list $l \in \text{List}(\alpha)$ if and only if there exist sublists $l_1, l_2$ of $l$ such that $l = l_1 \mathbin{+\kern-1.5ex+} l_2$, $\text{map } f l_1 = L_1$, and $\text{map } f l_2 = L_2$.
List.map_eq_append abbrev
Full source
@[deprecated map_eq_append_iff (since := "2024-09-05")] abbrev map_eq_append := @map_eq_append_iff
Map Distributes Over List Concatenation: $\text{map } f (l_1 \mathbin{+\kern-1.5ex+} l_2) = \text{map } f l_1 \mathbin{+\kern-1.5ex+} \text{map } f l_2$
Informal description
For any function $f : \alpha \to \beta$ and lists $l_1, l_2 : \text{List } \alpha$, the map of $f$ over the concatenation of $l_1$ and $l_2$ is equal to the concatenation of the maps of $f$ over $l_1$ and $l_2$, i.e., $\text{map } f (l_1 \mathbin{+\kern-1.5ex+} l_2) = \text{map } f l_1 \mathbin{+\kern-1.5ex+} \text{map } f l_2$.
List.append_eq_map abbrev
Full source
@[deprecated append_eq_map_iff (since := "2024-09-05")] abbrev append_eq_map := @append_eq_map_iff
Map Distributes Over List Concatenation: $\text{map } f (l_1 \mathbin{+\kern-1.5ex+} l_2) = \text{map } f l_1 \mathbin{+\kern-1.5ex+} \text{map } f l_2$
Informal description
For any function $f : \alpha \to \beta$ and lists $l_1, l_2 : \text{List } \alpha$, the concatenation of $l_1$ and $l_2$ under the map of $f$ is equal to the concatenation of the maps of $f$ over $l_1$ and $l_2$, i.e., $\text{map } f (l_1 \mathbin{+\kern-1.5ex+} l_2) = \text{map } f l_1 \mathbin{+\kern-1.5ex+} \text{map } f l_2$.
List.concat_nil theorem
{a : α} : concat [] a = [a]
Full source
theorem concat_nil {a : α} : concat [] a = [a] :=
  rfl
Appending to Empty List Yields Singleton: $\text{concat}\ []\ a = [a]$
Informal description
For any element $a$ of type $\alpha$, appending $a$ to the empty list results in the singleton list $[a]$.
List.concat_cons theorem
{a b : α} {l : List α} : concat (a :: l) b = a :: concat l b
Full source
theorem concat_cons {a b : α} {l : List α} : concat (a :: l) b = a :: concat l b :=
  rfl
Concatenation Distributes Over Cons: $\text{concat}(a :: l, b) = a :: \text{concat}(l, b)$
Informal description
For any elements $a, b$ of type $\alpha$ and any list $l$ of type $\text{List } \alpha$, appending $b$ to the list $a :: l$ is equal to the list $a$ followed by the result of appending $b$ to $l$. In other words, $\text{concat}(a :: l, b) = a :: \text{concat}(l, b)$.
List.init_eq_of_concat_eq theorem
{a b : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ b → l₁ = l₂
Full source
theorem init_eq_of_concat_eq {a b : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ b → l₁ = l₂ := by
  simp only [concat_eq_append]
  intro h
  apply append_inj_left' h (by simp)
Equality of Initial Segments from Concatenation Equality
Informal description
For any elements $a, b$ of type $\alpha$ and any lists $l_1, l_2$ of type $\text{List } \alpha$, if the concatenation of $l_1$ with $a$ equals the concatenation of $l_2$ with $b$, then $l_1 = l_2$.
List.last_eq_of_concat_eq theorem
{a b : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ b → a = b
Full source
theorem last_eq_of_concat_eq {a b : α} {l₁ l₂ : List α} : concat l₁ a = concat l₂ b → a = b := by
  simp only [concat_eq_append]
  intro h
  simpa using append_inj_right' h (by simp)
Equality of Last Elements in Concatenated Lists
Informal description
For any elements $a, b$ of type $\alpha$ and any lists $l_1, l_2$ of type $\text{List } \alpha$, if the concatenation of $l_1$ with $a$ equals the concatenation of $l_2$ with $b$, then $a = b$.
List.concat_inj theorem
{a b : α} {l l' : List α} : concat l a = concat l' b ↔ l = l' ∧ a = b
Full source
theorem concat_inj {a b : α} {l l' : List α} : concatconcat l a = concat l' b ↔ l = l' ∧ a = b :=
  ⟨fun h => ⟨init_eq_of_concat_eq h, last_eq_of_concat_eq h⟩, by rintro ⟨rfl, rfl⟩; rfl⟩
Injectivity of List Concatenation: $\text{concat}(l, a) = \text{concat}(l', b) \leftrightarrow l = l' \land a = b$
Informal description
For any elements $a, b$ of type $\alpha$ and any lists $l, l'$ of type $\text{List } \alpha$, the concatenation of $l$ with $a$ equals the concatenation of $l'$ with $b$ if and only if $l = l'$ and $a = b$.
List.concat_inj_left theorem
{l l' : List α} (a : α) : concat l a = concat l' a ↔ l = l'
Full source
theorem concat_inj_left {l l' : List α} (a : α) : concatconcat l a = concat l' a ↔ l = l' :=
  ⟨init_eq_of_concat_eq, by simp⟩
Injectivity of List Concatenation on Initial Segments: $\text{concat}(l, a) = \text{concat}(l', a) \leftrightarrow l = l'$
Informal description
For any lists $l, l'$ of type $\text{List } \alpha$ and any element $a$ of type $\alpha$, the concatenation of $l$ with $a$ equals the concatenation of $l'$ with $a$ if and only if $l = l'$.
List.concat_inj_right theorem
{l : List α} {a a' : α} : concat l a = concat l a' ↔ a = a'
Full source
theorem concat_inj_right {l : List α} {a a' : α} : concatconcat l a = concat l a' ↔ a = a' :=
  ⟨last_eq_of_concat_eq, by simp⟩
Equality of Concatenated Lists Implies Equality of Appended Elements
Informal description
For any list $l$ of elements of type $\alpha$ and any two elements $a, a' \in \alpha$, the concatenation of $l$ with $a$ is equal to the concatenation of $l$ with $a'$ if and only if $a = a'$. In symbols: $$\text{concat}(l, a) = \text{concat}(l, a') \leftrightarrow a = a'$$
List.concat_eq_concat abbrev
Full source
@[deprecated concat_inj (since := "2024-09-05")] abbrev concat_eq_concat := @concat_inj
Equality of Concatenated Lists: $\text{concat}(l_1, a) = \text{concat}(l_2, b) \leftrightarrow l_1 = l_2 \land a = b$
Informal description
For any lists $l_1, l_2$ of type $\text{List } \alpha$ and any elements $a, b$ of type $\alpha$, the concatenation of $l_1$ with $a$ is equal to the concatenation of $l_2$ with $b$ if and only if $l_1 = l_2$ and $a = b$. In symbols: $$\text{concat}(l_1, a) = \text{concat}(l_2, b) \leftrightarrow l_1 = l_2 \land a = b$$
List.concat_append theorem
{a : α} {l₁ l₂ : List α} : concat l₁ a ++ l₂ = l₁ ++ a :: l₂
Full source
theorem concat_append {a : α} {l₁ l₂ : List α} : concat l₁ a ++ l₂ = l₁ ++ a :: l₂ := by simp
Concatenation of Appended List with Another List
Informal description
For any element $a$ of type $\alpha$ and any two lists $l_1, l_2$ of type $\text{List } \alpha$, the concatenation of the list obtained by appending $a$ to the end of $l_1$ with $l_2$ is equal to the concatenation of $l_1$ with the list obtained by prepending $a$ to $l_2$. In symbols: $$\text{concat}(l_1, a) \mathbin{+\kern-1.5ex+} l_2 = l_1 \mathbin{+\kern-1.5ex+} (a :: l_2)$$
List.append_concat theorem
{a : α} {l₁ l₂ : List α} : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a
Full source
theorem append_concat {a : α} {l₁ l₂ : List α} : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a := by simp
Concatenation and Appending Commute: $l_1 \mathbin{+\kern-1.3ex+} \text{concat}(l_2, a) = \text{concat}(l_1 \mathbin{+\kern-1.3ex+} l_2, a)$
Informal description
For any element $a$ of type $\alpha$ and any two lists $l_1, l_2$ of type $\text{List } \alpha$, the concatenation of $l_1$ with the list obtained by appending $a$ to the end of $l_2$ is equal to the list obtained by appending $a$ to the end of the concatenation of $l_1$ and $l_2$. In symbols: $$ l_1 \mathbin{+\kern-1.3ex+} \text{concat}(l_2, a) = \text{concat}(l_1 \mathbin{+\kern-1.3ex+} l_2, a) $$
List.map_concat theorem
{f : α → β} {a : α} {l : List α} : map f (concat l a) = concat (map f l) (f a)
Full source
theorem map_concat {f : α → β} {a : α} {l : List α} : map f (concat l a) = concat (map f l) (f a) := by
  induction l with
  | nil => rfl
  | cons x xs ih => simp [ih]
Map Preserves List Concatenation with Element: $\text{map } f (l \cdot a) = (\text{map } f l) \cdot f(a)$
Informal description
For any function $f : \alpha \to \beta$, any element $a \in \alpha$, and any list $l$ of elements of type $\alpha$, the map of $f$ over the concatenation of $l$ with $a$ is equal to the concatenation of the map of $f$ over $l$ with $f(a)$. That is, $$ \text{map } f (\text{concat } l a) = \text{concat } (\text{map } f l) (f a). $$
List.length_flatten theorem
{L : List (List α)} : L.flatten.length = (L.map length).sum
Full source
@[simp] theorem length_flatten {L : List (List α)} : L.flatten.length = (L.map length).sum := by
  induction L with
  | nil => rfl
  | cons =>
    simp [flatten, length_append, *]
Length of Flattened List Equals Sum of Sublist Lengths
Informal description
For any list of lists $L$ of elements of type $\alpha$, the length of the flattened list $\text{flatten}(L)$ is equal to the sum of the lengths of the sublists in $L$. That is, $$ \text{length}(\text{flatten}(L)) = \sum_{l \in L} \text{length}(l). $$
List.flatten_singleton theorem
{l : List α} : [l].flatten = l
Full source
theorem flatten_singleton {l : List α} : [l].flatten = l := by simp
Flattening of Singleton List of Lists
Informal description
For any list $l$ of elements of type $\alpha$, the flattening of the singleton list containing $l$ is equal to $l$ itself, i.e., $[[l]].\text{flatten} = l$.
List.mem_flatten theorem
: ∀ {L : List (List α)}, a ∈ L.flatten ↔ ∃ l, l ∈ L ∧ a ∈ l
Full source
@[simp] theorem mem_flatten : ∀ {L : List (List α)}, a ∈ L.flattena ∈ L.flatten ↔ ∃ l, l ∈ L ∧ a ∈ l
  | [] => by simp
  | _ :: _ => by simp [mem_flatten, or_and_right, exists_or]
Membership in Flattened List: $a \in \text{flatten}(L) \leftrightarrow \exists l \in L, a \in l$
Informal description
For any list of lists $L$ of elements of type $\alpha$, an element $a$ belongs to the flattened list $\text{flatten}(L)$ if and only if there exists a sublist $l \in L$ such that $a \in l$.
List.flatten_eq_nil_iff theorem
{L : List (List α)} : L.flatten = [] ↔ ∀ l ∈ L, l = []
Full source
@[simp] theorem flatten_eq_nil_iff {L : List (List α)} : L.flatten = [] ↔ ∀ l ∈ L, l = [] := by
  induction L <;> simp_all
Flattened List is Empty if and Only if All Sublists are Empty
Informal description
For a list of lists $L$ of elements of type $\alpha$, the flattening of $L$ is the empty list if and only if every list $l$ in $L$ is itself empty. That is, $\text{flatten}(L) = [] \leftrightarrow \forall l \in L, l = []$.
List.nil_eq_flatten_iff theorem
{L : List (List α)} : [] = L.flatten ↔ ∀ l ∈ L, l = []
Full source
@[simp] theorem nil_eq_flatten_iff {L : List (List α)} : [][] = L.flatten ↔ ∀ l ∈ L, l = [] := by
  rw [eq_comm, flatten_eq_nil_iff]
Empty List Equals Flattening if and Only if All Sublists are Empty
Informal description
For a list of lists $L$ of elements of type $\alpha$, the empty list equals the flattening of $L$ if and only if every list $l$ in $L$ is itself empty. That is, $[] = \text{flatten}(L) \leftrightarrow \forall l \in L, l = []$.
List.flatten_ne_nil_iff theorem
{xss : List (List α)} : xss.flatten ≠ [] ↔ ∃ xs, xs ∈ xss ∧ xs ≠ []
Full source
theorem flatten_ne_nil_iff {xss : List (List α)} : xss.flatten ≠ []xss.flatten ≠ [] ↔ ∃ xs, xs ∈ xss ∧ xs ≠ [] := by
  simp
Non-empty Flattened List iff Contains Non-empty Sublist
Informal description
For a list of lists `xss` of elements of type $\alpha$, the flattened list `xss.flatten` is non-empty if and only if there exists a non-empty sublist `xs` in `xss`. That is, $\text{flatten}(xss) \neq [] \leftrightarrow \exists xs \in xss, xs \neq []$.
List.exists_of_mem_flatten theorem
: a ∈ flatten L → ∃ l, l ∈ L ∧ a ∈ l
Full source
theorem exists_of_mem_flatten : a ∈ flatten L∃ l, l ∈ L ∧ a ∈ l := mem_flatten.1
Existence of Sublist Containing Element in Flattened List
Informal description
For any element $a$ and list of lists $L$, if $a$ is a member of the flattened list $\text{flatten}(L)$, then there exists a sublist $l \in L$ such that $a \in l$.
List.mem_flatten_of_mem theorem
(lL : l ∈ L) (al : a ∈ l) : a ∈ flatten L
Full source
theorem mem_flatten_of_mem (lL : l ∈ L) (al : a ∈ l) : a ∈ flatten L := mem_flatten.2 ⟨l, lL, al⟩
Element in Sublist Implies Element in Flattened List
Informal description
For any list of lists $L$ of elements of type $\alpha$, if $l$ is a sublist in $L$ (i.e., $l \in L$) and $a$ is an element of $l$ (i.e., $a \in l$), then $a$ is an element of the flattened list $\text{flatten}(L)$.
List.forall_mem_flatten theorem
{p : α → Prop} {L : List (List α)} : (∀ (x) (_ : x ∈ flatten L), p x) ↔ ∀ (l) (_ : l ∈ L) (x) (_ : x ∈ l), p x
Full source
theorem forall_mem_flatten {p : α → Prop} {L : List (List α)} :
    (∀ (x) (_ : x ∈ flatten L), p x) ↔ ∀ (l) (_ : l ∈ L) (x) (_ : x ∈ l), p x := by
  simp only [mem_flatten, forall_exists_index, and_imp]
  constructor <;> (intros; solve_by_elim)
Universal Quantification over Flattened List Equals Nested Universal Quantification
Informal description
For any predicate $p : \alpha \to \text{Prop}$ and list of lists $L : \text{List} (\text{List} \alpha)$, the following are equivalent: 1. For every element $x$ in the flattened list $\text{flatten}\ L$, the proposition $p(x)$ holds. 2. For every sublist $l$ in $L$ and every element $x$ in $l$, the proposition $p(x)$ holds. In other words, $\forall x \in \text{flatten}\ L, p(x) \leftrightarrow \forall l \in L, \forall x \in l, p(x)$.
List.flatten_eq_flatMap theorem
{L : List (List α)} : flatten L = L.flatMap id
Full source
theorem flatten_eq_flatMap {L : List (List α)} : flatten L = L.flatMap id := by
  induction L <;> simp [List.flatMap]
Flattening as Flat Mapping with Identity Function
Informal description
For any list of lists $L$ of elements of type $\alpha$, the flattening of $L$ is equal to the flat mapping of the identity function over $L$. That is, $$\text{flatten}(L) = \text{flatMap}(\text{id}, L).$$
List.head?_flatten theorem
{L : List (List α)} : (flatten L).head? = L.findSome? fun l => l.head?
Full source
theorem head?_flatten {L : List (List α)} : (flatten L).head? = L.findSome? fun l => l.head? := by
  induction L with
  | nil => rfl
  | cons =>
    simp only [findSome?_cons]
    split <;> simp_all
Head of Flattened List as First Non-Empty Sublist Head
Informal description
For any list of lists $L$ of elements of type $\alpha$, the head of the flattened list $\text{flatten}(L)$ (as an optional value) is equal to the first non-`none` result of applying $\text{head?}$ to each sublist in $L$. More precisely, $\text{head?}(\text{flatten}(L)) = \text{findSome?} (\lambda l, \text{head?}(l)) L$.
List.map_flatten theorem
{f : α → β} {L : List (List α)} : (flatten L).map f = (map (map f) L).flatten
Full source
@[simp] theorem map_flatten {f : α → β} {L : List (List α)} :
    (flatten L).map f = (map (map f) L).flatten := by
  induction L <;> simp_all
Map-Flatten Commutativity: $\text{map } f \circ \text{flatten} = \text{flatten} \circ \text{map } (\text{map } f)$
Informal description
For any function $f : \alpha \to \beta$ and any list of lists $L : \text{List}(\text{List} \alpha)$, mapping $f$ over the flattened list $\text{flatten}(L)$ is equivalent to first mapping $f$ over each sublist in $L$ and then flattening the result. That is, $$ \text{map } f (\text{flatten } L) = \text{flatten } (\text{map } (\text{map } f) L). $$
List.filterMap_flatten theorem
{f : α → Option β} {L : List (List α)} : filterMap f (flatten L) = flatten (map (filterMap f) L)
Full source
@[simp] theorem filterMap_flatten {f : α → Option β} {L : List (List α)} :
    filterMap f (flatten L) = flatten (map (filterMap f) L) := by
  induction L <;> simp [*, filterMap_append]
`filterMap` Commutes with Flattening of Lists
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any list of lists $L : \text{List } (\text{List } \alpha)$, applying the `filterMap` operation to the flattened list is equivalent to first mapping `filterMap f` over each sublist in $L$ and then flattening the result. That is, $$\text{filterMap } f (\text{flatten } L) = \text{flatten } (\text{map } (\text{filterMap } f) L).$$
List.filter_flatten theorem
{p : α → Bool} {L : List (List α)} : filter p (flatten L) = flatten (map (filter p) L)
Full source
@[simp] theorem filter_flatten {p : α → Bool} {L : List (List α)} :
    filter p (flatten L) = flatten (map (filter p) L) := by
  induction L <;> simp [*, filter_append]
Filter-Flatten Commutativity: $\text{filter } p \circ \text{flatten} = \text{flatten} \circ \text{map } (\text{filter } p)$
Informal description
For any predicate $p \colon \alpha \to \text{Bool}$ and any list of lists $L \colon \text{List}(\text{List} \ \alpha)$, filtering the flattened list $\text{flatten}(L)$ with $p$ is equivalent to first filtering each sublist in $L$ with $p$ and then flattening the result. That is, \[ \text{filter } p (\text{flatten } L) = \text{flatten } (\text{map } (\text{filter } p) L). \]
List.flatten_filter_not_isEmpty theorem
: ∀ {L : List (List α)}, flatten (L.filter fun l => !l.isEmpty) = L.flatten
Full source
theorem flatten_filter_not_isEmpty  :
    ∀ {L : List (List α)}, flatten (L.filter fun l => !l.isEmpty) = L.flatten
  | [] => rfl
  | [][] :: L
  | (a :: l) :: L => by
      simp [flatten_filter_not_isEmpty (L := L)]
Flattening Non-Empty Sublists is Equivalent to Flattening All Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, flattening the sublists of $L$ that are non-empty is equal to flattening the entire list $L$. That is, \[ \text{flatten} \big(\text{filter} (\lambda l \Rightarrow \neg l.\text{isEmpty}) L\big) = \text{flatten} L. \]
List.flatten_filter_ne_nil theorem
[DecidablePred fun l : List α => l ≠ []] {L : List (List α)} : flatten (L.filter fun l => l ≠ []) = L.flatten
Full source
theorem flatten_filter_ne_nil [DecidablePred fun l : List α => l ≠ []] {L : List (List α)} :
    flatten (L.filter fun l => l ≠ []) = L.flatten := by
  simp only [ne_eq, ← isEmpty_iff, Bool.not_eq_true, Bool.decide_eq_false,
    flatten_filter_not_isEmpty]
Flattening Non-Empty Sublists Equals Flattening All Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, where the predicate "is not the empty list" is decidable, flattening the sublists of $L$ that are non-empty is equal to flattening the entire list $L$. That is, \[ \text{flatten} \big(\text{filter} (\lambda l \Rightarrow l \neq []) L\big) = \text{flatten} L. \]
List.flatten_append theorem
{L₁ L₂ : List (List α)} : flatten (L₁ ++ L₂) = flatten L₁ ++ flatten L₂
Full source
@[simp] theorem flatten_append {L₁ L₂ : List (List α)} : flatten (L₁ ++ L₂) = flatten L₁ ++ flatten L₂ := by
  induction L₁ <;> simp_all
Flattening Distributes Over List Concatenation: $\text{flatten}(L_1 \mathbin{+\kern-0.5em+} L_2) = \text{flatten}(L_1) \mathbin{+\kern-0.5em+} \text{flatten}(L_2)$
Informal description
For any two lists of lists $L_1$ and $L_2$ of elements of type $\alpha$, the flattening of their concatenation $L_1 \mathbin{+\kern-0.5em+} L_2$ is equal to the concatenation of their individual flattenings: $\text{flatten}(L_1 \mathbin{+\kern-0.5em+} L_2) = \text{flatten}(L_1) \mathbin{+\kern-0.5em+} \text{flatten}(L_2)$.
List.flatten_concat theorem
{L : List (List α)} {l : List α} : flatten (L ++ [l]) = flatten L ++ l
Full source
theorem flatten_concat {L : List (List α)} {l : List α} : flatten (L ++ [l]) = flatten L ++ l := by
  simp
Flattening of Concatenation with Singleton List: $\text{flatten}(L \mathbin{+\kern-0.5em+} [l]) = \text{flatten}(L) \mathbin{+\kern-0.5em+} l$
Informal description
For any list of lists $L$ of elements of type $\alpha$ and any list $l$ of elements of type $\alpha$, the flattening of the concatenation $L \mathbin{+\kern-0.5em+} [l]$ is equal to the concatenation of the flattening of $L$ with $l$, i.e., $\text{flatten}(L \mathbin{+\kern-0.5em+} [l]) = \text{flatten}(L) \mathbin{+\kern-0.5em+} l$.
List.flatten_flatten theorem
{L : List (List (List α))} : flatten (flatten L) = flatten (map flatten L)
Full source
theorem flatten_flatten {L : List (List (List α))} : flatten (flatten L) = flatten (map flatten L) := by
  induction L <;> simp_all
Double Flattening Equals Flattening of Mapped Flatten: $\text{flatten}(\text{flatten}(L)) = \text{flatten}(\text{map}(\text{flatten}, L))$
Informal description
For any list of lists of lists $L$ of elements of type $\alpha$, flattening $L$ twice is equivalent to first mapping the flatten operation over each inner list in $L$ and then flattening the result. That is, $\text{flatten}(\text{flatten}(L)) = \text{flatten}(\text{map}(\text{flatten}, L))$.
List.flatten_eq_cons_iff theorem
{xss : List (List α)} {y : α} {ys : List α} : xss.flatten = y :: ys ↔ ∃ as bs cs, xss = as ++ (y :: bs) :: cs ∧ (∀ l, l ∈ as → l = []) ∧ ys = bs ++ cs.flatten
Full source
theorem flatten_eq_cons_iff {xss : List (List α)} {y : α} {ys : List α} :
    xss.flatten = y :: ys ↔
      ∃ as bs cs, xss = as ++ (y :: bs) :: cs ∧ (∀ l, l ∈ as → l = []) ∧ ys = bs ++ cs.flatten := by
  constructor
  · induction xss with
    | nil => simp
    | cons xs xss ih =>
      intro h
      simp only [flatten_cons] at h
      replace h := h.symm
      rw [cons_eq_append_iff] at h
      obtain (⟨rfl, h⟩ | ⟨z⟩) := h
      · obtain ⟨as, bs, cs, rfl, _, rfl⟩ := ih h
        refine ⟨[] :: as, bs, cs, ?_⟩
        simpa
      · obtain ⟨as', rfl, rfl⟩ := z
        refine ⟨[], as', xss, ?_⟩
        simp
  · rintro ⟨as, bs, cs, rfl, h₁, rfl⟩
    simp [flatten_eq_nil_iff.mpr h₁]
Characterization of Flattened List as Cons: $\text{flatten}(xss) = y :: ys$
Informal description
For a list of lists `xss` of elements of type `α`, an element `y : α`, and a list `ys : List α`, the flattening of `xss` equals the list `y :: ys` if and only if there exist lists `as`, `bs`, and `cs` such that: 1. `xss` can be written as the concatenation `as ++ (y :: bs) :: cs`, 2. Every list in `as` is empty, and 3. `ys` is equal to the concatenation `bs ++ cs.flatten`.
List.cons_eq_flatten_iff theorem
{xs : List (List α)} {y : α} {ys : List α} : y :: ys = xs.flatten ↔ ∃ as bs cs, xs = as ++ (y :: bs) :: cs ∧ (∀ l, l ∈ as → l = []) ∧ ys = bs ++ cs.flatten
Full source
theorem cons_eq_flatten_iff {xs : List (List α)} {y : α} {ys : List α} :
    y :: ysy :: ys = xs.flatten ↔
      ∃ as bs cs, xs = as ++ (y :: bs) :: cs ∧ (∀ l, l ∈ as → l = []) ∧ ys = bs ++ cs.flatten := by
  rw [eq_comm, flatten_eq_cons_iff]
Characterization of Cons Equality with Flattened List: $y :: ys = \text{flatten}(xs)$
Informal description
For a list of lists $xs$ of elements of type $\alpha$, an element $y \in \alpha$, and a list $ys \in \text{List}\ \alpha$, the equation $y :: ys = \text{flatten}(xs)$ holds if and only if there exist lists $as$, $bs$, and $cs$ such that: 1. $xs = as \mathbin{+\kern-0.5em+} (y :: bs) \mathbin{::} cs$, 2. Every list in $as$ is empty, and 3. $ys = bs \mathbin{+\kern-0.5em+} \text{flatten}(cs)$.
List.flatten_eq_singleton_iff theorem
{xs : List (List α)} {y : α} : xs.flatten = [y] ↔ ∃ as bs, xs = as ++ [y] :: bs ∧ (∀ l, l ∈ as → l = []) ∧ (∀ l, l ∈ bs → l = [])
Full source
theorem flatten_eq_singleton_iff {xs : List (List α)} {y : α} :
    xs.flatten = [y] ↔ ∃ as bs, xs = as ++ [y] :: bs ∧ (∀ l, l ∈ as → l = []) ∧ (∀ l, l ∈ bs → l = []) := by
  rw [flatten_eq_cons_iff]
  constructor
  · rintro ⟨as, bs, cs, rfl, h₁, h₂⟩
    simp at h₂
    obtain ⟨rfl, h₂⟩ := h₂
    exact ⟨as, cs, by simp, h₁, h₂⟩
  · rintro ⟨as, bs, rfl, h₁, h₂⟩
    exact ⟨as, [], bs, rfl, h₁, by simpa⟩
Characterization of Flattening to Singleton List: $\text{flatten}(xs) = [y]$
Informal description
For a list of lists $xs$ of elements of type $\alpha$ and an element $y \in \alpha$, the flattening of $xs$ equals the singleton list $[y]$ if and only if there exist lists $as$ and $bs$ such that: 1. $xs = as \mathbin{+\kern-0.5em+} [y] \mathbin{::} bs$, 2. Every list in $as$ is empty, and 3. Every list in $bs$ is empty.
List.singleton_eq_flatten_iff theorem
{xs : List (List α)} {y : α} : [y] = xs.flatten ↔ ∃ as bs, xs = as ++ [y] :: bs ∧ (∀ l, l ∈ as → l = []) ∧ (∀ l, l ∈ bs → l = [])
Full source
theorem singleton_eq_flatten_iff {xs : List (List α)} {y : α} :
    [y][y] = xs.flatten ↔ ∃ as bs, xs = as ++ [y] :: bs ∧ (∀ l, l ∈ as → l = []) ∧ (∀ l, l ∈ bs → l = []) := by
  rw [eq_comm, flatten_eq_singleton_iff]
Characterization of Singleton Equality with Flattened List: $[y] = \text{flatten}(xs)$
Informal description
For a list of lists $xs$ of elements of type $\alpha$ and an element $y \in \alpha$, the singleton list $[y]$ equals the flattening of $xs$ if and only if there exist lists $as$ and $bs$ such that: 1. $xs = as \mathbin{+\kern-0.5em+} [y] \mathbin{::} bs$, 2. Every list in $as$ is empty, and 3. Every list in $bs$ is empty.
List.flatten_eq_append_iff theorem
{xss : List (List α)} {ys zs : List α} : xss.flatten = ys ++ zs ↔ (∃ as bs, xss = as ++ bs ∧ ys = as.flatten ∧ zs = bs.flatten) ∨ ∃ as bs c cs ds, xss = as ++ (bs ++ c :: cs) :: ds ∧ ys = as.flatten ++ bs ∧ zs = c :: cs ++ ds.flatten
Full source
theorem flatten_eq_append_iff {xss : List (List α)} {ys zs : List α} :
    xss.flatten = ys ++ zs ↔
      (∃ as bs, xss = as ++ bs ∧ ys = as.flatten ∧ zs = bs.flatten) ∨
        ∃ as bs c cs ds, xss = as ++ (bs ++ c :: cs) :: ds ∧ ys = as.flatten ++ bs ∧
          zs = c :: cs ++ ds.flatten := by
  constructor
  · induction xss generalizing ys with
    | nil =>
      simp only [flatten_nil, nil_eq, append_eq_nil_iff, and_false, cons_append, false_and,
        exists_const, exists_false, or_false, and_imp, List.cons_ne_nil]
      rintro rfl rfl
      exact ⟨[], [], by simp⟩
    | cons xs xss ih =>
      intro h
      simp only [flatten_cons] at h
      rw [append_eq_append_iff] at h
      obtain (⟨ys, rfl, h⟩ | ⟨bs, rfl, h⟩) := h
      · obtain (⟨as, bs, rfl, rfl, rfl⟩ | ⟨as, bs, c, cs, ds, rfl, rfl, rfl⟩) := ih h
        · exact .inl ⟨xs :: as, bs, by simp⟩
        · exact .inr ⟨xs :: as, bs, c, cs, ds, by simp⟩
      · simp only [h]
        cases bs with
        | nil => exact .inl ⟨[ys], xss, by simp⟩
        | cons b bs => exact .inr ⟨[], ys, b, bs, xss, by simp⟩
  · rintro (⟨as, bs, rfl, rfl, rfl⟩ | ⟨as, bs, c, cs, ds, rfl, rfl, rfl⟩)
    · simp
    · simp
Characterization of Flattening as Concatenation: $\text{flatten}(xss) = ys \mathbin{+\kern-0.5em+} zs$
Informal description
For a list of lists `xss` of elements of type $\alpha$ and two lists `ys`, `zs` of elements of type $\alpha$, the flattening of `xss` equals the concatenation `ys ++ zs` if and only if either: 1. There exist lists `as` and `bs` such that `xss = as ++ bs`, `ys = as.flatten`, and `zs = bs.flatten`, or 2. There exist lists `as`, `bs`, `c`, `cs`, `ds` such that `xss = as ++ (bs ++ c :: cs) :: ds`, `ys = as.flatten ++ bs`, and `zs = c :: cs ++ ds.flatten`.
List.append_eq_flatten_iff theorem
{xs : List (List α)} {ys zs : List α} : ys ++ zs = xs.flatten ↔ (∃ as bs, xs = as ++ bs ∧ ys = as.flatten ∧ zs = bs.flatten) ∨ ∃ as bs c cs ds, xs = as ++ (bs ++ c :: cs) :: ds ∧ ys = as.flatten ++ bs ∧ zs = c :: cs ++ ds.flatten
Full source
theorem append_eq_flatten_iff {xs : List (List α)} {ys zs : List α} :
    ys ++ zs = xs.flatten ↔
      (∃ as bs, xs = as ++ bs ∧ ys = as.flatten ∧ zs = bs.flatten) ∨
        ∃ as bs c cs ds, xs = as ++ (bs ++ c :: cs) :: ds ∧ ys = as.flatten ++ bs ∧
          zs = c :: cs ++ ds.flatten := by
  rw [eq_comm, flatten_eq_append_iff]
Characterization of Concatenation as Flattening: $ys \mathbin{+\kern-0.5em+} zs = \text{flatten}(xs)$
Informal description
For a list of lists `xs` of elements of type $\alpha$ and two lists `ys`, `zs` of elements of type $\alpha$, the concatenation `ys ++ zs` equals the flattening of `xs` if and only if either: 1. There exist lists `as` and `bs` such that `xs = as ++ bs`, `ys = as.flatten`, and `zs = bs.flatten`, or 2. There exist lists `as`, `bs`, `c`, `cs`, `ds` such that `xs = as ++ (bs ++ c :: cs) :: ds`, `ys = as.flatten ++ bs`, and `zs = c :: cs ++ ds.flatten`.
List.flatMap_def theorem
{l : List α} {f : α → List β} : l.flatMap f = flatten (map f l)
Full source
theorem flatMap_def {l : List α} {f : α → List β} : l.flatMap f = flatten (map f l) := by rfl
FlatMap Equals Flatten of Map
Informal description
For any list $l$ of type $\alpha$ and any function $f : \alpha \to \text{List } \beta$, the flatMap operation on $l$ with $f$ is equal to the flattening of the list obtained by mapping $f$ over $l$. That is, \[ \text{flatMap } f \, l = \text{flatten } (\text{map } f \, l). \]
List.flatMap_id theorem
{L : List (List α)} : L.flatMap id = L.flatten
Full source
@[simp] theorem flatMap_id {L : List (List α)} : L.flatMap id = L.flatten := by simp [flatMap_def]
FlatMap with Identity Equals Flatten
Informal description
For any list of lists $L$ of type $\text{List}(\text{List } \alpha)$, the flatMap operation with the identity function $\text{id}$ is equal to the flattening of $L$, i.e., \[ L.\text{flatMap id} = L.\text{flatten}. \]
List.flatMap_id' theorem
{L : List (List α)} : L.flatMap (fun as => as) = L.flatten
Full source
@[simp] theorem flatMap_id' {L : List (List α)} : L.flatMap (fun as => as) = L.flatten := by simp [flatMap_def]
FlatMap with Anonymous Identity Equals Flatten
Informal description
For any list of lists $L$ of type $\text{List}(\text{List } \alpha)$, the flatMap operation with the anonymous identity function $\lambda (as : \text{List } \alpha), as$ is equal to the flattening of $L$, i.e., \[ L.\text{flatMap } (\lambda as. as) = L.\text{flatten}. \]
List.length_flatMap theorem
{l : List α} {f : α → List β} : length (l.flatMap f) = sum (map (fun a => (f a).length) l)
Full source
@[simp]
theorem length_flatMap {l : List α} {f : α → List β} :
    length (l.flatMap f) = sum (map (fun a => (f a).length) l) := by
  rw [List.flatMap, length_flatten, map_map, Function.comp_def]
Length of Flat-Mapped List Equals Sum of Component Lengths
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List}\ \beta$, the length of the flat-mapped list $l.\text{flatMap}\ f$ is equal to the sum of the lengths of the lists obtained by applying $f$ to each element of $l$. That is, \[ \text{length}(l.\text{flatMap}\ f) = \sum_{a \in l} \text{length}(f(a)). \]
List.mem_flatMap theorem
{f : α → List β} {b} {l : List α} : b ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a
Full source
@[simp] theorem mem_flatMap {f : α → List β} {b} {l : List α} : b ∈ l.flatMap fb ∈ l.flatMap f ↔ ∃ a, a ∈ l ∧ b ∈ f a := by
  simp [flatMap_def, mem_flatten]
  exact ⟨fun ⟨_, ⟨a, h₁, rfl⟩, h₂⟩ => ⟨a, h₁, h₂⟩, fun ⟨a, h₁, h₂⟩ => ⟨_, ⟨a, h₁, rfl⟩, h₂⟩⟩
Membership in Flat-Mapped List: $b \in l.\text{flatMap}\ f \leftrightarrow \exists a \in l, b \in f(a)$
Informal description
For any function $f : \alpha \to \text{List}\ \beta$, element $b : \beta$, and list $l : \text{List}\ \alpha$, the element $b$ is in the flat-mapped list $l.\text{flatMap}\ f$ if and only if there exists an element $a \in l$ such that $b \in f(a)$.
List.exists_of_mem_flatMap theorem
{b : β} {l : List α} {f : α → List β} : b ∈ l.flatMap f → ∃ a, a ∈ l ∧ b ∈ f a
Full source
theorem exists_of_mem_flatMap {b : β} {l : List α} {f : α → List β} :
    b ∈ l.flatMap f∃ a, a ∈ l ∧ b ∈ f a := mem_flatMap.1
Existence of Preimage in FlatMap Operation: $b \in l.\text{flatMap}\ f \to \exists a \in l, b \in f(a)$
Informal description
For any element $b$ of type $\beta$, list $l$ of type $\text{List}\ \alpha$, and function $f : \alpha \to \text{List}\ \beta$, if $b$ is in the flat-mapped list $l.\text{flatMap}\ f$, then there exists an element $a \in l$ such that $b \in f(a)$.
List.mem_flatMap_of_mem theorem
{b : β} {l : List α} {f : α → List β} {a} (al : a ∈ l) (h : b ∈ f a) : b ∈ l.flatMap f
Full source
theorem mem_flatMap_of_mem {b : β} {l : List α} {f : α → List β} {a} (al : a ∈ l) (h : b ∈ f a) :
    b ∈ l.flatMap f := mem_flatMap.2 ⟨a, al, h⟩
Membership in Flat-Mapped List via Membership in Mapped List
Informal description
For any function $f : \alpha \to \text{List}\ \beta$, element $b : \beta$, list $l : \text{List}\ \alpha$, and element $a \in l$, if $b \in f(a)$, then $b \in l.\text{flatMap}\ f$.
List.flatMap_eq_nil_iff theorem
{l : List α} {f : α → List β} : l.flatMap f = [] ↔ ∀ x ∈ l, f x = []
Full source
@[simp]
theorem flatMap_eq_nil_iff {l : List α} {f : α → List β} : l.flatMap f = [] ↔ ∀ x ∈ l, f x = [] :=
  flatten_eq_nil_iff.trans <| by
    simp only [mem_map, forall_exists_index, and_imp, forall_apply_eq_imp_iff₂]
FlatMap Yields Empty List if and Only if All Mapped Lists are Empty
Informal description
For a list $l$ of elements of type $\alpha$ and a function $f : \alpha \to \text{List } \beta$, the flatMap operation on $l$ with $f$ results in the empty list if and only if for every element $x$ in $l$, the list $f(x)$ is empty. That is, \[ \text{flatMap } f \, l = [] \leftrightarrow \forall x \in l, f(x) = []. \]
List.bind_eq_nil abbrev
Full source
@[deprecated flatMap_eq_nil_iff (since := "2024-09-05")] abbrev bind_eq_nil := @flatMap_eq_nil_iff
Bind Yields Empty List if and Only if All Mapped Lists are Empty
Informal description
For a list $l$ of elements of type $\alpha$ and a function $f : \alpha \to \text{List } \beta$, the bind operation (equivalent to `flatMap`) on $l$ with $f$ results in the empty list if and only if for every element $x$ in $l$, the list $f(x)$ is empty. That is, \[ l \mathbin{>>=} f = [] \leftrightarrow \forall x \in l, f(x) = []. \]
List.forall_mem_flatMap theorem
{p : β → Prop} {l : List α} {f : α → List β} : (∀ (x) (_ : x ∈ l.flatMap f), p x) ↔ ∀ (a) (_ : a ∈ l) (b) (_ : b ∈ f a), p b
Full source
theorem forall_mem_flatMap {p : β → Prop} {l : List α} {f : α → List β} :
    (∀ (x) (_ : x ∈ l.flatMap f), p x) ↔ ∀ (a) (_ : a ∈ l) (b) (_ : b ∈ f a), p b := by
  simp only [mem_flatMap, forall_exists_index, and_imp]
  constructor <;> (intros; solve_by_elim)
Universal Quantifier over FlatMap Elements
Informal description
For a predicate $p : \beta \to \text{Prop}$, a list $l$ of elements of type $\alpha$, and a function $f : \alpha \to \text{List } \beta$, the following equivalence holds: \[ (\forall x \in \text{flatMap } f \, l, p(x)) \leftrightarrow (\forall a \in l, \forall b \in f(a), p(b)). \]
List.flatMap_singleton theorem
(f : α → List β) (x : α) : [x].flatMap f = f x
Full source
theorem flatMap_singleton (f : α → List β) (x : α) : [x].flatMap f = f x :=
  append_nil (f x)
FlatMap of Singleton List Equals Function Application
Informal description
For any function $f : \alpha \to \text{List } \beta$ and any element $x \in \alpha$, the flatMap operation applied to the singleton list $[x]$ and $f$ equals $f(x)$. In other words, $[x].\text{flatMap } f = f(x)$.
List.flatMap_singleton' theorem
(l : List α) : (l.flatMap fun x => [x]) = l
Full source
@[simp] theorem flatMap_singleton' (l : List α) : (l.flatMap fun x => [x]) = l := by
  induction l <;> simp [*]
FlatMap with Singleton Function Preserves List Identity
Informal description
For any list $l$ of elements of type $\alpha$, the flatMap operation applied to $l$ with the function mapping each element to a singleton list containing that element is equal to $l$ itself. In other words, $\text{flatMap} (\lambda x \mapsto [x]) l = l$.
List.head?_flatMap theorem
{l : List α} {f : α → List β} : (l.flatMap f).head? = l.findSome? fun a => (f a).head?
Full source
theorem head?_flatMap {l : List α} {f : α → List β} :
    (l.flatMap f).head? = l.findSome? fun a => (f a).head? := by
  induction l with
  | nil => rfl
  | cons =>
    simp only [findSome?_cons]
    split <;> simp_all
Head of FlatMap as Find-Some Operation on Heads
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List } \beta$, the head of the flatMap operation applied to $l$ and $f$ (as an optional value) is equal to the first non-`none` result obtained by applying $\text{head?}$ to each $f(a)$ for $a \in l$. In other words, $\text{head?}(\text{flatMap } f l) = \text{findSome? } (\lambda a \mapsto \text{head?}(f a)) l$.
List.flatMap_append theorem
{xs ys : List α} {f : α → List β} : (xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f
Full source
@[simp] theorem flatMap_append {xs ys : List α} {f : α → List β} :
    (xs ++ ys).flatMap f = xs.flatMap f ++ ys.flatMap f := by
  induction xs; {rfl}; simp_all [flatMap_cons, append_assoc]
Distributivity of flatMap over List Concatenation
Informal description
For any lists $xs$ and $ys$ of elements of type $\alpha$, and any function $f : \alpha \to \text{List} \beta$, the flatMap operation distributes over list concatenation as follows: \[ \text{flatMap} f (xs ++ ys) = (\text{flatMap} f xs) ++ (\text{flatMap} f ys) \]
List.flatMap_assoc theorem
{l : List α} {f : α → List β} {g : β → List γ} : (l.flatMap f).flatMap g = l.flatMap fun x => (f x).flatMap g
Full source
theorem flatMap_assoc {l : List α} {f : α → List β} {g : β → List γ} :
    (l.flatMap f).flatMap g = l.flatMap fun x => (f x).flatMap g := by
  induction l <;> simp [*]
Associativity of `flatMap` for Lists
Informal description
For any list $l$ of elements of type $\alpha$, and any functions $f : \alpha \to \text{List } \beta$ and $g : \beta \to \text{List } \gamma$, the following associativity property holds: \[ (l.\text{flatMap } f).\text{flatMap } g = l.\text{flatMap } \big(x \mapsto (f\,x).\text{flatMap } g\big) \]
List.map_flatMap theorem
{f : β → γ} {g : α → List β} : ∀ {l : List α}, (l.flatMap g).map f = l.flatMap fun a => (g a).map f
Full source
theorem map_flatMap {f : β → γ} {g : α → List β} :
    ∀ {l : List α}, (l.flatMap g).map f = l.flatMap fun a => (g a).map f
  | [] => rfl
  | a::l => by simp only [flatMap_cons, map_append, map_flatMap]
Interchange of `map` and `flatMap`: $\text{map } f \circ \text{flatMap } g = \text{flatMap } (\text{map } f \circ g)$
Informal description
For any function $f : \beta \to \gamma$, any function $g : \alpha \to \text{List } \beta$, and any list $l : \text{List } \alpha$, the following equality holds: $$ \text{map } f (\text{flatMap } g\ l) = \text{flatMap } (fun\ a \mapsto \text{map } f (g\ a))\ l $$ In other words, mapping $f$ over the flattened list obtained by applying $g$ to each element of $l$ is equivalent to first applying $g$ to each element and then mapping $f$ over the resulting lists before flattening.
List.flatMap_map theorem
(f : α → β) (g : β → List γ) (l : List α) : (map f l).flatMap g = l.flatMap (fun a => g (f a))
Full source
theorem flatMap_map (f : α → β) (g : β → List γ) (l : List α) :
    (map f l).flatMap g = l.flatMap (fun a => g (f a)) := by
  induction l <;> simp [flatMap_cons, *]
Composition of `map` and `flatMap` via Function Composition
Informal description
For any function $f : \alpha \to \beta$, any function $g : \beta \to \text{List } \gamma$, and any list $l : \text{List } \alpha$, the following equality holds: $$(l.\text{map } f).\text{flatMap } g = l.\text{flatMap } (g \circ f)$$ where $\circ$ denotes function composition.
List.map_eq_flatMap theorem
{f : α → β} {l : List α} : map f l = l.flatMap fun x => [f x]
Full source
theorem map_eq_flatMap {f : α → β} {l : List α} : map f l = l.flatMap fun x => [f x] := by
  simp only [← map_singleton]
  rw [← flatMap_singleton' l, map_flatMap, flatMap_singleton']
Map as FlatMap of Singleton Lists: $\text{map } f = \text{flatMap } (\lambda x \mapsto [f x])$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the map of $f$ over $l$ is equal to the flatMap of the function $\lambda x \mapsto [f x]$ over $l$. In other words: $$\text{map } f\ l = \text{flatMap } (\lambda x \mapsto [f x])\ l$$
List.filterMap_flatMap theorem
{l : List α} {g : α → List β} {f : β → Option γ} : (l.flatMap g).filterMap f = l.flatMap fun a => (g a).filterMap f
Full source
theorem filterMap_flatMap {l : List α} {g : α → List β} {f : β → Option γ} :
    (l.flatMap g).filterMap f = l.flatMap fun a => (g a).filterMap f := by
  induction l <;> simp [*]
Commutativity of `filterMap` and `flatMap` for Lists
Informal description
For any list $l$ of type $\text{List } \alpha$, any function $g : \alpha \to \text{List } \beta$, and any function $f : \beta \to \text{Option } \gamma$, the following equality holds: $$\text{filterMap } f \left(\text{flatMap } g \, l\right) = \text{flatMap } \left(\lambda a, \text{filterMap } f (g \, a)\right) l$$ where $\text{flatMap}$ applies $g$ to each element of $l$ and concatenates the resulting lists, and $\text{filterMap } f$ applies $f$ to each element and collects the $\text{some}$ results.
List.filter_flatMap theorem
{l : List α} {g : α → List β} {f : β → Bool} : (l.flatMap g).filter f = l.flatMap fun a => (g a).filter f
Full source
theorem filter_flatMap {l : List α} {g : α → List β} {f : β → Bool} :
    (l.flatMap g).filter f = l.flatMap fun a => (g a).filter f := by
  induction l <;> simp [*]
Filter Commutes with FlatMap on Lists: $\text{filter } f \circ \text{flatMap } g = \text{flatMap } (g \circ \text{filter } f)$
Informal description
For any list $l$ of type $\alpha$, any function $g \colon \alpha \to \text{List } \beta$, and any predicate $f \colon \beta \to \text{Bool}$, the following equality holds: \[ \text{filter } f (\text{flatMap } g \, l) = \text{flatMap } (\lambda a, \text{filter } f (g \, a)) \, l \] where $\text{flatMap}$ applies $g$ to each element of $l$ and concatenates the resulting lists, and $\text{filter } f$ selects elements from a list that satisfy $f$.
List.flatMap_eq_foldl theorem
{f : α → List β} {l : List α} : l.flatMap f = l.foldl (fun acc a => acc ++ f a) []
Full source
theorem flatMap_eq_foldl {f : α → List β} {l : List α} :
    l.flatMap f = l.foldl (fun acc a => acc ++ f a) [] := by
  suffices ∀ l', l' ++ l.flatMap f = l.foldl (fun acc a => acc ++ f a) l' by simpa using this []
  intro l'
  induction l generalizing l'
  · simp
  · next ih => rw [flatMap_cons, ← append_assoc, ih, foldl_cons]
FlatMap as Left Fold: $\text{flatMap } f \, l = \text{foldl } (\lambda \text{acc } a, \text{acc} \mathbin{+\!\!+} f \, a) \ [] \ l$
Informal description
For any function $f : \alpha \to \text{List } \beta$ and any list $l : \text{List } \alpha$, the flatMap operation can be expressed as a left fold: $$\text{flatMap } f \, l = \text{foldl } (\lambda \text{acc } a, \text{acc} \mathbin{+\!\!+} f \, a) \ [] \ l$$ where $\mathbin{+\!\!+}$ denotes list concatenation.
List.replicate_one theorem
: replicate 1 a = [a]
Full source
@[simp] theorem replicate_one : replicate 1 a = [a] := rfl
Singleton Replication: $\text{replicate}\,1\,a = [a]$
Informal description
For any element $a$ of type $\alpha$, the list obtained by replicating $a$ exactly once is equal to the singleton list containing $a$, i.e., $\text{replicate}\,1\,a = [a]$.
List.replicate_succ' theorem
: replicate (n + 1) a = replicate n a ++ [a]
Full source
/-- Variant of `replicate_succ` that concatenates `a` to the end of the list. -/
theorem replicate_succ' : replicate (n + 1) a = replicate n a ++ [a] := by
  induction n <;> simp_all [replicate_succ, ← cons_append]
Recursive Definition of Replicate: $\text{replicate}\,(n+1)\,a = \text{replicate}\,n\,a \mathbin{+\!\!+} [a]$
Informal description
For any element $a$ and natural number $n$, the list obtained by replicating $a$ $n+1$ times is equal to the concatenation of the list obtained by replicating $a$ $n$ times and the singleton list $[a]$, i.e., $\text{replicate}\,(n+1)\,a = \text{replicate}\,n\,a \mathbin{+\!\!+} [a]$.
List.mem_replicate theorem
{a b : α} : ∀ {n}, b ∈ replicate n a ↔ n ≠ 0 ∧ b = a
Full source
@[simp] theorem mem_replicate {a b : α} : ∀ {n}, b ∈ replicate n ab ∈ replicate n a ↔ n ≠ 0 ∧ b = a
  | 0 => by simp
  | n+1 => by simp [replicate_succ, mem_replicate, Nat.succ_ne_zero]
Membership in Replicated List: $b \in \text{replicate}\,n\,a \leftrightarrow n \neq 0 \land b = a$
Informal description
For any elements $a$ and $b$ of type $\alpha$ and any natural number $n$, the element $b$ belongs to the list obtained by replicating $a$ $n$ times if and only if $n$ is nonzero and $b$ equals $a$, i.e., $b \in \text{replicate}\,n\,a \leftrightarrow n \neq 0 \land b = a$.
List.contains_replicate theorem
[BEq α] {n : Nat} {a b : α} : (replicate n b).contains a = (a == b && !n == 0)
Full source
@[simp, deprecated mem_replicate (since := "2024-09-05")]
theorem contains_replicate [BEq α] {n : Nat} {a b : α} :
    (replicate n b).contains a = (a == b && !n == 0) := by
  induction n with
  | zero => simp
  | succ n ih =>
    simp only [replicate_succ, elem_cons]
    split <;> simp_all
Containment in Replicated List: $(a \in \text{replicate}\,n\,b) \leftrightarrow (a = b) \land (n \neq 0)$
Informal description
For any type $\alpha$ with a boolean equality relation, and for any natural number $n$ and elements $a, b \in \alpha$, the boolean containment check $(a \in \text{replicate}\,n\,b)$ is equal to $(a == b) \land (n \neq 0)$, where $\text{replicate}\,n\,b$ denotes the list consisting of $n$ copies of $b$.
List.decide_mem_replicate theorem
[BEq α] [LawfulBEq α] {a b : α} : ∀ {n}, decide (b ∈ replicate n a) = ((¬n == 0) && b == a)
Full source
@[simp, deprecated mem_replicate (since := "2024-09-05")]
theorem decide_mem_replicate [BEq α] [LawfulBEq α] {a b : α} :
    ∀ {n}, decide (b ∈ replicate n a) = ((¬ n == 0) && b == a)
  | 0 => by simp
  | n+1 => by simp [replicate_succ, decide_mem_replicate, Nat.succ_ne_zero]
Decision Procedure for Membership in Replicated List: $\text{decide}(b \in \text{replicate}\,n\,a) = (\neg(n == 0) \land (b == a))$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, any elements $a, b \in \alpha$, and any natural number $n$, the boolean decision of whether $b$ is in the list obtained by replicating $a$ $n$ times is equal to the boolean conjunction of "$n$ is not zero" and "$b$ equals $a$", i.e., $\text{decide}(b \in \text{replicate}\,n\,a) = (\neg(n == 0) \land (b == a))$.
List.forall_mem_replicate theorem
{p : α → Prop} {a : α} {n} : (∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a
Full source
theorem forall_mem_replicate {p : α → Prop} {a : α} {n} :
    (∀ b, b ∈ replicate n a → p b) ↔ n = 0 ∨ p a := by
  cases n <;> simp [mem_replicate]
Universal Property of Replicated List: $(\forall b \in \text{replicate}(n, a), p(b)) \leftrightarrow n = 0 \lor p(a)$
Informal description
For any predicate $p : \alpha \to \text{Prop}$, element $a : \alpha$, and natural number $n$, the following are equivalent: 1. Every element in the list $\text{replicate}(n, a)$ (the list containing $n$ copies of $a$) satisfies $p$. 2. Either $n = 0$ (the list is empty) or $p(a)$ holds.
List.replicate_succ_ne_nil theorem
{n : Nat} {a : α} : replicate (n + 1) a ≠ []
Full source
@[simp] theorem replicate_succ_ne_nil {n : Nat} {a : α} : replicatereplicate (n+1) a ≠ [] := by
  simp [replicate_succ]
Non-emptiness of Replicated List: $\text{replicate}(n+1, a) \neq []$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the list obtained by replicating $a$ exactly $n+1$ times is not the empty list.
List.replicate_eq_nil_iff theorem
{n : Nat} (a : α) : replicate n a = [] ↔ n = 0
Full source
@[simp] theorem replicate_eq_nil_iff {n : Nat} (a : α) : replicatereplicate n a = [] ↔ n = 0 := by
  cases n <;> simp
Replicated List is Empty if and Only if Count is Zero
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the list obtained by replicating $a$ exactly $n$ times is equal to the empty list if and only if $n = 0$. In other words, $\text{replicate}(n, a) = [] \leftrightarrow n = 0$.
List.replicate_eq_nil abbrev
Full source
@[deprecated replicate_eq_nil_iff (since := "2024-09-05")] abbrev replicate_eq_nil := @replicate_eq_nil_iff
Replicated List is Empty if and Only if Count is Zero
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the list obtained by replicating $a$ exactly $n$ times is equal to the empty list if and only if $n = 0$. In other words, $\text{replicate}(n, a) = [] \leftrightarrow n = 0$.
List.getElem_replicate theorem
{a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) : (replicate n a)[i] = a
Full source
@[simp] theorem getElem_replicate {a : α} {n : Nat} {i : Nat} (h : i < (replicate n a).length) :
    (replicate n a)[i] = a :=
  eq_of_mem_replicate (getElem_mem _)
Element Access in Replicated List: $(\text{replicate}(n, a))[i] = a$ when $i < n$
Informal description
For any element $a$ of type $\alpha$, natural numbers $n$ and $i$ such that $i < \text{length}(\text{replicate}(n, a))$, the $i$-th element of the list $\text{replicate}(n, a)$ (which consists of $n$ copies of $a$) is equal to $a$. In other words, $(\text{replicate}(n, a))[i] = a$ when $i < n$.
List.getElem?_replicate theorem
: (replicate n a)[i]? = if i < n then some a else none
Full source
theorem getElem?_replicate : (replicate n a)[i]? = if i < n then some a else none := by
  by_cases h : i < n
  · rw [getElem?_eq_getElem (by simpa), getElem_replicate, if_pos h]
  · rw [getElem?_eq_none (by simpa using h), if_neg h]
Optional Indexing of Replicated List: $(\operatorname{replicate}(n, a))[i]? = \operatorname{some} a$ if $i < n$ else $\operatorname{none}$
Informal description
For any natural numbers $n$ and $i$, and any element $a$ of type $\alpha$, the optional indexing operation on the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) satisfies: $$(\operatorname{replicate}(n, a))[i]? = \begin{cases} \operatorname{some} a & \text{if } i < n \\ \operatorname{none} & \text{otherwise} \end{cases}$$
List.getElem?_replicate_of_lt theorem
{n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a
Full source
@[simp] theorem getElem?_replicate_of_lt {n : Nat} {i : Nat} (h : i < n) : (replicate n a)[i]? = some a := by
  simp [getElem?_replicate, h]
Optional Indexing of Replicated List Yields Element for Valid Indices: $(\operatorname{replicate}(n, a))[i]? = \operatorname{some} a$ when $i < n$
Informal description
For any natural numbers $n$ and $i$ such that $i < n$, the optional indexing operation on the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) returns $\operatorname{some} a$ at index $i$, i.e., $(\operatorname{replicate}(n, a))[i]? = \operatorname{some} a$.
List.head?_replicate theorem
{a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a
Full source
theorem head?_replicate {a : α} {n : Nat} : (replicate n a).head? = if n = 0 then none else some a := by
  cases n <;> simp [replicate_succ]
Head Option of Replicated List: $\operatorname{head?}(\operatorname{replicate}(n, a)) = \begin{cases} \operatorname{none} & \text{if } n = 0 \\ \operatorname{some}(a) & \text{otherwise} \end{cases}$
Informal description
For any element $a$ of type $\alpha$ and natural number $n$, the head element of the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) is: - $\operatorname{none}$ if $n = 0$ (empty list) - $\operatorname{some}(a)$ otherwise
List.head_replicate theorem
(w : replicate n a ≠ []) : (replicate n a).head w = a
Full source
@[simp] theorem head_replicate (w : replicatereplicate n a ≠ []) : (replicate n a).head w = a := by
  cases n
  · simp at w
  · simp_all [replicate_succ]
Head of a Replicated List is the Replicated Element
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, if the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) is non-empty, then its head element is equal to $a$.
List.tail_replicate theorem
{n : Nat} {a : α} : (replicate n a).tail = replicate (n - 1) a
Full source
@[simp] theorem tail_replicate {n : Nat} {a : α} : (replicate n a).tail = replicate (n - 1) a := by
  cases n <;> simp [replicate_succ]
Tail of Replicated List is Replicate of Length Minus One
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the tail of the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) is equal to $\operatorname{replicate}(n-1, a)$.
List.replicate_inj theorem
: replicate n a = replicate m b ↔ n = m ∧ (n = 0 ∨ a = b)
Full source
@[simp] theorem replicate_inj : replicatereplicate n a = replicate m b ↔ n = m ∧ (n = 0 ∨ a = b) :=
  ⟨fun h => have eq : n = m := by simpa using congrArg length h
    ⟨eq, by
    subst eq
    by_cases w : n = 0
    · simp_all
    · right
      have p := congrArg (·[0]?) h
      replace w : 0 < n := by exact zero_lt_of_ne_zero w
      simp only [getElem?_replicate, if_pos w] at p
      simp_all⟩,
    by rintro ⟨rfl, rfl | rfl⟩ <;> rfl⟩
Replicated List Equality: $\operatorname{replicate}(n, a) = \operatorname{replicate}(m, b) \leftrightarrow n = m \land (n = 0 \lor a = b)$
Informal description
For any natural numbers $n, m$ and elements $a, b$ of type $\alpha$, the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) is equal to $\operatorname{replicate}(m, b)$ if and only if $n = m$ and either $n = 0$ or $a = b$.
List.map_eq_replicate_iff theorem
{l : List α} {f : α → β} {b : β} : l.map f = replicate l.length b ↔ ∀ x ∈ l, f x = b
Full source
theorem map_eq_replicate_iff {l : List α} {f : α → β} {b : β} :
    l.map f = replicate l.length b ↔ ∀ x ∈ l, f x = b := by
  simp [eq_replicate_iff]
Characterization of Constant Mapping: $f(l) = [b, \dots, b] \leftrightarrow \forall x \in l, f(x) = b$
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \beta$, and any element $b \in \beta$, the mapped list $f(l)$ is equal to the list $\text{replicate}(\text{length}(l), b)$ (a list of length $\text{length}(l)$ where every element is $b$) if and only if for every element $x \in l$, we have $f(x) = b$.
List.map_const theorem
{l : List α} {b : β} : map (Function.const α b) l = replicate l.length b
Full source
@[simp] theorem map_const {l : List α} {b : β} : map (Function.const α b) l = replicate l.length b :=
  map_eq_replicate_iff.mpr fun _ _ => rfl
Mapping a Constant Function Yields a Replicated List: $\text{map}(\text{const}(b), l) = [b, \dots, b]$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $b \in \beta$, the result of mapping the constant function $\text{const}_\alpha(b)$ over $l$ is equal to the list $\text{replicate}(\text{length}(l), b)$, which is a list of length $\text{length}(l)$ where every element is $b$.
List.map_const_fun theorem
{x : β} : map (Function.const α x) = (replicate ·.length x)
Full source
@[simp] theorem map_const_fun {x : β} : map (Function.const α x) = (replicate ·.length x) := by
  funext l
  simp
Constant Mapping Equals Replication: $\text{map}\,(\text{const}\,x) = \text{replicate}\,(\text{length}\,x)$
Informal description
For any element $x$ of type $\beta$, the function that maps a constant function $\text{const}_\alpha(x)$ over a list is equal to the function that replicates $x$ to match the length of the input list. In other words, for any list $l$ of type $\text{List}\,\alpha$, we have $\text{map}\,(\text{const}_\alpha\,x)\,l = \text{replicate}\,(\text{length}\,l)\,x$.
List.map_const' theorem
{l : List α} {b : β} : map (fun _ => b) l = replicate l.length b
Full source
/-- Variant of `map_const` using a lambda rather than `Function.const`. -/
-- This can not be a `@[simp]` lemma because it would fire on every `List.map`.
theorem map_const' {l : List α} {b : β} : map (fun _ => b) l = replicate l.length b :=
  map_const
Mapping a Constant Lambda Yields a Replicated List: $\text{map}(\lambda \_. b, l) = [b, \dots, b]$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $b \in \beta$, mapping the constant function $\lambda \_. b$ over $l$ yields a list of length $\text{length}(l)$ where every element is $b$, i.e., $\text{map}(\lambda \_. b, l) = \text{replicate}(\text{length}(l), b)$.
List.set_replicate_self theorem
: (replicate n a).set i a = replicate n a
Full source
@[simp] theorem set_replicate_self : (replicate n a).set i a = replicate n a := by
  apply ext_getElem
  · simp
  · intro i h₁ h₂
    simp [getElem_set]
Invariance of Replicated List under Self-Replacement: $\text{replicate}(n, a).\text{set}(i, a) = \text{replicate}(n, a)$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and index $i$, replacing the element at position $i$ in the list $\text{replicate}(n, a)$ (which consists of $n$ copies of $a$) with $a$ again leaves the list unchanged. That is, $\text{replicate}(n, a).\text{set}(i, a) = \text{replicate}(n, a)$.
List.replicate_append_replicate theorem
: replicate n a ++ replicate m a = replicate (n + m) a
Full source
@[simp] theorem replicate_append_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
  rw [eq_replicate_iff]
  constructor
  · simp
  · intro b
    simp only [mem_append, mem_replicate, ne_eq]
    rintro (⟨-, rfl⟩ | ⟨_, rfl⟩) <;> rfl
Concatenation of Replicated Lists: $\text{replicate}(n, a) +\!\!+ \text{replicate}(m, a) = \text{replicate}(n + m, a)$
Informal description
For any natural numbers $n$ and $m$ and any element $a$, the concatenation of the list consisting of $n$ copies of $a$ with the list consisting of $m$ copies of $a$ is equal to the list consisting of $n + m$ copies of $a$. In other words, $\text{replicate}(n, a) +\!\!+ \text{replicate}(m, a) = \text{replicate}(n + m, a)$.
List.append_replicate_replicate abbrev
Full source
@[deprecated replicate_append_replicate (since := "2025-01-16")]
abbrev append_replicate_replicate := @replicate_append_replicate
Concatenation of Replicated Lists: $\text{replicate}(n, a) +\!\!+ \text{replicate}(m, a) = \text{replicate}(n + m, a)$
Informal description
For any natural numbers $n$ and $m$ and any element $a$ of type $\alpha$, the concatenation of the list $\text{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) with the list $\text{replicate}(m, a)$ is equal to the list $\text{replicate}(n + m, a)$. In other words, $\text{replicate}(n, a) +\!\!+ \text{replicate}(m, a) = \text{replicate}(n + m, a)$.
List.append_eq_replicate_iff theorem
{l₁ l₂ : List α} {a : α} : l₁ ++ l₂ = replicate n a ↔ l₁.length + l₂.length = n ∧ l₁ = replicate l₁.length a ∧ l₂ = replicate l₂.length a
Full source
theorem append_eq_replicate_iff {l₁ l₂ : List α} {a : α} :
    l₁ ++ l₂ = replicate n a ↔
      l₁.length + l₂.length = n ∧ l₁ = replicate l₁.length a ∧ l₂ = replicate l₂.length a := by
  simp only [eq_replicate_iff, length_append, mem_append, true_and, and_congr_right_iff]
  exact fun _ =>
    { mp := fun h => ⟨fun b m => h b (Or.inl m), fun b m => h b (Or.inr m)⟩,
      mpr := fun h b x => Or.casesOn x (fun m => h.left b m) fun m => h.right b m }
Concatenation Equals Replicate List if and only if Components Are Replicates and Lengths Sum Correctly
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any element $a \in \alpha$, the concatenation $l_1 ++ l_2$ equals the list $\text{replicate}\ n\ a$ (a list of length $n$ with all elements equal to $a$) if and only if the following three conditions hold: 1. The sum of the lengths of $l_1$ and $l_2$ equals $n$, 2. $l_1$ equals $\text{replicate}\ (\text{length}\ l_1)\ a$, and 3. $l_2$ equals $\text{replicate}\ (\text{length}\ l_2)\ a$.
List.append_eq_replicate abbrev
Full source
@[deprecated append_eq_replicate_iff (since := "2024-09-05")] abbrev append_eq_replicate := @append_eq_replicate_iff
Concatenation Equals Replicate List if and only if Components Are Replicates and Lengths Sum Correctly
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any element $a \in \alpha$, the concatenation $l_1 ++ l_2$ equals the list $\text{replicate}\ n\ a$ (a list of length $n$ with all elements equal to $a$) if and only if the following three conditions hold: 1. The sum of the lengths of $l_1$ and $l_2$ equals $n$, 2. $l_1$ equals $\text{replicate}\ (\text{length}\ l_1)\ a$, and 3. $l_2$ equals $\text{replicate}\ (\text{length}\ l_2)\ a$.
List.replicate_eq_append_iff theorem
{l₁ l₂ : List α} {a : α} : replicate n a = l₁ ++ l₂ ↔ l₁.length + l₂.length = n ∧ l₁ = replicate l₁.length a ∧ l₂ = replicate l₂.length a
Full source
theorem replicate_eq_append_iff {l₁ l₂ : List α} {a : α} :
    replicatereplicate n a = l₁ ++ l₂ ↔
      l₁.length + l₂.length = n ∧ l₁ = replicate l₁.length a ∧ l₂ = replicate l₂.length a := by
  rw [eq_comm, append_eq_replicate_iff]
Replicated List Equals Concatenation if and only if Components Are Replicates and Lengths Sum Correctly
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any element $a \in \alpha$, the replicated list $\text{replicate}\ n\ a$ (a list of length $n$ with all elements equal to $a$) equals the concatenation $l_1 ++ l_2$ if and only if the following three conditions hold: 1. The sum of the lengths of $l_1$ and $l_2$ equals $n$, 2. $l_1$ equals $\text{replicate}\ (\text{length}\ l_1)\ a$, and 3. $l_2$ equals $\text{replicate}\ (\text{length}\ l_2)\ a$.
List.map_replicate theorem
: (replicate n a).map f = replicate n (f a)
Full source
@[simp] theorem map_replicate : (replicate n a).map f = replicate n (f a) := by
  ext1 n
  simp only [getElem?_map, getElem?_replicate]
  split <;> simp
Mapping over a Replicated List: $(\operatorname{replicate}(n, a)).\text{map}\,f = \operatorname{replicate}(n, f(a))$
Informal description
For any function $f : \alpha \to \beta$, natural number $n$, and element $a \in \alpha$, mapping $f$ over a list consisting of $n$ copies of $a$ produces a list consisting of $n$ copies of $f(a)$. That is, $$(\operatorname{replicate}(n, a)).\text{map}\,f = \operatorname{replicate}(n, f(a))$$
List.filter_replicate theorem
: (replicate n a).filter p = if p a then replicate n a else []
Full source
theorem filter_replicate : (replicate n a).filter p = if p a then replicate n a else [] := by
  cases n with
  | zero => simp
  | succ n =>
    simp only [replicate_succ, filter_cons]
    split <;> simp_all
Filtering a Replicated List: $\text{filter}\ p\ (\text{replicate}\ n\ a) = \text{if}\ p(a)\ \text{then}\ \text{replicate}\ n\ a\ \text{else}\ []$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, natural number $n$, and element $a : \alpha$, filtering the list $\text{replicate}\ n\ a$ (which consists of $n$ copies of $a$) with $p$ yields: - $\text{replicate}\ n\ a$ if $p(a)$ is true, - the empty list $[]$ otherwise.
List.filter_replicate_of_pos theorem
(h : p a) : (replicate n a).filter p = replicate n a
Full source
@[simp] theorem filter_replicate_of_pos (h : p a) : (replicate n a).filter p = replicate n a := by
  simp [filter_replicate, h]
Filtering a Replicated List with True Predicate Preserves the List
Informal description
For any predicate $p : \alpha \to \text{Bool}$, natural number $n$, and element $a : \alpha$, if $p(a)$ holds, then filtering the list $\text{replicate}\ n\ a$ (which consists of $n$ copies of $a$) with $p$ yields the original list $\text{replicate}\ n\ a$.
List.filter_replicate_of_neg theorem
(h : ¬p a) : (replicate n a).filter p = []
Full source
@[simp] theorem filter_replicate_of_neg (h : ¬ p a) : (replicate n a).filter p = [] := by
  simp [filter_replicate, h]
Filtering a Replicated List with False Predicate Yields Empty List
Informal description
For any predicate $p : \alpha \to \text{Bool}$, natural number $n$, and element $a : \alpha$, if $p(a)$ is false, then filtering the list $\text{replicate}\ n\ a$ (which consists of $n$ copies of $a$) with $p$ yields the empty list $[]$.
List.filterMap_replicate theorem
{f : α → Option β} : (replicate n a).filterMap f = match f a with | none => [] | .some b => replicate n b
Full source
theorem filterMap_replicate {f : α → Option β} :
    (replicate n a).filterMap f = match f a with | none => [] | .some b => replicate n b := by
  induction n with
  | zero => split <;> simp
  | succ n ih =>
    simp only [replicate_succ, filterMap_cons]
    split <;> simp_all
Behavior of `filterMap` on Replicated Lists: $(\text{replicate}\ n\ a).\text{filterMap}\ f = \text{match}\ f(a)\ \text{with}\ \text{none} \Rightarrow []\ |\ \text{some}\ b \Rightarrow \text{replicate}\ n\ b$
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any natural number $n$, applying `filterMap` to a list of $n$ copies of $a$ (i.e., $\text{replicate}\ n\ a$) with $f$ yields either: - The empty list if $f(a) = \text{none}$, or - A list of $n$ copies of $b$ if $f(a) = \text{some}\ b$ In other words: $(\text{replicate}\ n\ a).\text{filterMap}\ f = \begin{cases} [] & \text{if } f(a) = \text{none} \\ \text{replicate}\ n\ b & \text{if } f(a) = \text{some}\ b \end{cases}$
List.filterMap_replicate_of_some theorem
{f : α → Option β} (h : f a = some b) : (replicate n a).filterMap f = replicate n b
Full source
theorem filterMap_replicate_of_some {f : α → Option β} (h : f a = some b) :
    (replicate n a).filterMap f = replicate n b := by
  simp [filterMap_replicate, h]
`filterMap` on Replicated List with Some Value Yields Replicated Result
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any natural number $n$, if $f(a) = \text{some}\ b$, then applying `filterMap` to a list of $n$ copies of $a$ (i.e., $\text{replicate}\ n\ a$) with $f$ yields a list of $n$ copies of $b$. That is, $$(\text{replicate}\ n\ a).\text{filterMap}\ f = \text{replicate}\ n\ b.$$
List.filterMap_replicate_of_isSome theorem
{f : α → Option β} (h : (f a).isSome) : (replicate n a).filterMap f = replicate n (Option.get _ h)
Full source
@[simp] theorem filterMap_replicate_of_isSome {f : α → Option β} (h : (f a).isSome) :
    (replicate n a).filterMap f = replicate n (Option.get _ h) := by
  rw [Option.isSome_iff_exists] at h
  obtain ⟨b, h⟩ := h
  simp [filterMap_replicate, h]
`filterMap` on Replicated List Preserves Length When Function Returns Non-Empty Option
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and natural number $n$, if $f(a)$ is non-empty (i.e., $\text{isSome}(f(a))$ holds), then applying `filterMap` to a list of $n$ copies of $a$ yields a list of $n$ copies of the value contained in $f(a)$. More precisely: $$(\text{replicate}\ n\ a).\text{filterMap}\ f = \text{replicate}\ n\ (\text{Option.get}\ (f\ a)\ h)$$ where $h$ is the proof that $f(a)$ is non-empty.
List.filterMap_replicate_of_none theorem
{f : α → Option β} (h : f a = none) : (replicate n a).filterMap f = []
Full source
@[simp] theorem filterMap_replicate_of_none {f : α → Option β} (h : f a = none) :
    (replicate n a).filterMap f = [] := by
  simp [filterMap_replicate, h]
`filterMap` on Replicated List Yields Empty List When Function Returns None
Informal description
For any function $f : \alpha \to \text{Option}\ \beta$ and any natural number $n$, if $f(a) = \text{none}$, then applying `filterMap` to a list of $n$ copies of $a$ (i.e., $\text{replicate}\ n\ a$) with $f$ yields the empty list. That is: $$(\text{replicate}\ n\ a).\text{filterMap}\ f = []$$
List.flatten_replicate_nil theorem
: (replicate n ([] : List α)).flatten = []
Full source
@[simp] theorem flatten_replicate_nil : (replicate n ([] : List α)).flatten = [] := by
  induction n <;> simp_all [replicate_succ]
Flattening of Replicated Empty Lists Yields Empty List
Informal description
For any natural number $n$, the flattening of a list consisting of $n$ empty lists is the empty list. That is: $$\text{flatten}(\text{replicate}(n, [])) = []$$
List.flatten_replicate_singleton theorem
: (replicate n [a]).flatten = replicate n a
Full source
@[simp] theorem flatten_replicate_singleton : (replicate n [a]).flatten = replicate n a := by
  induction n <;> simp_all [replicate_succ]
Flattening of Replicated Singleton Lists Equals Replication of Elements
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the flattening of a list consisting of $n$ singleton lists $[a]$ is equal to the list of $n$ copies of $a$. In other words: $$\text{flatten}(\text{replicate}(n, [a])) = \text{replicate}(n, a)$$
List.flatten_replicate_replicate theorem
: (replicate n (replicate m a)).flatten = replicate (n * m) a
Full source
@[simp] theorem flatten_replicate_replicate : (replicate n (replicate m a)).flatten = replicate (n * m) a := by
  induction n with
  | zero => simp
  | succ n ih =>
    simp only [replicate_succ, flatten_cons, ih, replicate_append_replicate, replicate_inj, or_true,
      and_true, add_one_mul, Nat.add_comm]
Flattening of Replicated Lists: $\text{flatten}(\text{replicate}(n, \text{replicate}(m, a))) = \text{replicate}(n \cdot m, a)$
Informal description
For any natural numbers $n$ and $m$ and any element $a$, the flattening of a list consisting of $n$ copies of the list containing $m$ copies of $a$ is equal to the list containing $n \times m$ copies of $a$. In other words: $$\text{flatten}(\text{replicate}(n, \text{replicate}(m, a))) = \text{replicate}(n \cdot m, a)$$
List.flatMap_replicate theorem
{β} {f : α → List β} : (replicate n a).flatMap f = (replicate n (f a)).flatten
Full source
theorem flatMap_replicate {β} {f : α → List β} : (replicate n a).flatMap f = (replicate n (f a)).flatten := by
  induction n with
  | zero => simp
  | succ n ih => simp only [replicate_succ, flatMap_cons, ih, flatten_cons]
FlatMap of Replicated List Equals Flatten of Mapped Replication
Informal description
For any type $\alpha$ and $\beta$, any function $f : \alpha \to \text{List}\ \beta$, any natural number $n$, and any element $a \in \alpha$, the flatMap operation on the replicated list satisfies: $$\text{flatMap}\ f\ (\text{replicate}\ n\ a) = \text{flatten}\ (\text{replicate}\ n\ (f\ a))$$ where: - $\text{replicate}\ n\ a$ creates a list containing $n$ copies of $a$ - $\text{flatMap}\ f\ L$ applies $f$ to each element of $L$ and concatenates the results - $\text{flatten}$ concatenates a list of lists into a single list
List.isEmpty_replicate theorem
: (replicate n a).isEmpty = decide (n = 0)
Full source
@[simp] theorem isEmpty_replicate : (replicate n a).isEmpty = decide (n = 0) := by
  cases n <;> simp [replicate_succ]
Empty Replicated List iff Zero Replications
Informal description
For any natural number $n$ and any element $a$, the list obtained by replicating $a$ $n$ times is empty if and only if $n = 0$. More precisely, the boolean value indicating whether the replicated list is empty is equal to the boolean evaluation of the proposition $n = 0$.
List.replicateRecOn theorem
{α : Type _} {p : List α → Prop} (l : List α) (h0 : p []) (hr : ∀ a n, 0 < n → p (replicate n a)) (hi : ∀ a b n l, a ≠ b → 0 < n → p (b :: l) → p (replicate n a ++ b :: l)) : p l
Full source
/-- An induction principle for lists based on contiguous runs of identical elements. -/
-- A `Sort _` valued version would require a different design. (And associated `@[simp]` lemmas.)
theorem replicateRecOn {α : Type _} {p : List α → Prop} (l : List α)
    (h0 : p []) (hr : ∀ a n, 0 < n → p (replicate n a))
    (hi : ∀ a b n l, a ≠ b → 0 < n → p (b :: l) → p (replicate n a ++ b :: l)) : p l := by
  rcases eq_replicate_or_eq_replicate_append_cons l with
    rfl | ⟨n, a, rfl, hn⟩ | ⟨n, a, b, l', w, hn, h⟩
  · exact h0
  · exact hr _ _ hn
  · have : (b :: l').length < l.length := by
      simpa [w] using Nat.lt_add_of_pos_left hn
    subst w
    exact hi _ _ _ _ h hn (replicateRecOn (b :: l') h0 hr hi)
termination_by l.length
Induction Principle for Lists via Replicated Runs
Informal description
Let $\alpha$ be a type and $p$ be a predicate on lists of elements of $\alpha$. Given a list $l$ of elements of $\alpha$, the following induction principle holds: 1. Base case: $p$ holds for the empty list $[]$. 2. Homogeneous case: For any element $a$ and positive natural number $n$, $p$ holds for the list consisting of $n$ copies of $a$. 3. Heterogeneous case: For any distinct elements $a$ and $b$, positive natural number $n$, and list $l'$, if $p$ holds for $b :: l'$, then $p$ holds for the concatenation of $n$ copies of $a$ followed by $b :: l'$. Then $p$ holds for $l$.
List.sum_replicate_nat theorem
{n : Nat} {a : Nat} : (replicate n a).sum = n * a
Full source
@[simp] theorem sum_replicate_nat {n : Nat} {a : Nat} : (replicate n a).sum = n * a := by
  induction n <;> simp_all [replicate_succ, Nat.add_mul, Nat.add_comm]
Sum of Replicated List: $\text{sum}(\text{replicate}\ n\ a) = n \cdot a$
Informal description
For any natural numbers $n$ and $a$, the sum of the list consisting of $n$ copies of $a$ is equal to $n$ multiplied by $a$, i.e., $\text{sum}(\text{replicate}\ n\ a) = n \cdot a$.
List.length_reverse theorem
{as : List α} : (as.reverse).length = as.length
Full source
@[simp] theorem length_reverse {as : List α} : (as.reverse).length = as.length := by
  induction as with
  | nil => rfl
  | cons a as ih => simp [ih]
Length Preservation under List Reversal: $|as.reverse| = |as|$
Informal description
For any list $as$ of elements of type $\alpha$, the length of the reversed list $as.reverse$ is equal to the length of $as$, i.e., $|as.reverse| = |as|$.
List.mem_reverseAux theorem
{x : α} : ∀ {as bs}, x ∈ reverseAux as bs ↔ x ∈ as ∨ x ∈ bs
Full source
theorem mem_reverseAux {x : α} : ∀ {as bs}, x ∈ reverseAux as bsx ∈ reverseAux as bs ↔ x ∈ as ∨ x ∈ bs
  | [], _ => ⟨.inr, fun | .inr h => h⟩
  | a :: _, _ => by rw [reverseAux, mem_cons, or_assoc, or_left_comm, mem_reverseAux, mem_cons]
Membership in Reverse Auxiliary List: $x \in \text{reverseAux}\ as\ bs \leftrightarrow x \in as \lor x \in bs$
Informal description
For any element $x$ of type $\alpha$ and any lists $as$ and $bs$ of elements of type $\alpha$, the element $x$ belongs to the auxiliary reversed list $\text{reverseAux}\ as\ bs$ if and only if $x$ belongs to $as$ or $x$ belongs to $bs$.
List.mem_reverse theorem
{x : α} {as : List α} : x ∈ reverse as ↔ x ∈ as
Full source
@[simp] theorem mem_reverse {x : α} {as : List α} : x ∈ reverse asx ∈ reverse as ↔ x ∈ as := by
  simp [reverse, mem_reverseAux]
Membership in Reversed List: $x \in as.reverse \leftrightarrow x \in as$
Informal description
For any element $x$ of type $\alpha$ and any list $as$ of elements of type $\alpha$, the element $x$ is in the reversed list $as.reverse$ if and only if $x$ is in the original list $as$.
List.reverse_eq_nil_iff theorem
{xs : List α} : xs.reverse = [] ↔ xs = []
Full source
@[simp] theorem reverse_eq_nil_iff {xs : List α} : xs.reverse = [] ↔ xs = [] := by
  match xs with
  | [] => simp
  | x :: xs => simp
Reversed List is Empty if and Only if Original List is Empty: $xs.reverse = [] \leftrightarrow xs = []$
Informal description
For any list $xs$ of elements of type $\alpha$, the reversed list $xs.reverse$ is equal to the empty list $[]$ if and only if $xs$ itself is equal to $[]$.
List.reverse_ne_nil_iff theorem
{xs : List α} : xs.reverse ≠ [] ↔ xs ≠ []
Full source
theorem reverse_ne_nil_iff {xs : List α} : xs.reverse ≠ []xs.reverse ≠ [] ↔ xs ≠ [] :=
  not_congr reverse_eq_nil_iff
Reversed List is Non-Empty if and Only if Original List is Non-Empty: $xs.reverse \neq [] \leftrightarrow xs \neq []$
Informal description
For any list $xs$ of elements of type $\alpha$, the reversed list $xs.reverse$ is non-empty if and only if the original list $xs$ is non-empty. In other words, $xs.reverse \neq [] \leftrightarrow xs \neq []$.
List.isEmpty_reverse theorem
{xs : List α} : xs.reverse.isEmpty = xs.isEmpty
Full source
@[simp] theorem isEmpty_reverse {xs : List α} : xs.reverse.isEmpty = xs.isEmpty := by
  cases xs <;> simp
Reversing a List Preserves Emptiness: $\text{isEmpty}(\text{reverse}(xs)) = \text{isEmpty}(xs)$
Informal description
For any list `xs` of elements of type `α`, the property of being empty is preserved under reversal, i.e., `xs.reverse` is empty if and only if `xs` is empty. In other words, $\text{isEmpty}(\text{reverse}(xs)) = \text{isEmpty}(xs)$.
List.getElem?_reverse' theorem
: ∀ {l : List α} {i j}, i + j + 1 = length l → l.reverse[i]? = l[j]?
Full source
/-- Variant of `getElem?_reverse` with a hypothesis giving the linear relation between the indices. -/
theorem getElem?_reverse' : ∀ {l : List α} {i j}, i + j + 1 = length l →
    l.reverse[i]? = l[j]?
  | [], _, _, _ => rfl
  | a::l, i, 0, h => by simp [Nat.succ.injEq] at h; simp [h, getElem?_append_right, Nat.succ.injEq]
  | a::l, i, j+1, h => by
    have := Nat.succ.inj h; simp at this ⊢
    rw [getElem?_append_left, getElem?_reverse' this]
    rw [length_reverse, ← this]; apply Nat.lt_add_of_pos_right (Nat.succ_pos _)
Index Correspondence in Reversed List: $l.reverse[i]? = l[j]?$ when $i + j + 1 = |l|$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i + j + 1 = \text{length}(l)$, the optional indexing operation on the reversed list $l.reverse[i]?$ returns the same result as the optional indexing operation on the original list $l[j]?$.
List.getElem?_reverse theorem
{l : List α} {i} (h : i < length l) : l.reverse[i]? = l[l.length - 1 - i]?
Full source
@[simp]
theorem getElem?_reverse {l : List α} {i} (h : i < length l) :
    l.reverse[i]? = l[l.length - 1 - i]? :=
  getElem?_reverse' <| by
    rw [Nat.add_sub_of_le (Nat.le_sub_one_of_lt h),
      Nat.sub_add_cancel (Nat.lt_of_le_of_lt (Nat.zero_le _) h)]
Index Correspondence in Reversed List: $l.reverse[i]? = l[|l|-1-i]?$ for valid $i$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number index $i$ such that $i < \text{length}(l)$, the optional indexing operation on the reversed list $l.reverse[i]?$ returns the same result as the optional indexing operation on the original list $l$ at index $\text{length}(l) - 1 - i$. In other words, when $i$ is a valid index for $l.reverse$, we have: $$l.reverse[i]? = l[|l| - 1 - i]?$$ where $|l|$ denotes the length of $l$.
List.getElem_reverse theorem
{l : List α} {i} (h : i < l.reverse.length) : l.reverse[i] = l[l.length - 1 - i]'(Nat.sub_one_sub_lt_of_lt (by simpa using h))
Full source
@[simp]
theorem getElem_reverse {l : List α} {i} (h : i < l.reverse.length) :
    l.reverse[i] = l[l.length - 1 - i]'(Nat.sub_one_sub_lt_of_lt (by simpa using h)) := by
  apply Option.some.inj
  rw [← getElem?_eq_getElem, ← getElem?_eq_getElem]
  rw [getElem?_reverse (by simpa using h)]
Index Correspondence in Reversed List: $l^{\text{reverse}}[i] = l[|l|-1-i]$ for valid $i$
Informal description
For any list $l$ of elements of type $\alpha$ and natural number index $i$ such that $i < \text{length}(l^{\text{reverse}})$, the element at position $i$ in the reversed list $l^{\text{reverse}}[i]$ is equal to the element at position $\text{length}(l) - 1 - i$ in the original list $l$. In other words: $$l^{\text{reverse}}[i] = l[|l| - 1 - i]$$ where $|l|$ denotes the length of $l$ and $i$ is a valid index for the reversed list.
List.reverseAux_reverseAux_nil theorem
{as bs : List α} : reverseAux (reverseAux as bs) [] = reverseAux bs as
Full source
theorem reverseAux_reverseAux_nil {as bs : List α} : reverseAux (reverseAux as bs) [] = reverseAux bs as := by
  induction as generalizing bs with
  | nil => rfl
  | cons a as ih => simp [reverseAux, ih]
Double Reverse Auxiliary with Empty List Equals Direct Reverse Auxiliary
Informal description
For any two lists `as` and `bs` of elements of type `α`, applying the reverse auxiliary function twice - first to `as` and `bs`, then to the result and the empty list `[]` - is equal to applying the reverse auxiliary function directly to `bs` and `as`. In mathematical notation: $\text{reverseAux}(\text{reverseAux}(as, bs), []) = \text{reverseAux}(bs, as)$
List.reverse_reverse theorem
(as : List α) : as.reverse.reverse = as
Full source
@[simp] theorem reverse_reverse (as : List α) : as.reverse.reverse = as := by
  simp only [reverse]; rw [reverseAux_reverseAux_nil]; rfl
Double Reverse of a List Equals the Original List
Informal description
For any list $as$ of elements of type $\alpha$, reversing the list twice returns the original list, i.e., $(as^{\mathrm{reverse}})^{\mathrm{reverse}} = as$.
List.reverse_eq_iff theorem
{as bs : List α} : as.reverse = bs ↔ as = bs.reverse
Full source
theorem reverse_eq_iff {as bs : List α} : as.reverse = bs ↔ as = bs.reverse := by
  constructor <;> (rintro rfl; simp)
Reverse Equality Criterion: $as^{\mathrm{reverse}} = bs \leftrightarrow as = bs^{\mathrm{reverse}}$
Informal description
For any two lists $as$ and $bs$ of elements of type $\alpha$, the reverse of $as$ equals $bs$ if and only if $as$ equals the reverse of $bs$.
List.reverse_inj theorem
{xs ys : List α} : xs.reverse = ys.reverse ↔ xs = ys
Full source
@[simp] theorem reverse_inj {xs ys : List α} : xs.reverse = ys.reverse ↔ xs = ys := by
  simp [reverse_eq_iff]
Injectivity of List Reversal: $xs^{\mathrm{reverse}} = ys^{\mathrm{reverse}} \leftrightarrow xs = ys$
Informal description
For any two lists $xs$ and $ys$ of elements of type $\alpha$, the reverses of $xs$ and $ys$ are equal if and only if $xs$ and $ys$ themselves are equal. That is, $xs^{\mathrm{reverse}} = ys^{\mathrm{reverse}} \leftrightarrow xs = ys$.
List.reverse_eq_cons_iff theorem
{xs : List α} {a : α} {ys : List α} : xs.reverse = a :: ys ↔ xs = ys.reverse ++ [a]
Full source
@[simp] theorem reverse_eq_cons_iff {xs : List α} {a : α} {ys : List α} :
    xs.reverse = a :: ys ↔ xs = ys.reverse ++ [a] := by
  rw [reverse_eq_iff, reverse_cons]
Reverse-cons Equivalence for Lists: $xs^{\mathrm{reverse}} = a :: ys \leftrightarrow xs = ys^{\mathrm{reverse}} ++ [a]$
Informal description
For any list $xs$ of elements of type $\alpha$, an element $a \in \alpha$, and another list $ys$ of elements of type $\alpha$, the reverse of $xs$ equals the list obtained by prepending $a$ to $ys$ if and only if $xs$ equals the concatenation of the reverse of $ys$ with the singleton list $[a]$. In other words: $$xs^{\mathrm{reverse}} = a :: ys \leftrightarrow xs = ys^{\mathrm{reverse}} ++ [a]$$
List.reverse_eq_cons abbrev
Full source
@[deprecated reverse_eq_cons_iff (since := "2024-09-05")] abbrev reverse_eq_cons := @reverse_eq_cons_iff
Reverse-cons Equivalence for Lists: $xs^{\mathrm{reverse}} = a :: ys \leftrightarrow xs = ys^{\mathrm{reverse}} ++ [a]$
Informal description
For any list $xs$ of elements of type $\alpha$, an element $a \in \alpha$, and another list $ys$ of elements of type $\alpha$, the reverse of $xs$ equals the list obtained by prepending $a$ to $ys$ if and only if $xs$ equals the concatenation of the reverse of $ys$ with the singleton list $[a]$. In other words: $$xs^{\mathrm{reverse}} = a :: ys \leftrightarrow xs = ys^{\mathrm{reverse}} ++ [a]$$
List.getLast?_reverse theorem
{l : List α} : l.reverse.getLast? = l.head?
Full source
@[simp] theorem getLast?_reverse {l : List α} : l.reverse.getLast? = l.head? := by
  cases l <;> simp [getLast?_concat]
Last Element of Reversed List Equals First Element of Original List: $\text{getLast?}(l^{\mathrm{reverse}}) = \text{head?}(l)$
Informal description
For any list $l$ of elements of type $\alpha$, the optional last element of the reversed list $l^{\mathrm{reverse}}$ is equal to the optional first element of the original list $l$. In other words: $$\text{getLast?}(l^{\mathrm{reverse}}) = \text{head?}(l)$$
List.head?_reverse theorem
{l : List α} : l.reverse.head? = l.getLast?
Full source
@[simp] theorem head?_reverse {l : List α} : l.reverse.head? = l.getLast? := by
  rw [← getLast?_reverse, reverse_reverse]
First Element of Reversed List Equals Last Element of Original List: $\text{head?}(l^{\mathrm{reverse}}) = \text{getLast?}(l)$
Informal description
For any list $l$ of elements of type $\alpha$, the optional first element of the reversed list $l^{\mathrm{reverse}}$ is equal to the optional last element of the original list $l$. In other words: $$\text{head?}(l^{\mathrm{reverse}}) = \text{getLast?}(l)$$
List.getLast?_eq_head?_reverse theorem
{xs : List α} : xs.getLast? = xs.reverse.head?
Full source
theorem getLast?_eq_head?_reverse {xs : List α} : xs.getLast? = xs.reverse.head? := by
  simp
Last Element Equals First Element of Reversed List: $\text{getLast?}(xs) = \text{head?}(xs^{\text{rev}})$
Informal description
For any list $xs$ of elements of type $\alpha$, the optional last element of $xs$ is equal to the optional first element of the reversed list $xs^{\text{rev}}$. That is, $$ \text{getLast?}(xs) = \text{head?}(xs^{\text{rev}}). $$
List.head?_eq_getLast?_reverse theorem
{xs : List α} : xs.head? = xs.reverse.getLast?
Full source
theorem head?_eq_getLast?_reverse {xs : List α} : xs.head? = xs.reverse.getLast? := by
  simp
First Element Equals Last Element of Reversed List: $\text{head?}(xs) = \text{getLast?}(xs^{\text{rev}})$
Informal description
For any list $xs$ of elements of type $\alpha$, the optional first element of $xs$ is equal to the optional last element of the reversed list $xs^{\text{rev}}$. That is, $$ \text{head?}(xs) = \text{getLast?}(xs^{\text{rev}}). $$
List.mem_of_mem_getLast? theorem
{l : List α} {a : α} (h : a ∈ getLast? l) : a ∈ l
Full source
theorem mem_of_mem_getLast? {l : List α} {a : α} (h : a ∈ getLast? l) : a ∈ l := by
  rw [getLast?_eq_head?_reverse] at h
  rw [← mem_reverse]
  exact mem_of_mem_head? h
Membership in Optional Last Element Implies Membership in List
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, if $a$ is in the optional last element of $l$ (i.e., $a \in \text{getLast?}(l)$), then $a$ is a member of $l$ (i.e., $a \in l$).
List.map_reverse theorem
{f : α → β} {l : List α} : l.reverse.map f = (l.map f).reverse
Full source
@[simp] theorem map_reverse {f : α → β} {l : List α} : l.reverse.map f = (l.map f).reverse := by
  induction l <;> simp [*]
Map Commutes with List Reversal: $\text{map } f (l^{\text{rev}}) = (\text{map } f l)^{\text{rev}}$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the map of $f$ over the reverse of $l$ is equal to the reverse of the map of $f$ over $l$. That is, $$ \text{map } f (l^{\text{rev}}) = (\text{map } f l)^{\text{rev}}. $$
List.filter_reverse theorem
{p : α → Bool} {l : List α} : (l.reverse.filter p) = (l.filter p).reverse
Full source
@[simp] theorem filter_reverse {p : α → Bool} {l : List α} : (l.reverse.filter p) = (l.filter p).reverse := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [reverse_cons, filter_append, filter_cons, ih]
    split <;> simp_all
Filter Commutes with List Reversal: $\text{filter } p (l^{\text{rev}}) = (\text{filter } p l)^{\text{rev}}$
Informal description
For any predicate $p \colon \alpha \to \text{Bool}$ and any list $l$ of elements of type $\alpha$, filtering the reverse of $l$ with $p$ is equal to the reverse of filtering $l$ with $p$. That is, \[ \text{filter } p (l^{\text{rev}}) = (\text{filter } p l)^{\text{rev}} \] where $l^{\text{rev}}$ denotes the reverse of list $l$.
List.filterMap_reverse theorem
{f : α → Option β} {l : List α} : (l.reverse.filterMap f) = (l.filterMap f).reverse
Full source
@[simp] theorem filterMap_reverse {f : α → Option β} {l : List α} : (l.reverse.filterMap f) = (l.filterMap f).reverse := by
  induction l with
  | nil => simp
  | cons a l ih =>
    simp only [reverse_cons, filterMap_append, filterMap_cons, ih]
    split <;> simp_all
Reversing Commutes with `filterMap`: $\text{filterMap } f (l^{\text{rev}}) = (\text{filterMap } f l)^{\text{rev}}$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any list $l : \text{List } \alpha$, applying `filterMap f` to the reverse of $l$ is equal to reversing the result of applying `filterMap f` to $l$. That is, $$\text{filterMap } f (l^{\text{rev}}) = (\text{filterMap } f l)^{\text{rev}}$$ where $l^{\text{rev}}$ denotes the reverse of list $l$.
List.reverse_append theorem
{as bs : List α} : (as ++ bs).reverse = bs.reverse ++ as.reverse
Full source
@[simp] theorem reverse_append {as bs : List α} : (as ++ bs).reverse = bs.reverse ++ as.reverse := by
  induction as <;> simp_all
Reverse of List Concatenation: $(as \mathbin{+\!\!+} bs).\text{reverse} = bs.\text{reverse} \mathbin{+\!\!+} as.\text{reverse}$
Informal description
For any two lists `as` and `bs` of elements of type `α`, the reverse of their concatenation `as ++ bs` is equal to the concatenation of the reverses of `bs` and `as`, i.e., $(as \mathbin{+\!\!+} bs).\text{reverse} = bs.\text{reverse} \mathbin{+\!\!+} as.\text{reverse}$.
List.reverse_eq_append_iff theorem
{xs ys zs : List α} : xs.reverse = ys ++ zs ↔ xs = zs.reverse ++ ys.reverse
Full source
@[simp] theorem reverse_eq_append_iff {xs ys zs : List α} :
    xs.reverse = ys ++ zs ↔ xs = zs.reverse ++ ys.reverse := by
  rw [reverse_eq_iff, reverse_append]
Reverse-Concatenation Equivalence: $xs^{\mathrm{rev}} = ys \mathbin{+\!\!+} zs \leftrightarrow xs = zs^{\mathrm{rev}} \mathbin{+\!\!+} ys^{\mathrm{rev}}$
Informal description
For any lists $xs$, $ys$, and $zs$ of elements of type $\alpha$, the reverse of $xs$ equals the concatenation of $ys$ and $zs$ if and only if $xs$ equals the concatenation of the reverse of $zs$ and the reverse of $ys$. That is, $$xs^{\mathrm{reverse}} = ys \mathbin{+\!\!+} zs \leftrightarrow xs = zs^{\mathrm{reverse}} \mathbin{+\!\!+} ys^{\mathrm{reverse}}$$
List.reverse_eq_append abbrev
Full source
@[deprecated reverse_eq_append_iff (since := "2024-09-05")] abbrev reverse_eq_append := @reverse_eq_append_iff
Reverse-Concatenation Equivalence: $xs^{\text{rev}} = ys \mathbin{+\!\!+} zs \leftrightarrow xs = zs^{\text{rev}} \mathbin{+\!\!+} ys^{\text{rev}}$
Informal description
For any lists $xs$, $ys$, and $zs$ of elements of type $\alpha$, the reverse of $xs$ equals the concatenation of $ys$ and $zs$ if and only if $xs$ equals the concatenation of the reverse of $zs$ and the reverse of $ys$. That is, $$xs^{\text{reverse}} = ys \mathbin{+\!\!+} zs \leftrightarrow xs = zs^{\text{reverse}} \mathbin{+\!\!+} ys^{\text{reverse}}.$$
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
Reverse of List Concatenation with Singleton: $(l \mathbin{+\!\!+} [a]).\text{reverse} = a :: l.\text{reverse}$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \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$, i.e., $(l \mathbin{+\!\!+} [a]).\text{reverse} = a :: l.\text{reverse}$.
List.reverse_eq_concat theorem
{xs ys : List α} {a : α} : xs.reverse = ys ++ [a] ↔ xs = a :: ys.reverse
Full source
theorem reverse_eq_concat {xs ys : List α} {a : α} :
    xs.reverse = ys ++ [a] ↔ xs = a :: ys.reverse := by
  rw [reverse_eq_iff, reverse_concat]
Reverse-Concatenation Equivalence: $xs^{\text{rev}} = ys \mathbin{+\!\!+} [a] \leftrightarrow xs = a :: ys^{\text{rev}}$
Informal description
For any lists $xs$ and $ys$ of elements of type $\alpha$ and any element $a \in \alpha$, the reverse of $xs$ equals the concatenation of $ys$ with the singleton list $[a]$ if and only if $xs$ equals the list obtained by prepending $a$ to the reverse of $ys$, i.e., $$ xs^{\text{reverse}} = ys \mathbin{+\!\!+} [a] \leftrightarrow xs = a :: ys^{\text{reverse}}. $$
List.reverse_flatten theorem
{L : List (List α)} : L.flatten.reverse = (L.map reverse).reverse.flatten
Full source
/-- Reversing a flatten is the same as reversing the order of parts and reversing all parts. -/
theorem reverse_flatten {L : List (List α)} :
    L.flatten.reverse = (L.map reverse).reverse.flatten := by
  induction L <;> simp_all
Reverse of Flattened List Equals Flattened Reverse of Reversed Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, the reverse of the flattened list $\text{flatten}(L)$ is equal to the flattened list obtained by first reversing the order of the sublists in $L$ and then reversing each sublist individually, i.e., $$(\text{flatten}(L))^{\text{rev}} = \text{flatten}\big((\text{map}(\text{rev}, L))^{\text{rev}}\big).$$
List.flatten_reverse theorem
{L : List (List α)} : L.reverse.flatten = (L.map reverse).flatten.reverse
Full source
/-- Flattening a reverse is the same as reversing all parts and reversing the flattened result. -/
theorem flatten_reverse {L : List (List α)} :
    L.reverse.flatten = (L.map reverse).flatten.reverse := by
  induction L <;> simp_all
Flattening Reversed List Equals Reversed Flattening of Reversed Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, flattening the reversed list $L^{\text{rev}}$ is equal to reversing the flattened list obtained by first reversing each sublist in $L$, i.e., $$ \text{flatten}(L^{\text{rev}}) = (\text{flatten}(\text{map}(\text{rev}, L)))^{\text{rev}}. $$
List.reverse_flatMap theorem
{β} {l : List α} {f : α → List β} : (l.flatMap f).reverse = l.reverse.flatMap (reverse ∘ f)
Full source
theorem reverse_flatMap {β} {l : List α} {f : α → List β} : (l.flatMap f).reverse = l.reverse.flatMap (reversereverse ∘ f) := by
  induction l <;> simp_all
Reverse of flatMap Equals flatMap of Reverse with Composed Reverse Function
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List} \beta$, the reverse of the flatMap operation satisfies: \[ \text{reverse}(l.\text{flatMap} f) = \text{reverse}(l).\text{flatMap} (\text{reverse} \circ f) \] where $\circ$ denotes function composition.
List.flatMap_reverse theorem
{β} {l : List α} {f : α → List β} : (l.reverse.flatMap f) = (l.flatMap (reverse ∘ f)).reverse
Full source
theorem flatMap_reverse {β} {l : List α} {f : α → List β} : (l.reverse.flatMap f) = (l.flatMap (reversereverse ∘ f)).reverse := by
  induction l <;> simp_all
Reverse and flatMap Commutation: $\text{flatMap} f (l^{\text{reverse}}) = (\text{flatMap} (\text{reverse} \circ f) l)^{\text{reverse}}$
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List} \beta$, the flatMap operation applied to the reverse of $l$ satisfies: \[ \text{flatMap} f (l^{\text{reverse}}) = (\text{flatMap} (\text{reverse} \circ f) l)^{\text{reverse}} \] where $\circ$ denotes function composition.
List.reverseAux_eq theorem
{as bs : List α} : reverseAux as bs = reverse as ++ bs
Full source
@[simp] theorem reverseAux_eq {as bs : List α} : reverseAux as bs = reverse as ++ bs :=
  reverseAux_eq_append ..
Reverse Auxiliary Function Equals Reverse Concatenation
Informal description
For any two lists `as` and `bs` of elements of type `α`, the auxiliary reverse operation `reverseAux as bs` is equal to the concatenation of the reverse of `as` with `bs`, i.e., $\text{reverseAux}(as, bs) = \text{reverse}(as) ++ bs$.
List.reverse_replicate theorem
{n : Nat} {a : α} : reverse (replicate n a) = replicate n a
Full source
@[simp] theorem reverse_replicate {n : Nat} {a : α} : reverse (replicate n a) = replicate n a :=
  eq_replicate_iff.2
    ⟨by rw [length_reverse, length_replicate],
     fun _ h => eq_of_mem_replicate (mem_reverse.1 h)⟩
Reversed Replicated List Equals Original: $\text{reverse}(\text{replicate}(n, a)) = \text{replicate}(n, a)$
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the reverse of the list obtained by replicating $a$ $n$ times is equal to the list obtained by replicating $a$ $n$ times, i.e., $\text{reverse}(\text{replicate}(n, a)) = \text{replicate}(n, a)$.
List.foldlM_append theorem
[Monad m] [LawfulMonad m] {f : β → α → m β} {b : β} {l l' : List α} : (l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f
Full source
@[simp] theorem foldlM_append [Monad m] [LawfulMonad m] {f : β → α → m β} {b : β} {l l' : List α} :
    (l ++ l').foldlM f b = l.foldlM f b >>= l'.foldlM f := by
  induction l generalizing b <;> simp [*]
Monadic Fold of Concatenated Lists: $\text{foldlM}_f b (l \mathbin{+\!\!+} l') = \text{foldlM}_f b l \mathbin{>\!\!>\!\!=} \text{foldlM}_f \cdot l'$
Informal description
Let $m$ be a monad that satisfies the monad laws, and let $f : \beta \to \alpha \to m \beta$ be a function. For any initial value $b \in \beta$ and lists $l, l'$ of elements of type $\alpha$, the monadic fold of the concatenated list $l ++ l'$ with function $f$ and initial value $b$ is equal to first folding $l$ with $f$ starting from $b$, and then using the result to fold $l'$ with $f$. In symbols: $$ \text{foldlM}_f b (l \mathbin{+\!\!+} l') = \text{foldlM}_f b l \mathbin{>\!\!>\!\!=} \text{foldlM}_f \cdot l' $$
List.foldrM_cons theorem
[Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α → β → m β} {b : β} : (a :: l).foldrM f b = l.foldrM f b >>= f a
Full source
@[simp] theorem foldrM_cons [Monad m] [LawfulMonad m] {a : α} {l : List α} {f : α → β → m β} {b : β} :
    (a :: l).foldrM f b = l.foldrM f b >>= f a := by
  simp only [foldrM]
  induction l <;> simp_all
Monadic Right Fold of Cons List: $\text{foldrM}_f b (a :: l) = \text{foldrM}_f b l \mathbin{>\!\!>\!\!=} f a$
Informal description
Let $m$ be a monad that satisfies the monad laws, and let $f : \alpha \to \beta \to m \beta$ be a function. For any element $a \in \alpha$, list $l$ of elements of type $\alpha$, and initial value $b \in \beta$, the monadic right fold of the list $a :: l$ with function $f$ and initial value $b$ is equal to first folding $l$ with $f$ starting from $b$, and then applying $f$ to $a$ and the result. In symbols: $$ \text{foldrM}_f b (a :: l) = \text{foldrM}_f b l \mathbin{>\!\!>\!\!=} f a $$
List.foldlM_pure theorem
[Monad m] [LawfulMonad m] {f : β → α → β} {b : β} {l : List α} : l.foldlM (m := m) (pure <| f · ·) b = pure (l.foldl f b)
Full source
@[simp] theorem foldlM_pure [Monad m] [LawfulMonad m] {f : β → α → β} {b : β} {l : List α} :
    l.foldlM (m := m) (pure <| f · ·) b = pure (l.foldl f b) := by
  induction l generalizing b <;> simp [*]
Monadic Left Fold of Pure Function Equals Pure of Standard Left Fold
Informal description
Let $m$ be a monad that satisfies the monad laws, and let $f : \beta \to \alpha \to \beta$ be a function. For any initial value $b \in \beta$ and list $l$ of elements of type $\alpha$, the monadic left fold of $l$ with the pure version of $f$ (i.e., $\text{pure} \circ f$) starting from $b$ is equal to the pure computation of the standard left fold of $l$ with $f$ starting from $b$. In symbols: $$ \text{foldlM}_m (\text{pure} \circ f) b l = \text{pure} (\text{foldl } f b l) $$
List.foldrM_pure theorem
[Monad m] [LawfulMonad m] {f : α → β → β} {b : β} {l : List α} : l.foldrM (m := m) (pure <| f · ·) b = pure (l.foldr f b)
Full source
@[simp] theorem foldrM_pure [Monad m] [LawfulMonad m] {f : α → β → β} {b : β} {l : List α} :
    l.foldrM (m := m) (pure <| f · ·) b = pure (l.foldr f b) := by
  induction l generalizing b <;> simp [*]
Monadic Right Fold of Pure Function Equals Pure of Standard Right Fold
Informal description
Let $m$ be a monad that satisfies the monad laws, and let $f : \alpha \to \beta \to \beta$ be a function. For any initial value $b \in \beta$ and list $l$ of elements of type $\alpha$, the monadic right fold of $l$ with the pure version of $f$ (i.e., $\text{pure} \circ f$) starting from $b$ is equal to the pure computation of the standard right fold of $l$ with $f$ starting from $b$. In symbols: $$ \text{foldrM}_m (\text{pure} \circ f) b l = \text{pure} (\text{foldr } f b l) $$
List.foldl_eq_foldlM theorem
{f : β → α → β} {b : β} {l : List α} : l.foldl f b = l.foldlM (m := Id) f b
Full source
theorem foldl_eq_foldlM {f : β → α → β} {b : β} {l : List α} :
    l.foldl f b = l.foldlM (m := Id) f b := by
  induction l generalizing b <;> simp [*, foldl]
Equality of Left Fold and Monadic Left Fold in Identity Monad
Informal description
For any binary operation $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and list $l$ of elements of type $\alpha$, the left fold of $l$ with $f$ and $b$ is equal to the monadic left fold of $l$ with $f$ and $b$ in the identity monad.
List.foldr_eq_foldrM theorem
{f : α → β → β} {b : β} {l : List α} : l.foldr f b = l.foldrM (m := Id) f b
Full source
theorem foldr_eq_foldrM {f : α → β → β} {b : β} {l : List α} :
    l.foldr f b = l.foldrM (m := Id) f b := by
  induction l <;> simp [*, foldr]
Equality of Right Fold and Monadic Right Fold in Identity Monad
Informal description
For any binary operation $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, and list $l$ of elements of type $\alpha$, the right fold of $l$ with $f$ and $b$ is equal to the monadic right fold of $l$ with $f$ and $b$ in the identity monad.
List.id_run_foldlM theorem
{f : β → α → Id β} {b : β} {l : List α} : Id.run (l.foldlM f b) = l.foldl f b
Full source
@[simp] theorem id_run_foldlM {f : β → α → Id β} {b : β} {l : List α} :
    Id.run (l.foldlM f b) = l.foldl f b := foldl_eq_foldlM.symm
Equality of Left Fold and Monadic Left Fold in Identity Monad via `Id.run`
Informal description
For any binary operation $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and list $l$ of elements of type $\alpha$, the result of running the monadic left fold of $l$ with $f$ and $b$ in the identity monad is equal to the left fold of $l$ with $f$ and $b$. In symbols: $$\text{Id.run}(\text{foldlM}_{\text{Id}}\ f\ b\ l) = \text{foldl}\ f\ b\ l$$
List.id_run_foldrM theorem
{f : α → β → Id β} {b : β} {l : List α} : Id.run (l.foldrM f b) = l.foldr f b
Full source
@[simp] theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
    Id.run (l.foldrM f b) = l.foldr f b := foldr_eq_foldrM.symm
Equality of Right Fold and Monadic Right Fold in Identity Monad via `Id.run`
Informal description
For any binary operation $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, and list $l$ of elements of type $\alpha$, the result of running the monadic right fold of $l$ with $f$ and $b$ in the identity monad is equal to the right fold of $l$ with $f$ and $b$. In symbols: $$\text{Id.run}(\text{foldrM}_{\text{Id}}\ f\ b\ l) = \text{foldr}\ f\ b\ l$$
List.foldlM_reverse theorem
[Monad m] {l : List α} {f : β → α → m β} {b : β} : l.reverse.foldlM f b = l.foldrM (fun x y => f y x) b
Full source
@[simp] theorem foldlM_reverse [Monad m] {l : List α} {f : β → α → m β} {b : β} :
    l.reverse.foldlM f b = l.foldrM (fun x y => f y x) b := rfl
Monadic Left Fold of Reversed List Equals Right Fold with Flipped Function
Informal description
For any monad $m$, list $l$ of elements of type $\alpha$, function $f : \beta \to \alpha \to m \beta$, and initial value $b : \beta$, the monadic left fold of the reversed list $l$ with $f$ and $b$ is equal to the monadic right fold of $l$ with the flipped function $\lambda x y, f y x$ and $b$. In symbols: $$\text{foldlM}_m\ f\ b\ l^{\text{rev}} = \text{foldrM}_m\ (\lambda x y, f y x)\ b\ l$$
List.foldrM_reverse theorem
[Monad m] {l : List α} {f : α → β → m β} {b : β} : l.reverse.foldrM f b = l.foldlM (fun x y => f y x) b
Full source
@[simp] theorem foldrM_reverse [Monad m] {l : List α} {f : α → β → m β} {b : β} :
    l.reverse.foldrM f b = l.foldlM (fun x y => f y x) b :=
  (foldlM_reverse ..).symm.trans <| by simp
Monadic Right Fold of Reversed List Equals Left Fold with Flipped Function
Informal description
For any monad $m$, list $l$ of elements of type $\alpha$, function $f : \alpha \to \beta \to m \beta$, and initial value $b : \beta$, the monadic right fold of the reversed list $l$ with $f$ and $b$ is equal to the monadic left fold of $l$ with the flipped function $\lambda x y, f y x$ and $b$. In symbols: $$\text{foldrM}_m\ f\ b\ l^{\text{rev}} = \text{foldlM}_m\ (\lambda x y, f y x)\ b\ l$$
List.foldr_cons_eq_append theorem
{l : List α} {f : α → β} {l' : List β} : l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l'
Full source
@[simp] theorem foldr_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
    l.foldr (fun x ys => f x :: ys) l' = l.map f ++ l' := by
  induction l <;> simp [*]
Right Fold with Function Application and Cons Equals Map and Append
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \beta$, and any list $l'$ of elements of type $\beta$, the right fold of $l$ with the function $\lambda x\ ys, f(x) :: ys$ and initial accumulator $l'$ is equal to the concatenation of the mapped list $l.map\ f$ and $l'$. In symbols: $$\text{foldr}\ (\lambda x\ ys, f(x) :: ys)\ l'\ l = (l.map\ f) \mathbin{+\!\!+} l'$$
List.foldr_cons_eq_append' theorem
{l l' : List β} : l.foldr cons l' = l ++ l'
Full source
/-- Variant of `foldr_cons_eq_append` specalized to `f = id`. -/
@[simp] theorem foldr_cons_eq_append' {l l' : List β} :
    l.foldr cons l' = l ++ l' := by
  induction l <;> simp [*]
Right Fold with Cons Equals Append
Informal description
For any lists $l$ and $l'$ of elements of type $\beta$, the right fold of $l$ with the `cons` operation and initial accumulator $l'$ is equal to the concatenation of $l$ and $l'$. In other words, $\text{foldr}(\text{cons}, l', l) = l \mathbin{+\!\!+} l'$.
List.foldl_flip_cons_eq_append theorem
{l : List α} {f : α → β} {l' : List β} : l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l'
Full source
@[simp] theorem foldl_flip_cons_eq_append {l : List α} {f : α → β} {l' : List β} :
    l.foldl (fun xs y => f y :: xs) l' = (l.map f).reverse ++ l' := by
  induction l generalizing l' <;> simp [*]
Left Fold with Cons Equals Reverse Map Append
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \beta$, and any list $l'$ of elements of type $\beta$, the left fold of $l$ with the operation $\lambda xs\ y, f(y) :: xs$ and initial accumulator $l'$ is equal to the concatenation of the reversed mapped list $(l.map\ f).reverse$ and $l'$. In symbols: $$\text{foldl}\ (\lambda xs\ y, f(y) :: xs)\ l'\ l = (l.map\ f).reverse \mathbin{+\!\!+} l'$$
List.foldr_append_eq_append theorem
{l : List α} {f : α → List β} {l' : List β} : l.foldr (f · ++ ·) l' = (l.map f).flatten ++ l'
Full source
@[simp] theorem foldr_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
    l.foldr (f · ++ ·) l' = (l.map f).flatten ++ l' := by
  induction l <;> simp [*]
Right Fold with Append Equals Flattened Map Append
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \text{List } \beta$, and any list $l'$ of elements of type $\beta$, the right fold of $l$ with the operation $(f \cdot \mathbin{+\!\!+} \cdot)$ and initial accumulator $l'$ is equal to the concatenation of the flattened list obtained by mapping $f$ over $l$ and $l'$. In other words, \[ \text{foldr} (f \cdot \mathbin{+\!\!+} \cdot) l' l = (\text{map } f l).\text{flatten} \mathbin{+\!\!+} l'. \]
List.foldl_append_eq_append theorem
{l : List α} {f : α → List β} {l' : List β} : l.foldl (· ++ f ·) l' = l' ++ (l.map f).flatten
Full source
@[simp] theorem foldl_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
    l.foldl (· ++ f ·) l' = l' ++ (l.map f).flatten := by
  induction l generalizing l'<;> simp [*]
Left Fold with Append Equals Concatenation with Flattened Map
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \text{List } \beta$, and any list $l'$ of elements of type $\beta$, the left fold of $l$ with the operation $(\cdot \mathbin{+\!\!+} f \cdot)$ and initial accumulator $l'$ is equal to the concatenation of $l'$ with the flattened list obtained by mapping $f$ over $l$. In other words, \[ \text{foldl}\ (\cdot \mathbin{+\!\!+} f \cdot)\ l'\ l = l' \mathbin{+\!\!+} (\text{map } f\ l).\text{flatten}. \]
List.foldr_flip_append_eq_append theorem
{l : List α} {f : α → List β} {l' : List β} : l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten
Full source
@[simp] theorem foldr_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
    l.foldr (fun x ys => ys ++ f x) l' = l' ++ (l.map f).reverse.flatten := by
  induction l generalizing l' <;> simp [*]
Right Fold with Flipped Append Equals Concatenation with Flattened Reverse Map
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \text{List } \beta$, and any list $l'$ of elements of type $\beta$, the right fold of $l$ with the operation $\lambda x\ ys \mapsto ys \mathbin{+\!\!+} f(x)$ and initial accumulator $l'$ is equal to the concatenation of $l'$ with the flattened reverse of the list obtained by mapping $f$ over $l$. In other words, \[ \text{foldr}\ (\lambda x\ ys \mapsto ys \mathbin{+\!\!+} f(x))\ l'\ l = l' \mathbin{+\!\!+} (\text{map } f\ l).\text{reverse}.\text{flatten}. \]
List.foldl_flip_append_eq_append theorem
{l : List α} {f : α → List β} {l' : List β} : l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l'
Full source
@[simp] theorem foldl_flip_append_eq_append {l : List α} {f : α → List β} {l' : List β} :
    l.foldl (fun xs y => f y ++ xs) l' = (l.map f).reverse.flatten ++ l' := by
  induction l generalizing l' <;> simp [*]
Left Fold with Flipped Append Equals Concatenation of Flattened Reverse Map and Initial List
Informal description
For any list $l$ of elements of type $\alpha$, any function $f : \alpha \to \text{List } \beta$, and any list $l'$ of elements of type $\beta$, the left fold of $l$ with the operation $\lambda xs\ y \mapsto f(y) \mathbin{+\!\!+} xs$ and initial accumulator $l'$ is equal to the concatenation of the flattened reverse of the list obtained by mapping $f$ over $l$ with $l'$. In other words, \[ \text{foldl}\ (\lambda xs\ y \mapsto f(y) \mathbin{+\!\!+} xs)\ l'\ l = (\text{map } f\ l).\text{reverse}.\text{flatten} \mathbin{+\!\!+} l'. \]
List.foldr_cons_nil theorem
{l : List α} : l.foldr cons [] = l
Full source
theorem foldr_cons_nil {l : List α} : l.foldr cons [] = l := by simp
Right Fold with Cons and Nil Preserves List Identity
Informal description
For any list $l$ of elements of type $\alpha$, the right fold of $l$ with the `cons` operation and initial accumulator `[]` (the empty list) is equal to $l$ itself. In other words, $\text{foldr}(\text{cons}, [], l) = l$.
List.foldr_self abbrev
Full source
@[deprecated foldr_cons_nil (since := "2024-09-04")] abbrev foldr_self := @foldr_cons_nil
Right Fold with Identity Preserves List
Informal description
For any list $l$ of elements of type $\alpha$, the right fold of $l$ with the identity operation and initial accumulator $l$ is equal to $l$ itself. In other words, $\text{foldr}(\text{id}, l, l) = l$.
List.foldl_map theorem
{f : β₁ → β₂} {g : α → β₂ → α} {l : List β₁} {init : α} : (l.map f).foldl g init = l.foldl (fun x y => g x (f y)) init
Full source
theorem foldl_map {f : β₁ → β₂} {g : α → β₂ → α} {l : List β₁} {init : α} :
    (l.map f).foldl g init = l.foldl (fun x y => g x (f y)) init := by
  induction l generalizing init <;> simp [*]
Left Fold of Mapped List Equals Fold with Composed Operation
Informal description
For any function $f : \beta_1 \to \beta_2$, any binary operation $g : \alpha \to \beta_2 \to \alpha$, any list $l$ of elements of type $\beta_1$, and any initial value $\text{init} : \alpha$, the left fold of the mapped list $(l.\text{map}\, f)$ with operation $g$ and initial value $\text{init}$ is equal to the left fold of the original list $l$ with operation $\lambda x y, g x (f y)$ and initial value $\text{init}$. In symbols: $$(\text{map}\, f\, l).\text{foldl}\, g\, \text{init} = l.\text{foldl}\, (\lambda x y, g x (f y))\, \text{init}$$
List.foldr_map theorem
{f : α₁ → α₂} {g : α₂ → β → β} {l : List α₁} {init : β} : (l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init
Full source
theorem foldr_map {f : α₁ → α₂} {g : α₂ → β → β} {l : List α₁} {init : β} :
    (l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
  induction l generalizing init <;> simp [*]
Right Fold of Mapped List Equals Fold with Composed Operation
Informal description
For any function $f : \alpha_1 \to \alpha_2$, any binary operation $g : \alpha_2 \to \beta \to \beta$, any list $l$ of elements of type $\alpha_1$, and any initial value $\text{init} : \beta$, the right fold of the mapped list $(l.\text{map} f)$ with operation $g$ and initial value $\text{init}$ is equal to the right fold of the original list $l$ with operation $\lambda x y, g (f x) y$ and initial value $\text{init}$. In symbols: $$(\text{map}\, f\, l).\text{foldr}\, g\, \text{init} = l.\text{foldr}\, (\lambda x y, g (f x) y)\, \text{init}$$
List.foldl_filterMap theorem
{f : α → Option β} {g : γ → β → γ} {l : List α} {init : γ} : (l.filterMap f).foldl g init = l.foldl (fun x y => match f y with | some b => g x b | none => x) init
Full source
theorem foldl_filterMap {f : α → Option β} {g : γ → β → γ} {l : List α} {init : γ} :
    (l.filterMap f).foldl g init = l.foldl (fun x y => match f y with | some b => g x b | none => x) init := by
  induction l generalizing init with
  | nil => rfl
  | cons a l ih =>
    simp only [filterMap_cons, foldl_cons]
    cases f a <;> simp [ih]
Left Fold of Filtered and Mapped List Equals Fold with Conditional Operation
Informal description
Let $f : \alpha \to \text{Option } \beta$ be a function, $g : \gamma \to \beta \to \gamma$ a binary operation, $l$ a list of elements of type $\alpha$, and $\text{init} : \gamma$ an initial value. Then the left fold of the filtered and mapped list $\text{filterMap}\, f\, l$ with operation $g$ and initial value $\text{init}$ is equal to the left fold of the original list $l$ with operation $\lambda x y, \text{match } f y \text{ with } | \text{some } b \Rightarrow g x b | \text{none} \Rightarrow x$ and initial value $\text{init}$. In symbols: $$(\text{filterMap}\, f\, l).\text{foldl}\, g\, \text{init} = l.\text{foldl}\, (\lambda x y, \text{match } f y \text{ with } | \text{some } b \Rightarrow g x b | \text{none} \Rightarrow x)\, \text{init}$$
List.foldr_filterMap theorem
{f : α → Option β} {g : β → γ → γ} {l : List α} {init : γ} : (l.filterMap f).foldr g init = l.foldr (fun x y => match f x with | some b => g b y | none => y) init
Full source
theorem foldr_filterMap {f : α → Option β} {g : β → γ → γ} {l : List α} {init : γ} :
    (l.filterMap f).foldr g init = l.foldr (fun x y => match f x with | some b => g b y | none => y) init := by
  induction l generalizing init with
  | nil => rfl
  | cons a l ih =>
    simp only [filterMap_cons, foldr_cons]
    cases f a <;> simp [ih]
Right Fold of Filtered and Mapped List Equals Fold with Conditional Operation
Informal description
For any function $f : \alpha \to \text{Option } \beta$, any binary operation $g : \beta \to \gamma \to \gamma$, any list $l$ of elements of type $\alpha$, and any initial value $\text{init} : \gamma$, the right fold of the filtered and mapped list $(l.\text{filterMap} f)$ with operation $g$ and initial value $\text{init}$ is equal to the right fold of the original list $l$ with operation $\lambda x y, \text{match } f x \text{ with } | \text{some } b \Rightarrow g b y | \text{none} \Rightarrow y$ and initial value $\text{init}$. In symbols: $$(\text{filterMap}\, f\, l).\text{foldr}\, g\, \text{init} = l.\text{foldr}\, (\lambda x y, \text{match } f x \text{ with } | \text{some } b \Rightarrow g b y | \text{none} \Rightarrow y)\, \text{init}$$
List.foldl_map_hom theorem
{g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {l : List α} (h : ∀ x y, f' (g x) (g y) = g (f x y)) : (l.map g).foldl f' (g a) = g (l.foldl f a)
Full source
theorem foldl_map_hom {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {l : List α}
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    (l.map g).foldl f' (g a) = g (l.foldl f a) := by
  induction l generalizing a
  · simp
  · simp [*, h]
Homomorphism Property of Left Fold Under Mapping
Informal description
Let $g : \alpha \to \beta$ be a function, $f : \alpha \to \alpha \to \alpha$ and $f' : \beta \to \beta \to \beta$ be binary operations, $a \in \alpha$ an initial value, and $l$ a list of elements of type $\alpha$. If for all $x, y \in \alpha$ the homomorphism condition $f'(g(x), g(y)) = g(f(x, y))$ holds, then the left fold of the mapped list $(l.\text{map}\, g)$ with operation $f'$ and initial value $g(a)$ equals $g$ applied to the left fold of the original list $l$ with operation $f$ and initial value $a$. In symbols: $$(l.\text{map}\, g).\text{foldl}\, f'\, (g(a)) = g(l.\text{foldl}\, f\, a)$$
List.foldl_map' abbrev
Full source
@[deprecated foldl_map_hom (since := "2025-01-20")] abbrev foldl_map' := @foldl_map_hom
Left Fold of Mapped List Equals Fold with Composed Operation
Informal description
Let $g : \alpha \to \beta$ be a function, $f : \beta \to \beta \to \beta$ a binary operation, $b : \beta$ an initial value, and $l$ a list of elements of type $\alpha$. Then the left fold of the mapped list $(l.\text{map}\, g)$ with operation $f$ and initial value $b$ equals the left fold of the original list $l$ with operation $f \circ g$ and initial value $b$. In symbols: $$(l.\text{map}\, g).\text{foldl}\, f\, b = l.\text{foldl}\, (f \circ g)\, b$$
List.foldr_map_hom theorem
{g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {l : List α} (h : ∀ x y, f' (g x) (g y) = g (f x y)) : (l.map g).foldr f' (g a) = g (l.foldr f a)
Full source
theorem foldr_map_hom {g : α → β} {f : α → α → α} {f' : β → β → β} {a : α} {l : List α}
    (h : ∀ x y, f' (g x) (g y) = g (f x y)) :
    (l.map g).foldr f' (g a) = g (l.foldr f a) := by
  induction l generalizing a
  · simp
  · simp [*, h]
Homomorphism Property of Right Fold Under Mapping
Informal description
Let $g : \alpha \to \beta$ be a function, $f : \alpha \to \alpha \to \alpha$ and $f' : \beta \to \beta \to \beta$ be binary operations, $a \in \alpha$ an initial value, and $l$ a list of elements of type $\alpha$. If for all $x, y \in \alpha$ the homomorphism condition $f'(g(x), g(y)) = g(f(x, y))$ holds, then the right fold of the mapped list $(l.map\ g)$ with operation $f'$ and initial value $g(a)$ equals $g$ applied to the right fold of the original list $l$ with operation $f$ and initial value $a$. In symbols: $$(l.map\ g).foldr\ f'\ (g(a)) = g(l.foldr\ f\ a)$$
List.foldr_map' abbrev
Full source
@[deprecated foldr_map_hom (since := "2025-01-20")] abbrev foldr_map' := @foldr_map_hom
Right Fold of Mapped List Equals Fold with Composed Operation
Informal description
Let $g : \alpha \to \beta$ be a function, $f : \beta \to \beta \to \beta$ a binary operation, $b : \beta$ an initial value, and $l$ a list of elements of type $\alpha$. Then the right fold of the mapped list $(l.map\ g)$ with operation $f$ and initial value $b$ equals the right fold of the original list $l$ with operation $f \circ g$ and initial value $b$. In symbols: $$(l.map\ g).foldr\ f\ b = l.foldr\ (f \circ g)\ b$$
List.foldrM_append theorem
[Monad m] [LawfulMonad m] {f : α → β → m β} {b : β} {l l' : List α} : (l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f
Full source
@[simp] theorem foldrM_append [Monad m] [LawfulMonad m] {f : α → β → m β} {b : β} {l l' : List α} :
    (l ++ l').foldrM f b = l'.foldrM f b >>= l.foldrM f := by
  induction l <;> simp [*]
Monadic Right Fold Distributes Over List Concatenation: $\text{foldrM}_f b (l ++ l') = \text{foldrM}_f b l' \mathbin{>\!\!>\!\!=} \text{foldrM}_f$
Informal description
Let $m$ be a monad that satisfies the monad laws, and let $f : \alpha \to \beta \to m \beta$ be a function. For any initial value $b \in \beta$ and lists $l, l'$ of elements of type $\alpha$, the monadic right fold of the concatenated list $l ++ l'$ with function $f$ and initial value $b$ is equal to first folding $l'$ with $f$ starting from $b$, and then folding $l$ with $f$ starting from the result of the first fold. In symbols: $$ \text{foldrM}_f b (l ++ l') = \text{foldrM}_f b l' \mathbin{>\!\!>\!\!=} \text{foldrM}_f $$
List.foldl_append theorem
{β : Type _} {f : β → α → β} {b : β} {l l' : List α} : (l ++ l').foldl f b = l'.foldl f (l.foldl f b)
Full source
@[simp] theorem foldl_append {β : Type _} {f : β → α → β} {b : β} {l l' : List α} :
    (l ++ l').foldl f b = l'.foldl f (l.foldl f b) := by simp [foldl_eq_foldlM]
Left Fold of Concatenated Lists: $(l \mathbin{+\!\!+} l').\text{foldl}\ f\ b = l'.\text{foldl}\ f\ (l.\text{foldl}\ f\ b)$
Informal description
For any type $\beta$, binary operation $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and lists $l, l'$ of elements of type $\alpha$, the left fold of the concatenated list $l \mathbin{+\!\!+} l'$ with operation $f$ and initial value $b$ is equal to the left fold of $l'$ with operation $f$ and initial value given by the left fold of $l$ with $f$ and $b$. In symbols: $$(l \mathbin{+\!\!+} l').\text{foldl}\ f\ b = l'.\text{foldl}\ f\ (l.\text{foldl}\ f\ b)$$
List.foldr_append theorem
{f : α → β → β} {b : β} {l l' : List α} : (l ++ l').foldr f b = l.foldr f (l'.foldr f b)
Full source
@[simp] theorem foldr_append {f : α → β → β} {b : β} {l l' : List α} :
    (l ++ l').foldr f b = l.foldr f (l'.foldr f b) := by simp [foldr_eq_foldrM]
Right Fold Distributes Over List Concatenation: $\text{foldr}_f b (l \mathbin{+\!\!+} l') = \text{foldr}_f (\text{foldr}_f b l') l$
Informal description
For any binary operation $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, and lists $l, l'$ of elements of type $\alpha$, the right fold of the concatenated list $l \mathbin{+\!\!+} l'$ with operation $f$ and initial value $b$ is equal to the right fold of $l$ with operation $f$ and initial value given by the right fold of $l'$ with $f$ and $b$. In symbols: $$(l \mathbin{+\!\!+} l').\text{foldr}\ f\ b = l.\text{foldr}\ f\ (l'.\text{foldr}\ f\ b)$$
List.foldl_flatten theorem
{f : β → α → β} {b : β} {L : List (List α)} : (flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b
Full source
theorem foldl_flatten {f : β → α → β} {b : β} {L : List (List α)} :
    (flatten L).foldl f b = L.foldl (fun b l => l.foldl f b) b := by
  induction L generalizing b <;> simp_all
Left Fold of Flattened List Equals Nested Left Fold
Informal description
For any binary operation $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and list of lists $L : \text{List}(\text{List } \alpha)$, the left fold of the flattened list $\text{flatten } L$ with operation $f$ and initial value $b$ is equal to the left fold of $L$ with the operation $\lambda b' \ l. \text{foldl } f \ b' \ l$ and initial value $b$. In symbols: $$\text{foldl } f \ b \ (\text{flatten } L) = \text{foldl } (\lambda b' \ l. \text{foldl } f \ b' \ l) \ b \ L$$
List.foldr_flatten theorem
{f : α → β → β} {b : β} {L : List (List α)} : (flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b
Full source
theorem foldr_flatten {f : α → β → β} {b : β} {L : List (List α)} :
    (flatten L).foldr f b = L.foldr (fun l b => l.foldr f b) b := by
  induction L <;> simp_all
Right Fold of Flattened List Equals Nested Right Fold
Informal description
For any binary operation $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, and list of lists $L : \text{List}(\text{List } \alpha)$, the right fold of the flattened list $\text{flatten } L$ with operation $f$ and initial value $b$ is equal to the right fold of $L$ with the operation $\lambda l \ b'. \text{foldr } f \ b' \ l$ and initial value $b$. In symbols: $$\text{foldr } f \ b \ (\text{flatten } L) = \text{foldr } (\lambda l \ b'. \text{foldr } f \ b' \ l) \ b \ L$$
List.foldl_reverse theorem
{l : List α} {f : β → α → β} {b : β} : l.reverse.foldl f b = l.foldr (fun x y => f y x) b
Full source
@[simp] theorem foldl_reverse {l : List α} {f : β → α → β} {b : β} :
    l.reverse.foldl f b = l.foldr (fun x y => f y x) b := by simp [foldl_eq_foldlM, foldr_eq_foldrM]
Left Fold of Reversed List Equals Right Fold with Flipped Operation
Informal description
For any list $l$ of elements of type $\alpha$, binary operation $f : \beta \to \alpha \to \beta$, and initial value $b \in \beta$, the left fold of the reversed list $l$ with $f$ and $b$ is equal to the right fold of the original list $l$ with the flipped operation $\lambda x y \mapsto f y x$ and $b$. In symbols: $$\text{foldl}\ f\ b\ (l.\text{reverse}) = \text{foldr}\ (\lambda x y \mapsto f y x)\ b\ l$$
List.foldr_reverse theorem
{l : List α} {f : α → β → β} {b : β} : l.reverse.foldr f b = l.foldl (fun x y => f y x) b
Full source
@[simp] theorem foldr_reverse {l : List α} {f : α → β → β} {b : β} :
    l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
  (foldl_reverse ..).symm.trans <| by simp
Right Fold of Reversed List Equals Left Fold with Flipped Operation
Informal description
For any list $l$ of elements of type $\alpha$, binary operation $f : \alpha \to \beta \to \beta$, and initial value $b \in \beta$, the right fold of the reversed list $l$ with $f$ and $b$ is equal to the left fold of the original list $l$ with the flipped operation $\lambda x y \mapsto f y x$ and $b$. In symbols: $$\text{foldr}\ f\ b\ (l^{\text{reverse}}) = \text{foldl}\ (\lambda x y \mapsto f y x)\ b\ l$$
List.foldl_eq_foldr_reverse theorem
{l : List α} {f : β → α → β} {b : β} : l.foldl f b = l.reverse.foldr (fun x y => f y x) b
Full source
theorem foldl_eq_foldr_reverse {l : List α} {f : β → α → β} {b : β} :
    l.foldl f b = l.reverse.foldr (fun x y => f y x) b := by simp
Left Fold Equals Right Fold of Reversed List with Flipped Operation
Informal description
For any list $l$ of elements of type $\alpha$, binary operation $f : \beta \to \alpha \to \beta$, and initial value $b \in \beta$, the left fold of $l$ with $f$ and $b$ is equal to the right fold of the reversed list $l$ with the flipped operation $\lambda x y \mapsto f y x$ and $b$. In symbols: $$\text{foldl}\ f\ b\ l = \text{foldr}\ (\lambda x y \mapsto f y x)\ b\ (l^{\text{reverse}})$$
List.foldr_eq_foldl_reverse theorem
{l : List α} {f : α → β → β} {b : β} : l.foldr f b = l.reverse.foldl (fun x y => f y x) b
Full source
theorem foldr_eq_foldl_reverse {l : List α} {f : α → β → β} {b : β} :
    l.foldr f b = l.reverse.foldl (fun x y => f y x) b := by simp
Right Fold Equals Left Fold of Reversed List with Flipped Operation
Informal description
For any list $l$ of elements of type $\alpha$, binary operation $f : \alpha \to \beta \to \beta$, and initial value $b \in \beta$, the right fold of $l$ with $f$ and $b$ is equal to the left fold of the reversed list $l$ with the flipped operation $\lambda x y \mapsto f y x$ and $b$. In symbols: $$\text{foldr}\ f\ b\ l = \text{foldl}\ (\lambda x y \mapsto f y x)\ b\ (l.\text{reverse})$$
List.foldl_assoc theorem
{op : α → α → α} [ha : Std.Associative op] : ∀ {l : List α} {a₁ a₂}, l.foldl op (op a₁ a₂) = op a₁ (l.foldl op a₂)
Full source
theorem foldl_assoc {op : α → α → α} [ha : Std.Associative op] :
    ∀ {l : List α} {a₁ a₂}, l.foldl op (op a₁ a₂) = op a₁ (l.foldl op a₂)
  | [], a₁, a₂ => rfl
  | a :: l, a₁, a₂ => by
    simp only [foldl_cons, ha.assoc]
    rw [foldl_assoc]
Associativity of Left Fold Operation on Lists
Informal description
Let $op : \alpha \to \alpha \to \alpha$ be an associative binary operation. For any list $l$ of elements of type $\alpha$ and any elements $a_1, a_2 \in \alpha$, the left fold of $l$ with operation $op$ and initial value $op(a_1, a_2)$ equals $op$ applied to $a_1$ and the left fold of $l$ with initial value $a_2$. In symbols: $$ \text{foldl}(op, op(a_1, a_2), l) = op(a_1, \text{foldl}(op, a_2, l)) $$
List.foldr_assoc theorem
{op : α → α → α} [ha : Std.Associative op] : ∀ {l : List α} {a₁ a₂}, l.foldr op (op a₁ a₂) = op (l.foldr op a₁) a₂
Full source
theorem foldr_assoc {op : α → α → α} [ha : Std.Associative op] :
    ∀ {l : List α} {a₁ a₂}, l.foldr op (op a₁ a₂) = op (l.foldr op a₁) a₂
  | [], a₁, a₂ => rfl
  | a :: l, a₁, a₂ => by
    simp only [foldr_cons, ha.assoc]
    rw [foldr_assoc]
Associativity of Right Fold Operation on Lists
Informal description
Let $op : \alpha \to \alpha \to \alpha$ be an associative binary operation. For any list $l$ of elements of type $\alpha$ and any elements $a_1, a_2 \in \alpha$, the right fold of $l$ with operation $op$ and initial value $op(a_1, a_2)$ equals $op$ applied to the right fold of $l$ with initial value $a_1$ and the element $a_2$. In symbols: $$ \text{foldr}(op, op(a_1, a_2), l) = op(\text{foldr}(op, a_1, l), a_2) $$
List.foldl_hom theorem
(f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {l : List β} {init : α₁} (H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init)
Full source
theorem foldl_hom (f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {l : List β} {init : α₁}
    (H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init) := by
  induction l generalizing init <;> simp [*, H]
Homomorphism Property of Left Fold on Lists
Informal description
Let $f : \alpha_1 \to \alpha_2$ be a function, and let $g_1 : \alpha_1 \to \beta \to \alpha_1$ and $g_2 : \alpha_2 \to \beta \to \alpha_2$ be binary operations. For any list $l$ of elements of type $\beta$ and initial value $\text{init} \in \alpha_1$, if the operations satisfy the homomorphism condition $g_2(f(x), y) = f(g_1(x, y))$ for all $x \in \alpha_1$ and $y \in \beta$, then the left fold of $l$ with $g_2$ and initial value $f(\text{init})$ equals $f$ applied to the left fold of $l$ with $g_1$ and initial value $\text{init}$. In symbols: $$ \text{foldl}(g_2, f(\text{init}), l) = f(\text{foldl}(g_1, \text{init}, l)) $$
List.foldr_hom theorem
(f : β₁ → β₂) {g₁ : α → β₁ → β₁} {g₂ : α → β₂ → β₂} {l : List α} {init : β₁} (H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init)
Full source
theorem foldr_hom (f : β₁ → β₂) {g₁ : α → β₁ → β₁} {g₂ : α → β₂ → β₂} {l : List α} {init : β₁}
    (H : ∀ x y, g₂ x (f y) = f (g₁ x y)) : l.foldr g₂ (f init) = f (l.foldr g₁ init) := by
  induction l <;> simp [*, H]
Homomorphism Property of Right Fold on Lists
Informal description
Let $f : \beta_1 \to \beta_2$ be a function, and let $g_1 : \alpha \to \beta_1 \to \beta_1$ and $g_2 : \alpha \to \beta_2 \to \beta_2$ be binary operations. For any list $l$ of elements of type $\alpha$ and initial value $\text{init} \in \beta_1$, if the operations satisfy the homomorphism condition $g_2(x, f(y)) = f(g_1(x, y))$ for all $x \in \alpha$ and $y \in \beta_1$, then the right fold of $l$ with $g_2$ and initial value $f(\text{init})$ equals $f$ applied to the right fold of $l$ with $g_1$ and initial value $\text{init}$. In symbols: $$ \text{foldr}(g_2, f(\text{init}), l) = f(\text{foldr}(g_1, \text{init}, l)) $$
List.foldlRecOn definition
{motive : β → Sort _} : ∀ (l : List α) (op : β → α → β) {b : β} (_ : motive b) (_ : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ l), motive (op b a)), motive (List.foldl op b l)
Full source
/--
A reasoning principle for proving propositions about the result of `List.foldl` by establishing an
invariant that is true for the initial data and preserved by the operation being folded.

Because the motive can return a type in any sort, this function may be used to construct data as
well as to prove propositions.

Example:
```lean example
example {xs : List Nat} : xs.foldl (· + ·) 1 > 0 := by
  apply List.foldlRecOn
  . show 0 < 1; trivial
  . show ∀ (b : Nat), 0 < b → ∀ (a : Nat), a ∈ xs → 0 < b + a
    intros; omega
```
-/
def foldlRecOn {motive : β → Sort _} : ∀ (l : List α) (op : β → α → β) {b : β} (_ : motive b)
    (_ : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ l), motive (op b a)), motive (List.foldl op b l)
  | [], _, _, hb, _ => hb
  | hd :: tl, op, b, hb, hl =>
    foldlRecOn tl op (hl b hb hd mem_cons_self)
      fun y hy x hx => hl y hy x (mem_cons_of_mem hd hx)
Recursion principle for left fold over a list
Informal description
Given a list $l : \text{List } \alpha$, a binary operation $\text{op} : \beta \to \alpha \to \beta$, an initial value $b : \beta$ with a property $\text{motive } b$, and a preservation property stating that for any $b' : \beta$ with $\text{motive } b'$ and any $a \in l$, the result $\text{op } b' a$ also satisfies $\text{motive}$, then the result of the left fold $\text{foldl op b l}$ satisfies $\text{motive}$. This principle allows proving properties about the result of a left fold by establishing an invariant that holds initially and is preserved by each operation. The motive can be any type, enabling both proofs and constructions.
List.foldlRecOn_nil theorem
{motive : β → Sort _} {op : β → α → β} (hb : motive b) (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ []), motive (op b a)) : foldlRecOn [] op hb hl = hb
Full source
@[simp] theorem foldlRecOn_nil {motive : β → Sort _} {op : β → α → β} (hb : motive b)
    (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ []), motive (op b a)) :
    foldlRecOn [] op hb hl = hb := rfl
Left Fold Recursion on Empty List Yields Initial Proof
Informal description
Given a property $\text{motive} : \beta \to \text{Sort}$ and a binary operation $\text{op} : \beta \to \alpha \to \beta$, if $\text{motive}$ holds for an initial value $b$ and is preserved by $\text{op}$ for any element in the empty list, then the result of applying the left fold recursion principle to the empty list is equal to the initial proof $hb$ of $\text{motive } b$. In symbols: $$ \text{foldlRecOn } [] \text{ op } hb \ hl = hb $$
List.foldlRecOn_cons theorem
{motive : β → Sort _} {op : β → α → β} (hb : motive b) (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ x :: l), motive (op b a)) : foldlRecOn (x :: l) op hb hl = foldlRecOn l op (hl b hb x mem_cons_self) (fun b c a m => hl b c a (mem_cons_of_mem x m))
Full source
@[simp] theorem foldlRecOn_cons {motive : β → Sort _} {op : β → α → β} (hb : motive b)
    (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ x :: l), motive (op b a)) :
    foldlRecOn (x :: l) op hb hl =
      foldlRecOn l op (hl b hb x mem_cons_self)
        (fun b c a m => hl b c a (mem_cons_of_mem x m)) :=
  rfl
Recursion Principle for Left Fold on Non-Empty List
Informal description
Given a property $\text{motive} : \beta \to \text{Sort}\ \_$, a binary operation $\text{op} : \beta \to \alpha \to \beta$, an initial value $b : \beta$ satisfying $\text{motive}\ b$, and a step function $\text{hl}$ that preserves the motive for elements in the list $x :: l$, the recursion principle for left fold on the list $x :: l$ reduces to applying the recursion principle on $l$ with: 1. The new initial value $\text{op}\ b\ x$ (which satisfies $\text{motive}$ by $\text{hl}\ b\ \text{hb}\ x\ \text{mem\_cons\_self}$) 2. A modified step function that preserves the motive for elements in $l$ via $\text{mem\_cons\_of\_mem}\ x$
List.foldrRecOn definition
{motive : β → Sort _} : ∀ (l : List α) (op : α → β → β) {b : β} (_ : motive b) (_ : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ l), motive (op a b)), motive (List.foldr op b l)
Full source
/--
A reasoning principle for proving propositions about the result of `List.foldr` by establishing an
invariant that is true for the initial data and preserved by the operation being folded.

Because the motive can return a type in any sort, this function may be used to construct data as
well as to prove propositions.

Example:
```lean example
example {xs : List Nat} : xs.foldr (· + ·) 1 > 0 := by
  apply List.foldrRecOn
  . show 0 < 1; trivial
  . show ∀ (b : Nat), 0 < b → ∀ (a : Nat), a ∈ xs → 0 < a + b
    intros; omega
```
-/
def foldrRecOn {motive : β → Sort _} : ∀ (l : List α) (op : α → β → β) {b : β} (_ : motive b)
    (_ : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ l), motive (op a b)), motive (List.foldr op b l)
  | nil, _, _, hb, _ => hb
  | x :: l, op, b, hb, hl =>
    hl (foldr op b l)
      (foldrRecOn l op hb fun b c a m => hl b c a (mem_cons_of_mem x m)) x mem_cons_self
Recursion principle for right fold on lists
Informal description
A recursion principle for proving properties about the result of a right fold operation on a list. Given a list $l : \text{List } \alpha$, a binary operation $\text{op} : \alpha \to \beta \to \beta$, an initial value $b : \beta$ with a property $\text{motive } b$, and a step function that preserves the motive for each element in $l$, this principle proves that the result of $\text{foldr op } b\ l$ satisfies the motive. More precisely, to prove $\text{motive } (\text{foldr op } b\ l)$, it suffices to: 1. Show $\text{motive } b$ holds for the initial value 2. For any $b' : \beta$ where $\text{motive } b'$ holds and any $a \in l$, show $\text{motive } (\text{op } a\ b')$ holds This principle can be used both for proving propositions and constructing data, as the motive can return any type.
List.foldrRecOn_nil theorem
{motive : β → Sort _} {op : α → β → β} (hb : motive b) (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ []), motive (op a b)) : foldrRecOn [] op hb hl = hb
Full source
@[simp] theorem foldrRecOn_nil {motive : β → Sort _} {op : α → β → β} (hb : motive b)
    (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ []), motive (op a b)) :
    foldrRecOn [] op hb hl = hb := rfl
Recursion Principle for Right Fold on Empty List Yields Initial Motive
Informal description
For any type $\beta$ with a property $\text{motive} : \beta \to \text{Sort}\ \_$, binary operation $\text{op} : \alpha \to \beta \to \beta$, initial value $b : \beta$ satisfying $\text{motive}\ b$, and step function $\text{hl}$ that preserves the motive for elements in the empty list, the recursion principle for right fold on the empty list reduces to the proof of the initial motive $\text{hb}$. In other words, when applying the fold recursion principle to the empty list, the result is simply the initial proof $\text{hb}$ of $\text{motive}\ b$.
List.foldrRecOn_cons theorem
{motive : β → Sort _} {op : α → β → β} (hb : motive b) (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ x :: l), motive (op a b)) : foldrRecOn (x :: l) op hb hl = hl _ (foldrRecOn l op hb fun b c a m => hl b c a (mem_cons_of_mem x m)) x mem_cons_self
Full source
@[simp] theorem foldrRecOn_cons {motive : β → Sort _} {op : α → β → β} (hb : motive b)
    (hl : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ x :: l), motive (op a b)) :
    foldrRecOn (x :: l) op hb hl =
      hl _ (foldrRecOn l op hb fun b c a m => hl b c a (mem_cons_of_mem x m))
        x mem_cons_self :=
  rfl
Recursion Principle for Right Fold on Non-Empty Lists
Informal description
Given a list $x :: l$ (a list with head $x$ and tail $l$), a binary operation $\text{op} : \alpha \to \beta \to \beta$, an initial value $b : \beta$ with a property $\text{motive } b$, and a step function $\text{hl}$ that preserves the motive for each element in $x :: l$, the recursion principle for right fold satisfies: \[ \text{foldrRecOn } (x :: l)\ \text{op } \text{hb } \text{hl} = \text{hl } b'\ (\text{foldrRecOn } l\ \text{op } \text{hb } \text{hl}')\ x\ \text{mem\_cons\_self} \] where: - $b'$ is the result of the recursive call on $l$ - $\text{hl}'$ is the modified step function that handles elements in $l$ by proving they are also in $x :: l$ via $\text{mem\_cons\_of\_mem}$ - $\text{mem\_cons\_self}$ proves $x \in x :: l$
List.foldl_rel theorem
{l : List α} {f g : β → α → β} {a b : β} {r : β → β → Prop} (h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) : r (l.foldl (fun acc a => f acc a) a) (l.foldl (fun acc a => g acc a) b)
Full source
/--
We can prove that two folds over the same list are related (by some arbitrary relation)
if we know that the initial elements are related and the folding function, for each element of the list,
preserves the relation.
-/
theorem foldl_rel {l : List α} {f g : β → α → β} {a b : β} {r : β → β → Prop}
    (h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f c a) (g c' a)) :
    r (l.foldl (fun acc a => f acc a) a) (l.foldl (fun acc a => g acc a) b) := by
  induction l generalizing a b with
  | nil => simp_all
  | cons a l ih =>
    simp only [foldl_cons]
    apply ih
    · simp_all
    · exact fun a m c c' h => h' _ (by simp_all) _ _ h
Relation Preservation under Left Folding
Informal description
Let $l$ be a list of elements of type $\alpha$, and let $f, g : \beta \to \alpha \to \beta$ be two folding functions. Given an initial relation $r$ between elements of $\beta$ such that $r(a, b)$ holds for some $a, b \in \beta$, and for every element $x \in l$ and any $c, c' \in \beta$ with $r(c, c')$, the relation $r(f(c, x), g(c', x))$ holds, then the relation $r$ holds between the left folds of $l$ with $f$ and $g$ starting from $a$ and $b$ respectively. That is, $r(\text{foldl}(f, a, l), \text{foldl}(g, b, l))$.
List.foldr_rel theorem
{l : List α} {f g : α → β → β} {a b : β} {r : β → β → Prop} (h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f a c) (g a c')) : r (l.foldr (fun a acc => f a acc) a) (l.foldr (fun a acc => g a acc) b)
Full source
/--
We can prove that two folds over the same list are related (by some arbitrary relation)
if we know that the initial elements are related and the folding function, for each element of the list,
preserves the relation.
-/
theorem foldr_rel {l : List α} {f g : α → β → β} {a b : β} {r : β → β → Prop}
    (h : r a b) (h' : ∀ (a : α), a ∈ l → ∀ (c c' : β), r c c' → r (f a c) (g a c')) :
    r (l.foldr (fun a acc => f a acc) a) (l.foldr (fun a acc => g a acc) b) := by
  induction l generalizing a b with
  | nil => simp_all
  | cons a l ih =>
    simp only [foldr_cons]
    apply h'
    · simp
    · exact ih h fun a m c c' h => h' _ (by simp_all) _ _ h
Relation Preservation under Right Folding
Informal description
Let $l$ be a list of elements of type $\alpha$, and let $f, g : \alpha \to \beta \to \beta$ be two folding functions. Given an initial relation $r$ between elements of $\beta$ such that $r(a, b)$ holds for some $a, b \in \beta$, and for every element $x \in l$ and any $c, c' \in \beta$ with $r(c, c')$, the relation $r(f(x, c), g(x, c'))$ holds, then the relation $r$ holds between the right folds of $l$ with $f$ and $g$ starting from $a$ and $b$ respectively. That is, $r(\text{foldr}(f, a, l), \text{foldr}(g, b, l))$.
List.foldl_add_const theorem
{l : List α} {a b : Nat} : l.foldl (fun x _ => x + a) b = b + a * l.length
Full source
@[simp] theorem foldl_add_const {l : List α} {a b : Nat} :
    l.foldl (fun x _ => x + a) b = b + a * l.length := by
  induction l generalizing b with
  | nil => simp
  | cons y l ih =>
    simp only [foldl_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc,
      Nat.add_comm a]
Left Fold with Constant Addition: $\text{foldl} (\lambda x \_. x + a) b l = b + a \cdot \text{length}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $a$ and $b$, the left fold operation $\text{foldl}$ with the function $\lambda x \_. x + a$ and initial value $b$ satisfies $\text{foldl} (\lambda x \_. x + a) b l = b + a \cdot \text{length}(l)$.
List.foldr_add_const theorem
{l : List α} {a b : Nat} : l.foldr (fun _ x => x + a) b = b + a * l.length
Full source
@[simp] theorem foldr_add_const {l : List α} {a b : Nat} :
    l.foldr (fun _ x => x + a) b = b + a * l.length := by
  induction l generalizing b with
  | nil => simp
  | cons y l ih =>
    simp only [foldr_cons, ih, length_cons, Nat.mul_add, Nat.mul_one, Nat.add_assoc]
Right Fold with Constant Addition: $\text{foldr} (\lambda \_ x \mapsto x + a) b l = b + a \cdot \text{length}(l)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural numbers $a$ and $b$, the right fold of $l$ with the function `(fun _ x => x + a)` starting from $b$ equals $b + a \cdot \text{length}(l)$.
List.head_reverse theorem
{l : List α} (h : l.reverse ≠ []) : l.reverse.head h = getLast l (by simp_all)
Full source
@[simp] theorem head_reverse {l : List α} (h : l.reverse ≠ []) :
    l.reverse.head h = getLast l (by simp_all) := by
  induction l with
  | nil => contradiction
  | cons a l ih =>
    simp only [reverse_cons]
    by_cases h' : l = []
    · simp_all
    · simp only [head_eq_iff_head?_eq_some, head?_reverse] at ih
      simp [ih, h, h', getLast_cons, head_eq_iff_head?_eq_some]
Head of Reversed List Equals Last Element: $\text{head}(l^{\mathrm{reverse}}) = \text{getLast}(l)$
Informal description
For any non-empty list $l$ of elements of type $\alpha$, the head of the reversed list $l^{\mathrm{reverse}}$ (with non-emptiness witness $h$) is equal to the last element of the original list $l$.
List.getLast_eq_head_reverse theorem
{l : List α} (h : l ≠ []) : l.getLast h = l.reverse.head (by simp_all)
Full source
theorem getLast_eq_head_reverse {l : List α} (h : l ≠ []) :
    l.getLast h = l.reverse.head (by simp_all) := by
  rw [← head_reverse]
Last Element Equals Head of Reversed List: $\text{getLast}(l) = \text{head}(l^{\mathrm{reverse}})$
Informal description
For any non-empty list $l$ of elements of type $\alpha$, the last element of $l$ (with non-emptiness witness $h$) is equal to the head of the reversed list $l^{\mathrm{reverse}}$.
List.getLast_eq_iff_getLast_eq_some abbrev
Full source
@[deprecated getLast_eq_iff_getLast?_eq_some (since := "2025-02-17")]
abbrev getLast_eq_iff_getLast_eq_some := @getLast_eq_iff_getLast?_eq_some
Equivalence of Last Element and Optional Last Element: $\text{getLast}\ xs\ h = a \leftrightarrow \text{getLast}?\ xs = \text{some}\ a$
Informal description
For any nonempty list $xs$ of elements of type $\alpha$ (with nonemptiness witness $h$), the last element $xs.\text{getLast}\ h$ is equal to $a$ if and only if the optional last element $xs.\text{getLast}?$ is equal to $\text{some}\ a$.
List.getLast?_eq_none_iff theorem
{xs : List α} : xs.getLast? = none ↔ xs = []
Full source
@[simp] theorem getLast?_eq_none_iff {xs : List α} : xs.getLast? = none ↔ xs = [] := by
  rw [getLast?_eq_head?_reverse, head?_eq_none_iff, reverse_eq_nil_iff]
Empty List Characterization via Last Element Option: $xs.\text{getLast}? = \text{none} \leftrightarrow xs = []$
Informal description
For any list $xs$ of elements of type $\alpha$, the optional last element $xs.\text{getLast}?$ is `none` if and only if $xs$ is the empty list. That is, $$ xs.\text{getLast}? = \text{none} \leftrightarrow xs = []. $$
List.getLast?_eq_some_iff theorem
{xs : List α} {a : α} : xs.getLast? = some a ↔ ∃ ys, xs = ys ++ [a]
Full source
theorem getLast?_eq_some_iff {xs : List α} {a : α} : xs.getLast? = some a ↔ ∃ ys, xs = ys ++ [a] := by
  rw [getLast?_eq_head?_reverse, head?_eq_some_iff]
  simp only [reverse_eq_cons_iff]
  exact ⟨fun ⟨ys, h⟩ => ⟨ys.reverse, by simpa using h⟩, fun ⟨ys, h⟩ => ⟨ys.reverse, by simpa using h⟩⟩
Characterization of Last Element: $\text{getLast?}(xs) = \text{some }a \leftrightarrow xs = ys \mathbin{+\!\!\!+} [a]$ for some $ys$
Informal description
For any list $xs$ of elements of type $\alpha$ and any element $a \in \alpha$, the optional last element of $xs$ equals `some a` if and only if there exists a list $ys$ such that $xs$ can be written as the concatenation of $ys$ and the singleton list $[a]$, i.e., $$ \text{getLast?}(xs) = \text{some }a \leftrightarrow \exists ys, xs = ys \mathbin{+\!\!\!+} [a]. $$
List.getLast?_isSome theorem
: l.getLast?.isSome ↔ l ≠ []
Full source
@[simp] theorem getLast?_isSome : l.getLast?.isSome ↔ l ≠ [] := by
  rw [getLast?_eq_head?_reverse, isSome_head?]
  simp
Non-Empty List Characterization via Last Option: $\text{isSome}(l.\text{getLast?}) \leftrightarrow l \neq []$
Informal description
For any list $l$ of elements of type $\alpha$, the optional last element of $l$ is `some` (i.e., `l.getLast?.isSome` is true) if and only if $l$ is not the empty list (i.e., $l \neq []$).
List.mem_of_getLast? theorem
{xs : List α} {a : α} (h : xs.getLast? = some a) : a ∈ xs
Full source
theorem mem_of_getLast? {xs : List α} {a : α} (h : xs.getLast? = some a) : a ∈ xs := by
  obtain ⟨ys, rfl⟩ := getLast?_eq_some_iff.1 h
  exact mem_concat_self
Membership from Last Element: $\text{getLast?}(xs) = \text{some }a \implies a \in xs$
Informal description
For any list $xs$ of elements of type $\alpha$ and any element $a \in \alpha$, if the optional last element of $xs$ is `some a` (i.e., $xs.\text{getLast?} = \text{some }a$), then $a$ is a member of $xs$ (i.e., $a \in xs$).
List.mem_of_getLast?_eq_some abbrev
Full source
@[deprecated mem_of_getLast? (since := "2024-10-21")] abbrev mem_of_getLast?_eq_some := @mem_of_getLast?
Membership from Last Element Option: $xs.\text{getLast?} = \text{some }a \implies a \in xs$
Informal description
For any list $xs$ of elements of type $\alpha$ and any element $a \in \alpha$, if the optional last element of $xs$ is equal to `some a` (i.e., $xs.\text{getLast?} = \text{some }a$), then $a$ is a member of $xs$ (i.e., $a \in xs$).
List.getLast_reverse theorem
{l : List α} (h : l.reverse ≠ []) : l.reverse.getLast h = l.head (by simp_all)
Full source
@[simp] theorem getLast_reverse {l : List α} (h : l.reverse ≠ []) :
    l.reverse.getLast h = l.head (by simp_all) := by
  simp [getLast_eq_head_reverse]
Last Element of Reversed List Equals Head of Original List: $\text{getLast}(l^{\mathrm{reverse}}) = \text{head}(l)$
Informal description
For any non-empty list $l$ of elements of type $\alpha$, the last element of the reversed list $l^{\mathrm{reverse}}$ (with non-emptiness witness $h$) is equal to the head of the original list $l$.
List.head_eq_getLast_reverse theorem
{l : List α} (h : l ≠ []) : l.head h = l.reverse.getLast (by simp_all)
Full source
theorem head_eq_getLast_reverse {l : List α} (h : l ≠ []) :
    l.head h = l.reverse.getLast (by simp_all) := by
  rw [← getLast_reverse]
Head Equals Last of Reverse: $\text{head}(l) = \text{getLast}(l^{\mathrm{reverse}})$
Informal description
For any non-empty list $l$ of elements of type $\alpha$, the head of $l$ (with non-emptiness witness $h$) is equal to the last element of the reversed list $l^{\mathrm{reverse}}$.
List.getLast_append_of_ne_nil theorem
{l : List α} (h₁) (h₂ : l' ≠ []) : (l ++ l').getLast h₁ = l'.getLast h₂
Full source
@[simp] theorem getLast_append_of_ne_nil {l : List α} (h₁) (h₂ : l' ≠ []) :
    (l ++ l').getLast h₁ = l'.getLast h₂ := by
  simp only [getLast_eq_head_reverse, reverse_append]
  rw [head_append_of_ne_nil]
Last Element of Concatenated List Equals Last Element of Second List When Non-Empty
Informal description
For any list $l$ of elements of type $\alpha$ and any non-empty list $l'$ of elements of type $\alpha$, the last element of the concatenated list $l \mathbin{+\!\!+} l'$ (with non-emptiness witness $h_1$) is equal to the last element of $l'$ (with non-emptiness witness $h_2$).
List.getLast_append theorem
{l : List α} (h : l ++ l' ≠ []) : (l ++ l').getLast h = if h' : l'.isEmpty then l.getLast (by simp_all [isEmpty_iff]) else l'.getLast (by simp_all [isEmpty_iff])
Full source
theorem getLast_append {l : List α} (h : l ++ l' ≠ []) :
    (l ++ l').getLast h =
      if h' : l'.isEmpty then
        l.getLast (by simp_all [isEmpty_iff])
      else
        l'.getLast (by simp_all [isEmpty_iff]) := by
  split <;> rename_i h'
  · simp only [isEmpty_iff] at h'
    subst h'
    simp
  · simp [isEmpty_iff] at h'
    simp [h']
Last Element of Concatenated List: $(\mathtt{l} \mathbin{+\!\!+} \mathtt{l'}).\mathtt{getLast} = \text{if } \mathtt{l'}.\mathtt{isEmpty} \text{ then } \mathtt{l}.\mathtt{getLast} \text{ else } \mathtt{l'}.\mathtt{getLast}$
Informal description
For any list $l$ of elements of type $\alpha$ and any list $l'$ such that the concatenated list $l \mathbin{+\!\!+} l'$ is non-empty, the last element of $l \mathbin{+\!\!+} l'$ is equal to the last element of $l$ if $l'$ is empty, and to the last element of $l'$ otherwise.
List.getLast_append_right theorem
{l : List α} (h : l' ≠ []) : (l ++ l').getLast (fun h => by simp_all) = l'.getLast h
Full source
theorem getLast_append_right {l : List α} (h : l' ≠ []) :
    (l ++ l').getLast (fun h => by simp_all) = l'.getLast h := by
  rw [getLast_append, dif_neg (by simp_all)]
Last Element of Concatenated List Equals Last Element of Second List When Non-Empty
Informal description
For any list $l$ of elements of type $\alpha$ and any non-empty list $l'$ of elements of type $\alpha$, the last element of the concatenated list $l \mathbin{+\!\!+} l'$ is equal to the last element of $l'$.
List.getLast_append_left theorem
{l : List α} (w : l ++ l' ≠ []) (h : l' = []) : (l ++ l').getLast w = l.getLast (by simp_all)
Full source
theorem getLast_append_left {l : List α} (w : l ++ l' ≠ []) (h : l' = []) :
    (l ++ l').getLast w = l.getLast (by simp_all) := by
  rw [getLast_append, dif_pos (by simp_all)]
Last Element of Concatenated List with Empty Second List
Informal description
For any list $l$ of elements of type $\alpha$ and any empty list $l'$ (i.e., $l' = []$), if the concatenated list $l \mathbin{+\!\!+} l'$ is non-empty, then the last element of $l \mathbin{+\!\!+} l'$ is equal to the last element of $l$.
List.getLast?_append theorem
{l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast?
Full source
@[simp] theorem getLast?_append {l l' : List α} : (l ++ l').getLast? = l'.getLast?.or l.getLast? := by
  simp [← head?_reverse]
Last Element of Concatenated List: $\text{getLast?}(l \mathbin{+\!\!+} l') = \text{getLast?}(l') \mathbin{\text{or}} \text{getLast?}(l)$
Informal description
For any two lists $l$ and $l'$ of elements of type $\alpha$, the last element of the concatenated list $l \mathbin{+\!\!+} l'$ (as an optional value) is equal to the first non-`none` value between $\text{getLast?}(l')$ and $\text{getLast?}(l)$. More precisely, $\text{getLast?}(l \mathbin{+\!\!+} l') = \text{getLast?}(l') \mathbin{\text{or}} \text{getLast?}(l)$.
List.getLast_filter_of_pos theorem
{p : α → Bool} {l : List α} (w : l ≠ []) (h : p (getLast l w) = true) : getLast (filter p l) (ne_nil_of_mem (mem_filter.2 ⟨getLast_mem w, h⟩)) = getLast l w
Full source
theorem getLast_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p (getLast l w) = true) :
    getLast (filter p l) (ne_nil_of_mem (mem_filter.2 ⟨getLast_mem w, h⟩)) = getLast l w := by
  simp only [getLast_eq_head_reverse, ← filter_reverse]
  rw [head_filter_of_pos]
  simp_all
Last Element Preservation Under Filtering When Predicate Holds
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and non-empty list $l$ of type $\alpha$, if $p$ holds for the last element of $l$ (i.e., $p(\text{getLast}(l, w)) = \text{true}$ where $w$ proves $l \neq []$), then the last element of the filtered list $\text{filter } p l$ equals the last element of $l$. That is: $$\text{getLast}(\text{filter } p l) = \text{getLast}(l)$$ where the non-emptiness condition for $\text{filter } p l$ is satisfied because: 1. $\text{getLast}(l, w) \in l$ (by $\text{getLast\_mem}$) 2. $p(\text{getLast}(l, w))$ holds (by $h$) 3. Thus $\text{getLast}(l, w) \in \text{filter } p l$ (by $\text{mem\_filter}$) 4. Therefore $\text{filter } p l \neq []$ (by $\text{ne\_nil\_of\_mem}$)
List.getLast_filterMap_of_eq_some theorem
{f : α → Option β} {l : List α} (w : l ≠ []) {b : β} (h : f (l.getLast w) = some b) : (filterMap f l).getLast (ne_nil_of_mem (mem_filterMap.2 ⟨_, getLast_mem w, h⟩)) = b
Full source
theorem getLast_filterMap_of_eq_some {f : α → Option β} {l : List α} (w : l ≠ []) {b : β} (h : f (l.getLast w) = some b) :
    (filterMap f l).getLast (ne_nil_of_mem (mem_filterMap.2 ⟨_, getLast_mem w, h⟩)) = b := by
  simp only [getLast_eq_head_reverse, ← filterMap_reverse]
  rw [head_filterMap_of_eq_some (by simp_all)]
  simp_all
Last Element of Filtered Map When Last Element Maps to Some Value: $\text{getLast}(\text{filterMap } f l) = b$ when $f(\text{getLast } l) = \text{some } b$
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and non-empty list $l : \text{List } \alpha$, if $f$ applied to the last element of $l$ equals $\text{some } b$ for some $b : \beta$, then the last element of the filtered map $\text{filterMap } f l$ is equal to $b$.
List.getLast?_flatMap theorem
{l : List α} {f : α → List β} : (l.flatMap f).getLast? = l.reverse.findSome? fun a => (f a).getLast?
Full source
theorem getLast?_flatMap {l : List α} {f : α → List β} :
    (l.flatMap f).getLast? = l.reverse.findSome? fun a => (f a).getLast? := by
  simp only [← head?_reverse, reverse_flatMap]
  rw [head?_flatMap]
  rfl
Last Element of FlatMap as Find-Some Operation on Last Elements of Reversed List
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List } \beta$, the last element of the flatMap operation applied to $l$ and $f$ (as an optional value) is equal to the first non-`none` result obtained by applying $\text{getLast?}$ to each $f(a)$ for $a$ in the reverse of $l$. In other words, $\text{getLast?}(\text{flatMap } f l) = \text{findSome? } (\lambda a \mapsto \text{getLast?}(f a)) (\text{reverse } l)$.
List.getLast?_flatten theorem
{L : List (List α)} : (flatten L).getLast? = L.reverse.findSome? fun l => l.getLast?
Full source
theorem getLast?_flatten {L : List (List α)} :
    (flatten L).getLast? = L.reverse.findSome? fun l => l.getLast? := by
  simp [← flatMap_id, getLast?_flatMap]
Last Element of Flattened List as Find-Some Operation on Last Elements of Reversed List
Informal description
For any list of lists $L$ of type $\text{List}(\text{List } \alpha)$, the last element of the flattened list (as an optional value) is equal to the first non-`none` result obtained by applying $\text{getLast?}$ to each list in the reverse of $L$. In other words, $\text{getLast?}(\text{flatten } L) = \text{findSome? } (\lambda l \mapsto \text{getLast?}(l)) (\text{reverse } L)$.
List.getLast?_replicate theorem
{a : α} {n : Nat} : (replicate n a).getLast? = if n = 0 then none else some a
Full source
theorem getLast?_replicate {a : α} {n : Nat} : (replicate n a).getLast? = if n = 0 then none else some a := by
  simp only [← head?_reverse, reverse_replicate, head?_replicate]
Last Element of Replicated List: $\text{getLast?}(\text{replicate}(n, a)) = \text{if } n = 0 \text{ then none else some } a$
Informal description
For any element $a$ of type $\alpha$ and natural number $n$, the last element of the list obtained by replicating $a$ $n$ times (as an optional value) is: - $\text{none}$ if $n = 0$ (empty list) - $\text{some}(a)$ otherwise In other words, $\text{getLast?}(\text{replicate}(n, a)) = \begin{cases} \text{none} & \text{if } n = 0 \\ \text{some}(a) & \text{otherwise} \end{cases}$.
List.getLast_replicate theorem
(w : replicate n a ≠ []) : (replicate n a).getLast w = a
Full source
@[simp] theorem getLast_replicate (w : replicatereplicate n a ≠ []) : (replicate n a).getLast w = a := by
  simp [getLast_eq_head_reverse]
Last Element of Replicated List is the Replicated Element: $\text{getLast}(\text{replicate}(n, a)) = a$ for $n > 0$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, if the list $\operatorname{replicate}(n, a)$ (a list of length $n$ with all elements equal to $a$) is non-empty, then its last element is equal to $a$.
List.leftpad_prefix theorem
{n : Nat} {a : α} {l : List α} : replicate (n - length l) a <+: leftpad n a l
Full source
theorem leftpad_prefix {n : Nat} {a : α} {l : List α} :
    replicatereplicate (n - length l) a <+: leftpad n a l := by
  simp only [IsPrefix, leftpad]
  exact Exists.intro l rfl
Prefix Property of Left-Padded Lists: $\text{replicate}(n - \text{length}(l), a) \text{ is prefix of } \text{leftpad}(n, a, l)$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and list $l$ of elements of type $\alpha$, the list obtained by replicating $a$ for $(n - \text{length}(l))$ times is a prefix of the left-padded list $\text{leftpad}(n, a, l)$.
List.leftpad_suffix theorem
{n : Nat} {a : α} {l : List α} : l <:+ (leftpad n a l)
Full source
theorem leftpad_suffix {n : Nat} {a : α} {l : List α} : l <:+ (leftpad n a l) := by
  simp only [IsSuffix, leftpad]
  exact Exists.intro (replicate (n - length l) a) rfl
Suffix Property of Left-Padded Lists: $l \text{ is a suffix of } \text{leftpad}(n, a, l)$
Informal description
For any natural number $n$, element $a$ of type $\alpha$, and list $l$ of elements of type $\alpha$, the list $l$ is a suffix of the left-padded list $\text{leftpad}(n, a, l)$.
List.elem_cons_self theorem
[BEq α] [LawfulBEq α] {a : α} : (a :: as).elem a = true
Full source
theorem elem_cons_self [BEq α] [LawfulBEq α] {a : α} : (a::as).elem a = true := by simp
Self-Containment in List Cons: $\text{elem}(a, a :: as) = \text{true}$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, and for any element $a \in \alpha$ and list $as$ of elements of type $\alpha$, the boolean membership test for $a$ in the list $a :: as$ evaluates to $\text{true}$.
List.contains_eq_any_beq theorem
[BEq α] {l : List α} {a : α} : l.contains a = l.any (a == ·)
Full source
theorem contains_eq_any_beq [BEq α] {l : List α} {a : α} : l.contains a = l.any (a == ·) := by
  induction l with simp | cons b l => cases b == a <;> simp [*]
Containment as Boolean Any Check: $l.\text{contains}(a) = l.\text{any}(a == \cdot)$
Informal description
For any type $\alpha$ with a boolean equality relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the containment check $l.\text{contains}(a)$ is equal to checking whether any element in $l$ is equal to $a$ under the boolean equality relation, i.e., $l.\text{any}(a == \cdot)$.
List.contains_iff_exists_mem_beq theorem
[BEq α] {l : List α} {a : α} : l.contains a ↔ ∃ a' ∈ l, a == a'
Full source
theorem contains_iff_exists_mem_beq [BEq α] {l : List α} {a : α} :
    l.contains a ↔ ∃ a' ∈ l, a == a' := by
  induction l <;> simp_all
Containment in List via Boolean Equality: $l.\text{contains}(a) \leftrightarrow \exists a' \in l, a == a'$
Informal description
For any type $\alpha$ with a boolean equality relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the containment check $l.\text{contains}(a)$ holds if and only if there exists an element $a' \in l$ such that $a == a'$ under the boolean equality relation.
List.contains_iff_mem theorem
[BEq α] [LawfulBEq α] {l : List α} {a : α} : l.contains a ↔ a ∈ l
Full source
theorem contains_iff_mem [BEq α] [LawfulBEq α] {l : List α} {a : α} :
    l.contains a ↔ a ∈ l := by
  simp
Equivalence of Boolean Containment and Propositional Membership in Lists
Informal description
For any type $\alpha$ with a lawful boolean equality relation, any list $l$ of elements of type $\alpha$, and any element $a \in \alpha$, the boolean containment check $l.\text{contains}(a)$ is equivalent to the propositional membership $a \in l$.
List.partition_eq_filter_filter theorem
{p : α → Bool} {l : List α} : partition p l = (filter p l, filter (not ∘ p) l)
Full source
@[simp] theorem partition_eq_filter_filter {p : α → Bool} {l : List α} :
    partition p l = (filter p l, filter (not ∘ p) l) := by simp [partition, aux]
  where
    aux : ∀ l {as bs}, partition.loop p l (as, bs) =
        (as.reverse ++ filter p l, bs.reverse ++ filter (not ∘ p) l)
      | [] => by simp [partition.loop, filter]
      | a :: l => by cases pa : p a <;> simp [partition.loop, pa, aux, filter, append_assoc]
Partition as Filter Pair
Informal description
For any predicate `p : α → Bool` and any list `l : List α`, the partition of `l` according to `p` is equal to the pair of lists obtained by filtering `l` with `p` and filtering `l` with the negation of `p`. That is, \[ \text{partition } p \, l = (\text{filter } p \, l, \text{filter } (\neg \circ p) \, l). \]
List.mem_partition theorem
: a ∈ l ↔ a ∈ (partition p l).1 ∨ a ∈ (partition p l).2
Full source
theorem mem_partition : a ∈ la ∈ l ↔ a ∈ (partition p l).1 ∨ a ∈ (partition p l).2 := by
  by_cases p a <;> simp_all
Membership in Partitioned Lists: $a \in l \leftrightarrow a \in (\text{partition } p \, l).1 \lor a \in (\text{partition } p \, l).2$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, an element $a \in \alpha$ belongs to $l$ if and only if it belongs to either the first or second component of the partition of $l$ according to $p$.
List.length_dropLast theorem
: ∀ {xs : List α}, xs.dropLast.length = xs.length - 1
Full source
@[simp] theorem length_dropLast : ∀ {xs : List α}, xs.dropLast.length = xs.length - 1
  | [] => rfl
  | x::xs => by simp
Length of List After Dropping Last Element: $\text{length}(\text{dropLast}(xs)) = \text{length}(xs) - 1$
Informal description
For any list `xs` of elements of type `α`, the length of the list obtained by removing the last element of `xs` (denoted `xs.dropLast`) is equal to the length of `xs` minus one, i.e., \[ \text{length}(\text{dropLast}(xs)) = \text{length}(xs) - 1. \]
List.getElem_dropLast theorem
: ∀ {xs : List α} {i : Nat} (h : i < xs.dropLast.length), xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. ▸ Nat.pred_le _))
Full source
@[simp] theorem getElem_dropLast : ∀ {xs : List α} {i : Nat} (h : i < xs.dropLast.length),
    xs.dropLast[i] = xs[i]'(Nat.lt_of_lt_of_le h (length_dropLast .. ▸ Nat.pred_le _))
  | _ :: _ :: _, 0, _ => rfl
  | _ :: _ :: _, _ + 1, h => getElem_dropLast (Nat.add_one_lt_add_one_iff.mp h)
Element Preservation in Dropped-Last List: $\text{dropLast}(xs)[i] = xs[i]$ for $i < \text{length}(\text{dropLast}(xs))$
Informal description
For any list $xs$ of elements of type $\alpha$ and any natural number index $i$ such that $i < \text{length}(\text{dropLast}(xs))$, the $i$-th element of $\text{dropLast}(xs)$ is equal to the $i$-th element of $xs$. Here, $\text{dropLast}(xs)$ denotes the list obtained by removing the last element of $xs$.
List.getElem?_dropLast theorem
{xs : List α} {i : Nat} : xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none
Full source
theorem getElem?_dropLast {xs : List α} {i : Nat} :
    xs.dropLast[i]? = if i < xs.length - 1 then xs[i]? else none := by
  split
  · rw [getElem?_eq_getElem, getElem?_eq_getElem, getElem_dropLast]
    simpa
  · simp_all
Optional Indexing in Dropped-Last List: $\text{dropLast}(xs)[i]? = \text{if } i < \text{length}(xs) - 1 \text{ then } xs[i]? \text{ else none}$
Informal description
For any list $xs$ of elements of type $\alpha$ and any natural number index $i$, the optional indexing operation $\text{dropLast}(xs)[i]?$ (where $\text{dropLast}(xs)$ removes the last element of $xs$) satisfies: \[ \text{dropLast}(xs)[i]? = \begin{cases} xs[i]? & \text{if } i < \text{length}(xs) - 1 \\ \text{none} & \text{otherwise} \end{cases} \]
List.head_dropLast theorem
{xs : List α} (h) : xs.dropLast.head h = xs.head (by rintro rfl; simp at h)
Full source
theorem head_dropLast {xs : List α} (h) :
    xs.dropLast.head h = xs.head (by rintro rfl; simp at h) := by
  cases xs with
  | nil => rfl
  | cons x xs =>
    cases xs with
    | nil => simp at h
    | cons y ys => rfl
Head of List After Dropping Last Element Equals Original Head
Informal description
For any non-empty list `xs` of elements of type `α`, the head of `xs.dropLast` (with proof `h` that `xs.dropLast` is non-empty) is equal to the head of `xs` (with the automatically derived proof that `xs` is non-empty).
List.head?_dropLast theorem
{xs : List α} : xs.dropLast.head? = if 1 < xs.length then xs.head? else none
Full source
theorem head?_dropLast {xs : List α} : xs.dropLast.head? = if 1 < xs.length then xs.head? else none := by
  cases xs with
  | nil => rfl
  | cons x xs =>
    cases xs with
    | nil => rfl
    | cons y ys => simp [Nat.succ_lt_succ_iff]
Head of List After Dropping Last Element Depends on Length
Informal description
For any list `xs` of elements of type `α`, the head of the list obtained by dropping the last element of `xs` is equal to the head of `xs` if the length of `xs` is greater than 1, and is `none` otherwise. In other words, if `xs` has length greater than 1, then `xs.dropLast.head? = xs.head?`, otherwise `xs.dropLast.head? = none`.
List.getLast_dropLast theorem
{xs : List α} (h) : xs.dropLast.getLast h = xs[xs.length - 2]'(match xs, h with | (_ :: _ :: _), _ => Nat.lt_trans (Nat.lt_add_one _) (Nat.lt_add_one _))
Full source
theorem getLast_dropLast {xs : List α} (h) :
   xs.dropLast.getLast h =
     xs[xs.length - 2]'(match xs, h with | (_ :: _ :: _), _ => Nat.lt_trans (Nat.lt_add_one _) (Nat.lt_add_one _)) := by
  rw [getLast_eq_getElem, getElem_dropLast]
  congr 1
  simp; rfl
Last Element of Dropped-Last List Equals Second-to-Last Element of Original List
Informal description
For any non-empty list `xs` of elements of type `α`, the last element of `xs.dropLast` (with proof `h` that `xs.dropLast` is non-empty) is equal to the element at index `length(xs) - 2` of `xs`. In other words, if `xs` has at least two elements, then: \[ \text{getLast}(\text{dropLast}(xs), h) = xs[\text{length}(xs) - 2] \]
List.getLast?_dropLast theorem
{xs : List α} : xs.dropLast.getLast? = if xs.length ≤ 1 then none else xs[xs.length - 2]?
Full source
theorem getLast?_dropLast {xs : List α} :
    xs.dropLast.getLast? = if xs.length ≤ 1 then none else xs[xs.length - 2]? := by
  split <;> rename_i h
  · match xs, h with
    | [], _
    | [_], _ => simp
  · rw [getLast?_eq_getElem?, getElem?_dropLast, if_pos]
    · congr 1
      simp [← Nat.sub_add_eq]
    · simp only [Nat.not_le] at h
      match xs, h with
      | (_ :: _ :: _), _ => simp
Optional Last Element of Dropped-Last List: $\text{getLast?}(\text{dropLast}(xs)) = \text{if } \text{length}(xs) \leq 1 \text{ then none else } xs[\text{length}(xs) - 2]?$
Informal description
For any list $xs$ of elements of type $\alpha$, the optional last element of the list obtained by removing the last element of $xs$ is equal to: \[ \text{getLast?}(\text{dropLast}(xs)) = \begin{cases} \text{none} & \text{if } \text{length}(xs) \leq 1 \\ xs[\text{length}(xs) - 2]? & \text{otherwise} \end{cases} \]
List.dropLast_cons_of_ne_nil theorem
{α : Type u} {x : α} {l : List α} (h : l ≠ []) : (x :: l).dropLast = x :: l.dropLast
Full source
theorem dropLast_cons_of_ne_nil {α : Type u} {x : α}
    {l : List α} (h : l ≠ []) : (x :: l).dropLast = x :: l.dropLast := by
  simp [dropLast, h]
DropLast Operation Distributes Over Cons for Non-Empty Lists
Informal description
For any non-empty list $l$ of type $\alpha$ and any element $x \in \alpha$, the operation of removing the last element from the list $x :: l$ (where $::$ denotes list cons) results in $x$ cons'd to the list obtained by removing the last element from $l$. That is, $(x :: l).\text{dropLast} = x :: l.\text{dropLast}$.
List.dropLast_concat_getLast theorem
: ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
Full source
theorem dropLast_concat_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l ++ [getLast l h] = l
  | [], h => absurd rfl h
  | [_], _ => rfl
  | _ :: b :: l, _ => by
    rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)]
    congr
    exact dropLast_concat_getLast (cons_ne_nil b l)
Reconstruction of List from DropLast and Last Element: $\text{dropLast } l \mathbin{+\!\!+} [\text{last } l] = l$
Informal description
For any non-empty list $l$ of type $\alpha$, the concatenation of the list obtained by removing the last element of $l$ with the singleton list containing the last element of $l$ equals $l$ itself. That is, $\text{dropLast } l \mathbin{+\!\!+} [\text{getLast } l \ h] = l$, where $h$ is a proof that $l$ is non-empty.
List.map_dropLast theorem
{f : α → β} {l : List α} : l.dropLast.map f = (l.map f).dropLast
Full source
@[simp] theorem map_dropLast {f : α → β} {l : List α} : l.dropLast.map f = (l.map f).dropLast := by
  induction l with
  | nil => rfl
  | cons x xs ih => cases xs <;> simp [ih]
Map Commutes with DropLast: $\text{map } f \circ \text{dropLast} = \text{dropLast} \circ \text{map } f$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of type $\alpha$, the map of $f$ over the list obtained by removing the last element of $l$ is equal to the list obtained by removing the last element of the map of $f$ over $l$. In other words, $(l.\text{dropLast}).\text{map } f = (l.\text{map } f).\text{dropLast}$.
List.dropLast_append_of_ne_nil theorem
{α : Type u} {l : List α} : ∀ {l' : List α} (_ : l ≠ []), (l' ++ l).dropLast = l' ++ l.dropLast
Full source
@[simp] theorem dropLast_append_of_ne_nil {α : Type u} {l : List α} :
    ∀ {l' : List α} (_ : l ≠ []), (l' ++ l).dropLast = l' ++ l.dropLast
  | [], _ => by simp only [nil_append]
  | a :: l', h => by
    rw [cons_append, dropLast, dropLast_append_of_ne_nil h, cons_append]
    simp [h]
DropLast of Concatenated Lists with Nonempty Second List
Informal description
For any type $\alpha$ and nonempty list $l$ of type $\alpha$, and for any list $l'$ of type $\alpha$, the operation of removing the last element from the concatenated list $l' ++ l$ is equal to the concatenation of $l'$ with the list obtained by removing the last element of $l$. In other words, $(l' ++ l).\text{dropLast} = l' ++ l.\text{dropLast}$.
List.dropLast_append theorem
{l₁ l₂ : List α} : (l₁ ++ l₂).dropLast = if l₂.isEmpty then l₁.dropLast else l₁ ++ l₂.dropLast
Full source
theorem dropLast_append {l₁ l₂ : List α} :
    (l₁ ++ l₂).dropLast = if l₂.isEmpty then l₁.dropLast else l₁ ++ l₂.dropLast := by
  split <;> simp_all
DropLast of Concatenated Lists: $(l_1 ++ l_2).\text{dropLast} = \text{if } l_2.\text{isEmpty} \text{ then } l_1.\text{dropLast} \text{ else } l_1 ++ l_2.\text{dropLast}$
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$, the operation of removing the last element from their concatenation $l_1 ++ l_2$ equals: - $l_1.\text{dropLast}$ if $l_2$ is empty, - $l_1 ++ l_2.\text{dropLast}$ otherwise.
List.dropLast_append_cons theorem
: dropLast (l₁ ++ b :: l₂) = l₁ ++ dropLast (b :: l₂)
Full source
theorem dropLast_append_cons : dropLast (l₁ ++ b :: l₂) = l₁ ++ dropLast (b :: l₂) := by
  simp
DropLast of Concatenated List with Cons
Informal description
For any lists $l₁$ and $l₂$ of type $\alpha$ and any element $b$ of type $\alpha$, the operation of removing the last element from the concatenated list $l₁ ++ (b :: l₂)$ is equal to the concatenation of $l₁$ with the list obtained by removing the last element of $b :: l₂$. In other words, $\text{dropLast}(l₁ ++ (b :: l₂)) = l₁ ++ \text{dropLast}(b :: l₂)$.
List.dropLast_concat theorem
: dropLast (l₁ ++ [b]) = l₁
Full source
@[simp] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp
DropLast of Concatenated Singleton List Yields Original List
Informal description
For any list $l_1$ and element $b$ of type $\alpha$, the operation of removing the last element from the concatenated list $l_1 ++ [b]$ results in $l_1$, i.e., $\text{dropLast}(l_1 ++ [b]) = l_1$.
List.dropLast_replicate theorem
{n : Nat} {a : α} : dropLast (replicate n a) = replicate (n - 1) a
Full source
@[simp] theorem dropLast_replicate {n : Nat} {a : α} : dropLast (replicate n a) = replicate (n - 1) a := by
  match n with
  | 0 => simp
  | 1 => simp [replicate_succ]
  | n+2 =>
    rw [replicate_succ, dropLast_cons_of_ne_nil, dropLast_replicate]
    · simp [replicate_succ]
    · simp
DropLast of Replicated List Reduces Length by One
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, removing the last element from the list `replicate n a` (which consists of $n$ copies of $a$) results in a list of $n-1$ copies of $a$, i.e., $\text{dropLast}(\text{replicate}\ n\ a) = \text{replicate}\ (n-1)\ a$.
List.dropLast_cons_self_replicate theorem
{n : Nat} {a : α} : dropLast (a :: replicate n a) = replicate n a
Full source
@[simp] theorem dropLast_cons_self_replicate {n : Nat} {a : α} :
    dropLast (a :: replicate n a) = replicate n a := by
  rw [← replicate_succ, dropLast_replicate, Nat.add_sub_cancel]
DropLast of Cons with Self-Replicated List Yields Replicated List
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, removing the last element from the list $a :: \text{replicate}\ n\ a$ (which consists of $a$ followed by $n$ copies of $a$) results in the list $\text{replicate}\ n\ a$.
List.tail_reverse theorem
{l : List α} : l.reverse.tail = l.dropLast.reverse
Full source
@[simp] theorem tail_reverse {l : List α} : l.reverse.tail = l.dropLast.reverse := by
  apply ext_getElem
  · simp
  · intro i h₁ h₂
    simp [Nat.add_comm i, Nat.sub_add_eq]
Tail of Reversed List Equals Reversed Dropped-Last List
Informal description
For any list $l$ of elements of type $\alpha$, the tail of the reversed list $l^{\text{reverse}}$ is equal to the reversal of the list obtained by removing the last element of $l$. That is: $$ \text{tail}(l^{\text{reverse}}) = (\text{dropLast}(l))^{\text{reverse}} $$
List.splitAt_go theorem
{i : Nat} {l acc : List α} : splitAt.go l xs i acc = if i < xs.length then (acc.reverse ++ xs.take i, xs.drop i) else (l, [])
Full source
theorem splitAt_go {i : Nat} {l acc : List α} :
    splitAt.go l xs i acc =
      if i < xs.length then (acc.reverse ++ xs.take i, xs.drop i) else (l, []) := by
  induction xs generalizing i acc with
  | nil => simp [splitAt.go]
  | cons x xs ih =>
    cases i with
    | zero => simp [splitAt.go]
    | succ i =>
      rw [splitAt.go, take_succ_cons, drop_succ_cons, ih, reverse_cons, append_assoc,
        singleton_append, length_cons]
      simp only [Nat.succ_lt_succ_iff]
Behavior of `splitAt.go`: Conditional Concatenation and Splitting
Informal description
For any natural number $i$ and lists $l$, $xs$, and $acc$ of elements of type $\alpha$, the helper function `splitAt.go` satisfies: \[ \text{splitAt.go}\ l\ xs\ i\ acc = \begin{cases} (acc^{\text{rev}} \mathbin{+\kern-0.5ex+} \text{take}\ i\ xs,\ \text{drop}\ i\ xs) & \text{if } i < \text{length}\ xs \\ (l, []) & \text{otherwise} \end{cases} \] where $acc^{\text{rev}}$ denotes the reverse of $acc$, $\mathbin{+\kern-0.5ex+}$ denotes list concatenation, and $\text{take}\ i\ xs$ and $\text{drop}\ i\ xs$ are the first $i$ elements and the remaining elements of $xs$ respectively.
List.replace_cons_self theorem
[LawfulBEq α] {a : α} : (a :: as).replace a b = b :: as
Full source
@[simp] theorem replace_cons_self [LawfulBEq α] {a : α} : (a::as).replace a b = b::as := by
  simp [replace_cons]
Replacement of Head Element in List: $(a :: as).\text{replace}(a, b) = b :: as$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, and for any elements $a, b \in \alpha$ and list $as$ of elements in $\alpha$, replacing $a$ with $b$ in the list $a :: as$ results in $b :: as$. That is, $(a :: as).\text{replace}(a, b) = b :: as$.
List.replace_of_not_mem theorem
[LawfulBEq α] {l : List α} (h : a ∉ l) : l.replace a b = l
Full source
@[simp] theorem replace_of_not_mem [LawfulBEq α] {l : List α} (h : a ∉ l) : l.replace a b = l := by
  induction l with
  | nil => rfl
  | cons x xs ih =>
    simp only [replace_cons]
    split <;> simp_all
List Replacement Preserves Structure When Element Not Present
Informal description
For any type $\alpha$ with a lawful boolean equality relation, and for any list $l$ of elements in $\alpha$, if an element $a$ is not in $l$, then replacing $a$ with $b$ in $l$ leaves $l$ unchanged, i.e., $l.\text{replace}(a, b) = l$.
List.length_replace theorem
{l : List α} : (l.replace a b).length = l.length
Full source
@[simp] theorem length_replace {l : List α} : (l.replace a b).length = l.length := by
  induction l with
  | nil => simp
  | cons x l ih =>
    simp only [replace_cons]
    split <;> simp_all
Length Preservation under List Replacement: $\text{length}(\text{replace}(l, a, b)) = \text{length}(l)$
Informal description
For any list $l$ of elements of type $\alpha$, the length of the list obtained by replacing all occurrences of $a$ with $b$ in $l$ is equal to the length of $l$, i.e., $\text{length}(\text{replace}(l, a, b)) = \text{length}(l)$.
List.getElem?_replace theorem
[LawfulBEq α] {l : List α} {i : Nat} : (l.replace a b)[i]? = if l[i]? == some a then if a ∈ l.take i then some a else some b else l[i]?
Full source
theorem getElem?_replace [LawfulBEq α] {l : List α} {i : Nat} :
    (l.replace a b)[i]? = if l[i]? == some a then if a ∈ l.take i then some a else some b else l[i]? := by
  induction l generalizing i with
  | nil => cases i <;> simp
  | cons x xs ih =>
    cases i <;>
    · simp only [replace_cons]
      split <;> split <;> simp_all
Optional Indexing of List Replacement: $(l.\text{replace}(a, b))[i]?$ in Terms of $l[i]?$ and Occurrences of $a$
Informal description
For a type $\alpha$ with a lawful boolean equality relation, given a list $l$ of elements in $\alpha$ and an index $i$, the optional indexing operation on the list obtained by replacing all occurrences of $a$ with $b$ in $l$ satisfies: $$(l.\text{replace}(a, b))[i]? = \begin{cases} \text{some } a & \text{if } l[i]? = \text{some } a \text{ and } a \text{ appears in the first } i \text{ elements of } l, \\ \text{some } b & \text{if } l[i]? = \text{some } a \text{ and } a \text{ does not appear in the first } i \text{ elements of } l, \\ l[i]? & \text{otherwise.} \end{cases}$$
List.getElem?_replace_of_ne theorem
[LawfulBEq α] {l : List α} {i : Nat} (h : l[i]? ≠ some a) : (l.replace a b)[i]? = l[i]?
Full source
theorem getElem?_replace_of_ne [LawfulBEq α] {l : List α} {i : Nat} (h : l[i]?l[i]? ≠ some a) :
    (l.replace a b)[i]? = l[i]? := by
  simp_all [getElem?_replace]
Optional Indexing of List Replacement Preserves Non-Matching Elements: $(l.\text{replace}(a, b))[i]? = l[i]?$ when $l[i]? \neq \text{some } a$
Informal description
For a type $\alpha$ with a lawful boolean equality relation, given a list $l$ of elements in $\alpha$ and an index $i$, if the optional element at position $i$ in $l$ is not equal to $\text{some } a$, then the optional element at position $i$ in the list obtained by replacing all occurrences of $a$ with $b$ in $l$ is equal to the original optional element at position $i$ in $l$, i.e., $(l.\text{replace}(a, b))[i]? = l[i]?$.
List.getElem_replace theorem
[LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) : (l.replace a b)[i]'(by simpa) = if l[i] == a then if a ∈ l.take i then a else b else l[i]
Full source
theorem getElem_replace [LawfulBEq α] {l : List α} {i : Nat} (h : i < l.length) :
    (l.replace a b)[i]'(by simpa) = if l[i] == a then if a ∈ l.take i then a else b else l[i] := by
  apply Option.some.inj
  rw [← getElem?_eq_getElem, getElem?_replace]
  split <;> split <;> simp_all
Indexing of List Replacement: $(l.\text{replace}(a, b))[i]$ in Terms of $l[i]$ and Occurrences of $a$
Informal description
For a type $\alpha$ with a lawful boolean equality relation, given a list $l$ of elements in $\alpha$, an index $i$ with $i < \text{length}(l)$, and elements $a, b \in \alpha$, the $i$-th element of the list obtained by replacing all occurrences of $a$ with $b$ in $l$ satisfies: $$(l.\text{replace}(a, b))[i] = \begin{cases} a & \text{if } l[i] = a \text{ and } a \text{ appears in the first } i \text{ elements of } l, \\ b & \text{if } l[i] = a \text{ and } a \text{ does not appear in the first } i \text{ elements of } l, \\ l[i] & \text{otherwise.} \end{cases}$$
List.getElem_replace_of_ne theorem
[LawfulBEq α] {l : List α} {i : Nat} {h : i < l.length} (h' : l[i] ≠ a) : (l.replace a b)[i]'(by simpa) = l[i]'(h)
Full source
theorem getElem_replace_of_ne [LawfulBEq α] {l : List α} {i : Nat} {h : i < l.length} (h' : l[i]l[i] ≠ a) :
    (l.replace a b)[i]'(by simpa) = l[i]'(h) := by
  rw [getElem_replace h]
  simp [h']
Preservation of Non-Matching Elements under List Replacement: $(l.\text{replace}(a, b))[i] = l[i]$ when $l[i] \neq a$
Informal description
For a type $\alpha$ with a lawful boolean equality relation, given a list $l$ of elements in $\alpha$, an index $i$ with $i < \text{length}(l)$, and elements $a, b \in \alpha$, if the element at position $i$ in $l$ is not equal to $a$ (i.e., $l[i] \neq a$), then the element at position $i$ in the list obtained by replacing all occurrences of $a$ with $b$ in $l$ remains unchanged, i.e., $(l.\text{replace}(a, b))[i] = l[i]$.
List.head?_replace theorem
{l : List α} {a b : α} : (l.replace a b).head? = match l.head? with | none => none | some x => some (if a == x then b else x)
Full source
theorem head?_replace {l : List α} {a b : α} :
    (l.replace a b).head? = match l.head? with
      | none => none
      | some x => some (if a == x then b else x) := by
  cases l with
  | nil => rfl
  | cons x xs =>
    simp [replace_cons]
    split <;> simp_all
First Element After Replacement: $(l.replace\ a\ b).head? = \text{match } l.head? \text{ with } \text{none} \Rightarrow \text{none} \mid \text{some } x \Rightarrow \text{some } (\text{if } a == x \text{ then } b \text{ else } x)$
Informal description
For any list $l$ of elements of type $\alpha$ and any elements $a, b \in \alpha$, the first element of the list obtained by replacing all occurrences of $a$ with $b$ in $l$ is: - `none` if $l$ is empty, - `some (if a == x then b else x)` where $x$ is the first element of $l$, otherwise. Here, $l.replace\ a\ b$ denotes the list obtained by replacing all occurrences of $a$ in $l$ with $b$, and $l.head?$ denotes the optional first element of $l$ (which is `none` if $l$ is empty and `some x` otherwise).
List.head_replace theorem
{l : List α} {a b : α} (w) : (l.replace a b).head w = if a == l.head (by rintro rfl; simp_all) then b else l.head (by rintro rfl; simp_all)
Full source
theorem head_replace {l : List α} {a b : α} (w) :
    (l.replace a b).head w =
      if a == l.head (by rintro rfl; simp_all) then
        b
      else
        l.head  (by rintro rfl; simp_all) := by
  apply Option.some.inj
  rw [← head?_eq_head, head?_replace, head?_eq_head]
Head Preservation Under Replacement: $(l.replace\ a\ b).head = \text{if } a == l.head \text{ then } b \text{ else } l.head$
Informal description
For any nonempty list $l$ of elements of type $\alpha$ and any elements $a, b \in \alpha$, the head of the list obtained by replacing all occurrences of $a$ with $b$ in $l$ is equal to $b$ if the head of $l$ is equal to $a$ (under boolean equality), and remains the original head of $l$ otherwise. Here, $l.replace\ a\ b$ denotes the list obtained by replacing all occurrences of $a$ in $l$ with $b$, and $l.head$ denotes the first element of $l$ (with proof $w$ that $l$ is nonempty).
List.replace_append theorem
[LawfulBEq α] {l₁ l₂ : List α} : (l₁ ++ l₂).replace a b = if a ∈ l₁ then l₁.replace a b ++ l₂ else l₁ ++ l₂.replace a b
Full source
theorem replace_append [LawfulBEq α] {l₁ l₂ : List α} :
    (l₁ ++ l₂).replace a b = if a ∈ l₁ then l₁.replace a b ++ l₂ else l₁ ++ l₂.replace a b := by
  induction l₁ with
  | nil => simp
  | cons x xs ih =>
    simp only [cons_append, replace_cons]
    split <;> split <;> simp_all
Replacement in Concatenated Lists: $(l_1 ++ l_2).replace\ a\ b = \text{if } a \in l_1 \text{ then } l_1.replace\ a\ b ++ l_2 \text{ else } l_1 ++ l_2.replace\ a\ b$
Informal description
Let $\alpha$ be a type with a lawful boolean equality relation `==`. For any lists $l_1, l_2$ of elements of $\alpha$ and any elements $a, b \in \alpha$, the replacement of $a$ with $b$ in the concatenated list $l_1 ++ l_2$ is equal to: - $l_1.replace\ a\ b ++ l_2$ if $a$ is an element of $l_1$, - $l_1 ++ l_2.replace\ a\ b$ otherwise. Here, $l.replace\ a\ b$ denotes the list obtained by replacing all occurrences of $a$ in $l$ with $b$.
List.replace_append_left theorem
[LawfulBEq α] {l₁ l₂ : List α} (h : a ∈ l₁) : (l₁ ++ l₂).replace a b = l₁.replace a b ++ l₂
Full source
theorem replace_append_left [LawfulBEq α] {l₁ l₂ : List α} (h : a ∈ l₁) :
    (l₁ ++ l₂).replace a b = l₁.replace a b ++ l₂ := by
  simp [replace_append, h]
Replacement in Concatenated Lists when Element is in First List: $(l_1 ++ l_2).replace\ a\ b = l_1.replace\ a\ b ++ l_2$ if $a \in l_1$
Informal description
Let $\alpha$ be a type with a lawful boolean equality relation `==`. For any lists $l_1, l_2$ of elements of $\alpha$ and any elements $a, b \in \alpha$, if $a$ is an element of $l_1$, then the replacement of $a$ with $b$ in the concatenated list $l_1 ++ l_2$ is equal to $l_1.replace\ a\ b ++ l_2$. Here, $l.replace\ a\ b$ denotes the list obtained by replacing all occurrences of $a$ in $l$ with $b$.
List.replace_append_right theorem
[LawfulBEq α] {l₁ l₂ : List α} (h : ¬a ∈ l₁) : (l₁ ++ l₂).replace a b = l₁ ++ l₂.replace a b
Full source
theorem replace_append_right [LawfulBEq α] {l₁ l₂ : List α} (h : ¬ a ∈ l₁) :
    (l₁ ++ l₂).replace a b = l₁ ++ l₂.replace a b := by
  simp [replace_append, h]
Replacement in Concatenated Lists When Element Not in First List: $(l_1 ++ l_2).replace\ a\ b = l_1 ++ l_2.replace\ a\ b$ if $a \notin l_1$
Informal description
Let $\alpha$ be a type with a lawful boolean equality relation. For any lists $l_1, l_2$ of elements of $\alpha$ and any elements $a, b \in \alpha$, if $a$ is not an element of $l_1$, then replacing $a$ with $b$ in the concatenated list $l_1 ++ l_2$ is equal to $l_1$ concatenated with the result of replacing $a$ with $b$ in $l_2$.
List.replace_take theorem
{l : List α} {i : Nat} : (l.take i).replace a b = (l.replace a b).take i
Full source
theorem replace_take {l : List α} {i : Nat} :
    (l.take i).replace a b = (l.replace a b).take i := by
  induction l generalizing i with
  | nil => simp
  | cons x xs ih =>
    cases i with
    | zero => simp [ih]
    | succ i =>
      simp only [replace_cons, take_succ_cons]
      split <;> simp_all
Replacement Commutes with Taking Prefix: $(l.\text{take}\ i).\text{replace}(a, b) = (l.\text{replace}(a, b)).\text{take}\ i$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, replacing an element $a$ with $b$ in the first $i$ elements of $l$ is equivalent to taking the first $i$ elements of the list obtained by replacing all occurrences of $a$ with $b$ in $l$. That is, $(l.\text{take}\ i).\text{replace}(a, b) = (l.\text{replace}(a, b)).\text{take}\ i$.
List.replace_replicate_self theorem
[LawfulBEq α] {a : α} (h : 0 < n) : (replicate n a).replace a b = b :: replicate (n - 1) a
Full source
@[simp] theorem replace_replicate_self [LawfulBEq α] {a : α} (h : 0 < n) :
    (replicate n a).replace a b = b :: replicate (n - 1) a := by
  cases n <;> simp_all [replicate_succ, replace_cons]
Replacement in Replicated List: $(\text{replicate}\ n\ a).\text{replace}(a, b) = b :: \text{replicate}\ (n - 1)\ a$ for $n > 0$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, and for any elements $a, b \in \alpha$, if $n > 0$, then replacing $a$ with $b$ in a list consisting of $n$ copies of $a$ results in the list $b$ followed by $n-1$ copies of $a$, i.e., $$(\text{replicate}\ n\ a).\text{replace}(a, b) = b :: \text{replicate}\ (n - 1)\ a.$$
List.replace_replicate_ne theorem
[LawfulBEq α] {a b c : α} (h : !b == a) : (replicate n a).replace b c = replicate n a
Full source
@[simp] theorem replace_replicate_ne [LawfulBEq α] {a b c : α} (h : !b == a) :
    (replicate n a).replace b c = replicate n a := by
  rw [replace_of_not_mem]
  simp_all
Invariance of Replicated List under Replacement of Unequal Element: $(\text{replicate}\ n\ a).\text{replace}(b, c) = \text{replicate}\ n\ a$ when $b \neq a$
Informal description
For any type $\alpha$ with a lawful boolean equality relation, and for any elements $a, b, c \in \alpha$, if $b \neq a$ (as determined by the boolean equality), then replacing $b$ with $c$ in a list consisting of $n$ copies of $a$ leaves the list unchanged, i.e., $(\text{replicate}\ n\ a).\text{replace}(b, c) = \text{replicate}\ n\ a$.
List.insert_nil theorem
(a : α) : [].insert a = [a]
Full source
@[simp] theorem insert_nil (a : α) : [].insert a = [a] := rfl
Insertion into Empty List Yields Singleton List
Informal description
For any element $a$ of type $\alpha$, inserting $a$ into the empty list results in the singleton list $[a]$.
List.insert_of_mem theorem
{l : List α} (h : a ∈ l) : l.insert a = l
Full source
@[simp] theorem insert_of_mem {l : List α} (h : a ∈ l) : l.insert a = l := by
  simp [List.insert, h]
Insertion of Existing Element Preserves List: $l.\text{insert}(a) = l$ when $a \in l$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, if $a$ is already a member of $l$, then inserting $a$ into $l$ leaves the list unchanged, i.e., $l.\text{insert}(a) = l$.
List.insert_of_not_mem theorem
{l : List α} (h : a ∉ l) : l.insert a = a :: l
Full source
@[simp] theorem insert_of_not_mem {l : List α} (h : a ∉ l) : l.insert a = a :: l := by
  simp [List.insert, h]
Insertion into List When Element Not Present: $l.\text{insert}(a) = a :: l$ if $a \notin l$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$ such that $a$ is not in $l$, the insertion of $a$ into $l$ results in the list $a :: l$ (i.e., $a$ prepended to $l$).
List.mem_insert_iff theorem
{l : List α} : a ∈ l.insert b ↔ a = b ∨ a ∈ l
Full source
@[simp] theorem mem_insert_iff {l : List α} : a ∈ l.insert ba ∈ l.insert b ↔ a = b ∨ a ∈ l := by
  if h : b ∈ l then
    rw [insert_of_mem h]
    constructor; {apply Or.inr}
    intro
    | Or.inl h' => rw [h']; exact h
    | Or.inr h' => exact h'
  else rw [insert_of_not_mem h, mem_cons]
Membership Condition for List Insertion: $a \in l.\text{insert}(b) \leftrightarrow a = b \lor a \in l$
Informal description
For any list $l$ of elements of type $\alpha$ and any elements $a, b \in \alpha$, the element $a$ belongs to the list obtained by inserting $b$ into $l$ if and only if either $a$ equals $b$ or $a$ belongs to $l$. In symbols: $$a \in l.\text{insert}(b) \leftrightarrow a = b \lor a \in l.$$
List.mem_insert_self theorem
{a : α} {l : List α} : a ∈ l.insert a
Full source
@[simp] theorem mem_insert_self {a : α} {l : List α} : a ∈ l.insert a :=
  mem_insert_iff.2 (Or.inl rfl)
Self-Membership in List Insertion: $a \in l.\text{insert}(a)$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the element $a$ belongs to the list obtained by inserting $a$ into $l$, i.e., $a \in l.\text{insert}(a)$.
List.mem_insert_of_mem theorem
{l : List α} (h : a ∈ l) : a ∈ l.insert b
Full source
theorem mem_insert_of_mem {l : List α} (h : a ∈ l) : a ∈ l.insert b :=
  mem_insert_iff.2 (Or.inr h)
Membership Preservation under List Insertion
Informal description
For any list $l$ of elements of type $\alpha$ and any elements $a, b \in \alpha$, if $a$ is a member of $l$, then $a$ is also a member of the list obtained by inserting $b$ into $l$. In symbols: $$a \in l \implies a \in l.\text{insert}(b).$$
List.length_insert_of_mem theorem
{l : List α} (h : a ∈ l) : length (l.insert a) = length l
Full source
@[simp] theorem length_insert_of_mem {l : List α} (h : a ∈ l) :
    length (l.insert a) = length l := by rw [insert_of_mem h]
Length Preservation under Insertion of Existing Element
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, if $a$ is already a member of $l$, then the length of the list remains unchanged after inserting $a$ into $l$, i.e., $\text{length}(l.\text{insert}(a)) = \text{length}(l)$.
List.length_insert_of_not_mem theorem
{l : List α} (h : a ∉ l) : length (l.insert a) = length l + 1
Full source
@[simp] theorem length_insert_of_not_mem {l : List α} (h : a ∉ l) :
    length (l.insert a) = length l + 1 := by rw [insert_of_not_mem h]; rfl
Length Increase by Insertion of New Element: $\text{length}(l.\text{insert}(a)) = \text{length}(l) + 1$ when $a \notin l$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$ such that $a$ is not in $l$, the length of the list obtained by inserting $a$ into $l$ is equal to the length of $l$ plus one, i.e., $\text{length}(l.\text{insert}(a)) = \text{length}(l) + 1$.
List.length_le_length_insert theorem
{l : List α} {a : α} : l.length ≤ (l.insert a).length
Full source
theorem length_le_length_insert {l : List α} {a : α} : l.length ≤ (l.insert a).length := by
  by_cases h : a ∈ l
  · rw [length_insert_of_mem h]
    exact Nat.le_refl _
  · rw [length_insert_of_not_mem h]
    exact Nat.le_succ _
Monotonicity of List Length under Insertion: $\text{length}(l) \leq \text{length}(l.\text{insert}(a))$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the length of $l$ is less than or equal to the length of the list obtained by inserting $a$ into $l$, i.e., $\text{length}(l) \leq \text{length}(l.\text{insert}(a))$.
List.length_insert_pos theorem
{l : List α} {a : α} : 0 < (l.insert a).length
Full source
theorem length_insert_pos {l : List α} {a : α} : 0 < (l.insert a).length := by
  by_cases h : a ∈ l
  · rw [length_insert_of_mem h]
    exact length_pos_of_mem h
  · rw [length_insert_of_not_mem h]
    exact Nat.zero_lt_succ _
Positivity of Length After Insertion: $0 < \text{length}(l.\text{insert}(a))$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the length of the list after inserting $a$ is strictly positive, i.e., $0 < \text{length}(l.\text{insert}(a))$.
List.insert_eq theorem
{l : List α} {a : α} : l.insert a = if a ∈ l then l else a :: l
Full source
theorem insert_eq {l : List α} {a : α} : l.insert a = if a ∈ l then l else a :: l := by
  simp [List.insert]
Insert Operation on Lists: $l.\text{insert}(a) = \text{if } a \in l \text{ then } l \text{ else } a :: l$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the operation `insert a l` results in $l$ if $a$ is already an element of $l$, and otherwise it prepends $a$ to $l$, i.e., $l.\text{insert}(a) = \begin{cases} l & \text{if } a \in l \\ a :: l & \text{otherwise.} \end{cases}$
List.getElem?_insert_zero theorem
{l : List α} {a : α} : (l.insert a)[0]? = if a ∈ l then l[0]? else some a
Full source
theorem getElem?_insert_zero {l : List α} {a : α} :
    (l.insert a)[0]? = if a ∈ l then l[0]? else some a := by
  simp only [insert_eq]
  split <;> simp
Optional First Element After Insertion: $(l.\text{insert}(a))[0]? = \text{if } a \in l \text{ then } l[0]? \text{ else some } a$
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the optional lookup of the first element in the list after inserting $a$ satisfies: $$(l.\text{insert}(a))[0]? = \begin{cases} l[0]? & \text{if } a \in l \\ \text{some } a & \text{otherwise.} \end{cases}$$
List.getElem?_insert_succ theorem
{l : List α} {a : α} {i : Nat} : (l.insert a)[i + 1]? = if a ∈ l then l[i + 1]? else l[i]?
Full source
theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
    (l.insert a)[i+1]? = if a ∈ l then l[i+1]? else l[i]? := by
  simp only [insert_eq]
  split <;> simp
Optional Lookup at Successor Index After Insertion: $(l.\text{insert}(a))[i+1]? = \text{if } a \in l \text{ then } l[i+1]? \text{ else } l[i]?$
Informal description
For any list $l$ of elements of type $\alpha$, any element $a \in \alpha$, and any natural number index $i$, the optional lookup at index $i+1$ of the list obtained by inserting $a$ into $l$ satisfies: $$(l.\text{insert}(a))[i+1]? = \begin{cases} l[i+1]? & \text{if } a \in l \\ l[i]? & \text{otherwise.} \end{cases}$$
List.getElem?_insert theorem
{l : List α} {a : α} {i : Nat} : (l.insert a)[i]? = if a ∈ l then l[i]? else if i = 0 then some a else l[i - 1]?
Full source
theorem getElem?_insert {l : List α} {a : α} {i : Nat} :
    (l.insert a)[i]? = if a ∈ l then l[i]? else if i = 0 then some a else l[i-1]? := by
  cases i
  · simp [getElem?_insert_zero]
  · simp [getElem?_insert_succ]
Optional Element at Index After List Insertion: $(l.\text{insert}(a))[i]?$
Informal description
For any list $l$ of elements of type $\alpha$, any element $a \in \alpha$, and any natural number index $i$, the optional lookup at index $i$ of the list obtained by inserting $a$ into $l$ satisfies: $$(l.\text{insert}(a))[i]? = \begin{cases} l[i]? & \text{if } a \in l \\ \text{some } a & \text{if } i = 0 \text{ and } a \notin l \\ l[i-1]? & \text{otherwise.} \end{cases}$$
List.getElem_insert theorem
{l : List α} {a : α} {i : Nat} (h : i < l.length) : (l.insert a)[i]'(Nat.lt_of_lt_of_le h length_le_length_insert) = if a ∈ l then l[i] else if i = 0 then a else l[i - 1]'(Nat.lt_of_le_of_lt (Nat.pred_le _) h)
Full source
theorem getElem_insert {l : List α} {a : α} {i : Nat} (h : i < l.length) :
    (l.insert a)[i]'(Nat.lt_of_lt_of_le h length_le_length_insert) =
      if a ∈ l then l[i] else if i = 0 then a else l[i-1]'(Nat.lt_of_le_of_lt (Nat.pred_le _) h) := by
  apply Option.some.inj
  rw [← getElem?_eq_getElem, getElem?_insert]
  split
  · simp [getElem?_eq_getElem, h]
  · split
    · rfl
    · have h' : i - 1 < l.length := Nat.lt_of_le_of_lt (Nat.pred_le _) h
      simp [getElem?_eq_getElem, h']
Element at Index After List Insertion: $(l.\text{insert}(a))[i]$
Informal description
For any list $l$ of elements of type $\alpha$, any element $a \in \alpha$, and any natural number index $i$ such that $i < \text{length}(l)$, the element at index $i$ in the list obtained by inserting $a$ into $l$ satisfies: $$(l.\text{insert}(a))[i] = \begin{cases} l[i] & \text{if } a \in l \\ a & \text{if } i = 0 \text{ and } a \notin l \\ l[i-1] & \text{otherwise.} \end{cases}$$
List.head?_insert theorem
{l : List α} {a : α} : (l.insert a).head? = some (if h : a ∈ l then l.head (ne_nil_of_mem h) else a)
Full source
theorem head?_insert {l : List α} {a : α} :
    (l.insert a).head? = some (if h : a ∈ l then l.head (ne_nil_of_mem h) else a) := by
  simp only [insert_eq]
  split <;> rename_i h
  · simp [head?_eq_head (ne_nil_of_mem h)]
  · rfl
Optional Head of List After Insertion
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, the optional head of the list obtained by inserting $a$ into $l$ is equal to: - $\text{some}(x)$ where $x$ is the head of $l$ (if $a$ is already in $l$) - $\text{some}(a)$ (if $a$ is not in $l$) More formally: $(l.\text{insert}(a)).\text{head?} = \begin{cases} \text{some}(l.\text{head}) & \text{if } a \in l \\ \text{some}(a) & \text{otherwise} \end{cases}$
List.head_insert theorem
{l : List α} {a : α} (w) : (l.insert a).head w = if h : a ∈ l then l.head (ne_nil_of_mem h) else a
Full source
theorem head_insert {l : List α} {a : α} (w) :
    (l.insert a).head w = if h : a ∈ l then l.head (ne_nil_of_mem h) else a := by
  apply Option.some.inj
  rw [← head?_eq_head, head?_insert]
Head of List After Insertion
Informal description
For any list $l$ of elements of type $\alpha$ and any element $a \in \alpha$, if $w$ is a proof that the list $l.\text{insert}(a)$ is nonempty, then the head of this list is equal to: - The head of $l$ (if $a$ is already in $l$) - $a$ (if $a$ is not in $l$) More formally: $(l.\text{insert}(a)).\text{head}(w) = \begin{cases} l.\text{head}(h) & \text{if } a \in l \text{ (where } h \text{ is a proof that } l \text{ is nonempty)} \\ a & \text{otherwise} \end{cases}$
List.insert_append theorem
{l₁ l₂ : List α} {a : α} : (l₁ ++ l₂).insert a = if a ∈ l₂ then l₁ ++ l₂ else l₁.insert a ++ l₂
Full source
theorem insert_append {l₁ l₂ : List α} {a : α} :
    (l₁ ++ l₂).insert a = if a ∈ l₂ then l₁ ++ l₂ else l₁.insert a ++ l₂ := by
  simp only [insert_eq, mem_append]
  (repeat split) <;> simp_all
Insertion into Concatenated Lists: $(l_1 ++ l_2).\text{insert}(a) = \text{if } a \in l_2 \text{ then } l_1 ++ l_2 \text{ else } l_1.\text{insert}(a) ++ l_2$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$ and any element $a \in \alpha$, the insertion of $a$ into the concatenated list $l_1 ++ l_2$ is equal to $l_1 ++ l_2$ if $a$ is an element of $l_2$, and otherwise it is equal to the concatenation of $l_1$ with $a$ inserted and $l_2$. In other words: $$(l_1 ++ l_2).\text{insert}(a) = \begin{cases} l_1 ++ l_2 & \text{if } a \in l_2, \\ l_1.\text{insert}(a) ++ l_2 & \text{otherwise.} \end{cases}$$
List.insert_append_of_mem_left theorem
{l₁ l₂ : List α} (h : a ∈ l₂) : (l₁ ++ l₂).insert a = l₁ ++ l₂
Full source
theorem insert_append_of_mem_left {l₁ l₂ : List α} (h : a ∈ l₂) :
    (l₁ ++ l₂).insert a = l₁ ++ l₂ := by
  simp [insert_append, h]
Insertion into Concatenated List Preserves Structure When Element is in Second List
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, and any element $a \in \alpha$, if $a$ is a member of $l_2$, then inserting $a$ into the concatenated list $l_1 ++ l_2$ results in the original concatenated list, i.e., $(l_1 ++ l_2).\text{insert}(a) = l_1 ++ l_2$.
List.insert_append_of_not_mem_left theorem
{l₁ l₂ : List α} (h : ¬a ∈ l₂) : (l₁ ++ l₂).insert a = l₁.insert a ++ l₂
Full source
theorem insert_append_of_not_mem_left {l₁ l₂ : List α} (h : ¬ a ∈ l₂) :
    (l₁ ++ l₂).insert a = l₁.insert a ++ l₂ := by
  simp [insert_append, h]
Insertion into Concatenated List When Element Not in Second List: $(l_1 ++ l_2).\text{insert}(a) = l_1.\text{insert}(a) ++ l_2$ if $a \notin l_2$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, and any element $a \in \alpha$, if $a$ is not a member of $l_2$, then inserting $a$ into the concatenated list $l_1 ++ l_2$ results in the concatenation of $l_1$ with $a$ inserted and $l_2$, i.e., $(l_1 ++ l_2).\text{insert}(a) = l_1.\text{insert}(a) ++ l_2$.
List.insert_replicate_self theorem
{a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a
Full source
@[simp] theorem insert_replicate_self {a : α} (h : 0 < n) : (replicate n a).insert a = replicate n a := by
  cases n <;> simp_all
Insertion into Replicated List: $\text{insert}(a, \text{replicate}(n, a)) = \text{replicate}(n, a)$ for $n > 0$
Informal description
For any element $a$ of type $\alpha$ and any positive natural number $n$, inserting $a$ into a list consisting of $n$ copies of $a$ leaves the list unchanged, i.e., $\text{insert}(a, \text{replicate}(n, a)) = \text{replicate}(n, a)$.
List.insert_replicate_ne theorem
{a b : α} (h : !b == a) : (replicate n a).insert b = b :: replicate n a
Full source
@[simp] theorem insert_replicate_ne {a b : α} (h : !b == a) :
    (replicate n a).insert b = b :: replicate n a := by
  rw [insert_of_not_mem]
  simp_all
Insertion of Distinct Element into Replicated List: $(\text{replicate}\ n\ a).\text{insert}\ b = b :: \text{replicate}\ n\ a$ when $b \neq a$
Informal description
For any elements $a$ and $b$ of type $\alpha$ such that $b \neq a$ (as determined by the boolean equality test), inserting $b$ into a list consisting of $n$ copies of $a$ results in the list $b$ followed by $n$ copies of $a$, i.e., $(\text{replicate}\ n\ a).\text{insert}\ b = b :: \text{replicate}\ n\ a$.
List.not_any_eq_all_not theorem
{l : List α} {p : α → Bool} : (!l.any p) = l.all fun a => !p a
Full source
theorem not_any_eq_all_not {l : List α} {p : α → Bool} : (!l.any p) = l.all fun a => !p a := by
  induction l with simp | cons _ _ ih => rw [ih]
De Morgan's Law for List Disjunction: $\neg(\text{any}\ p\ l) = \text{all}\ (\neg p)\ l$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the negation of the disjunction of $p$ applied to all elements of $l$ is equal to the conjunction of the negations of $p$ applied to each element of $l$. In symbols: $$\neg \left( \bigvee_{a \in l} p(a) \right) = \bigwedge_{a \in l} \neg p(a)$$
List.not_all_eq_any_not theorem
{l : List α} {p : α → Bool} : (!l.all p) = l.any fun a => !p a
Full source
theorem not_all_eq_any_not {l : List α} {p : α → Bool} : (!l.all p) = l.any fun a => !p a := by
  induction l with simp | cons _ _ ih => rw [ih]
Negation of Universal Quantifier on Lists is Existential Quantifier of Negation
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the negation of the statement "all elements in $l$ satisfy $p$" is equivalent to "there exists an element in $l$ that does not satisfy $p$". In symbols: $$\neg (\text{all elements in } l \text{ satisfy } p) \leftrightarrow (\text{there exists an element in } l \text{ that satisfies } \neg p).$$
List.and_any_distrib_left theorem
{l : List α} {p : α → Bool} {q : Bool} : (q && l.any p) = l.any fun a => q && p a
Full source
theorem and_any_distrib_left {l : List α} {p : α → Bool} {q : Bool} :
    (q && l.any p) = l.any fun a => q && p a := by
  induction l with simp | cons _ _ ih => rw [Bool.and_or_distrib_left, ih]
Left Distributivity of Boolean AND over List Existential Quantifier
Informal description
For any list $l$ of elements of type $\alpha$, any predicate $p : \alpha \to \text{Bool}$, and any boolean value $q$, the following distributive law holds: $$ q \land \left(\bigvee_{a \in l} p(a)\right) = \bigvee_{a \in l} (q \land p(a)) $$ where $\land$ denotes logical AND and $\bigvee$ represents the disjunction over all elements in the list (i.e., the `any` operation).
List.and_any_distrib_right theorem
{l : List α} {p : α → Bool} {q : Bool} : (l.any p && q) = l.any fun a => p a && q
Full source
theorem and_any_distrib_right {l : List α} {p : α → Bool} {q : Bool} :
    (l.any p && q) = l.any fun a => p a && q := by
  induction l with simp | cons _ _ ih => rw [Bool.and_or_distrib_right, ih]
Right Distributivity of AND over ANY for Lists: $(\text{any}\ l\ p) \land q = \text{any}\ l\ (\lambda a, p(a) \land q)$
Informal description
For any list $l$ of elements of type $\alpha$, any predicate $p : \alpha \to \text{Bool}$, and any boolean value $q$, the following distributive property holds: $$(\text{any}\ l\ p) \land q = \text{any}\ l\ (\lambda a, p(a) \land q)$$ where $\text{any}\ l\ p$ checks if any element in $l$ satisfies $p$, and $\land$ denotes boolean AND.
List.or_all_distrib_left theorem
{l : List α} {p : α → Bool} {q : Bool} : (q || l.all p) = l.all fun a => q || p a
Full source
theorem or_all_distrib_left {l : List α} {p : α → Bool} {q : Bool} :
    (q || l.all p) = l.all fun a => q || p a := by
  induction l with simp | cons _ _ ih => rw [Bool.or_and_distrib_left, ih]
Left Distributivity of OR over Universal Quantification on Lists: $q \lor (\forall a \in l, p(a)) = \forall a \in l, (q \lor p(a))$
Informal description
For any list $l$ of elements of type $\alpha$, any predicate $p : \alpha \to \text{Bool}$, and any boolean value $q$, the following equality holds: $$ q \lor (\forall a \in l, p(a)) = \forall a \in l, (q \lor p(a)) $$ where $\lor$ denotes logical OR and $\forall$ denotes universal quantification over the list elements.
List.or_all_distrib_right theorem
{l : List α} {p : α → Bool} {q : Bool} : (l.all p || q) = l.all fun a => p a || q
Full source
theorem or_all_distrib_right {l : List α} {p : α → Bool} {q : Bool} :
    (l.all p || q) = l.all fun a => p a || q := by
  induction l with simp | cons _ _ ih => rw [Bool.or_and_distrib_right, ih]
Right Distributivity of OR over ALL: $(\text{all}\ l\ p) \lor q = \text{all}\ l\ (\lambda a, p(a) \lor q)$
Informal description
For any list $l$ of elements of type $\alpha$, any predicate $p : \alpha \to \text{Bool}$, and any boolean value $q$, the following equality holds: $$(\text{all}\ l\ p) \lor q = \text{all}\ l\ (\lambda a, p(a) \lor q)$$ where $\text{all}\ l\ p$ denotes the boolean result of checking if all elements in $l$ satisfy $p$, and $\lor$ denotes logical OR.
List.any_eq_not_all_not theorem
{l : List α} {p : α → Bool} : l.any p = !l.all (!p .)
Full source
theorem any_eq_not_all_not {l : List α} {p : α → Bool} : l.any p = !l.all (!p .) := by
  simp only [not_all_eq_any_not, Bool.not_not]
Existential Quantifier on Lists as Negation of Universal Quantifier of Negation: $\text{any}\ l\ p = \neg (\text{all}\ l\ (\neg p))$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the boolean value indicating whether any element of $l$ satisfies $p$ is equal to the negation of the boolean value indicating whether all elements of $l$ satisfy $\neg p$. In symbols: $$\text{any}\ l\ p = \neg (\text{all}\ l\ (\neg p))$$
List.all_eq_not_any_not theorem
{l : List α} {p : α → Bool} : l.all p = !l.any (!p .)
Full source
theorem all_eq_not_any_not {l : List α} {p : α → Bool} : l.all p = !l.any (!p .) := by
  simp only [not_any_eq_all_not, Bool.not_not]
De Morgan's Law for List Quantifiers: $\text{all}\ l\ p = \neg \text{any}\ l\ (\neg p)$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the statement that all elements of $l$ satisfy $p$ is equivalent to the negation of the statement that any element of $l$ satisfies $\neg p$. In symbols: $$\text{all}\ l\ p = \neg (\text{any}\ l\ (\neg p))$$
List.any_map theorem
{l : List α} {p : β → Bool} : (l.map f).any p = l.any (p ∘ f)
Full source
@[simp] theorem any_map {l : List α} {p : β → Bool} : (l.map f).any p = l.any (p ∘ f) := by
  induction l with simp | cons _ _ ih => rw [ih]
Any Predicate on Mapped List Equals Any Composed Predicate on Original List
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \beta \to \text{Bool}$, the boolean value indicating whether any element of the mapped list $\text{map}\ f\ l$ satisfies $p$ is equal to the boolean value indicating whether any element of $l$ satisfies the composition $p \circ f$. In symbols: $$(\text{map}\ f\ l).\text{any}\ p = l.\text{any}\ (p \circ f)$$
List.all_map theorem
{l : List α} {p : β → Bool} : (l.map f).all p = l.all (p ∘ f)
Full source
@[simp] theorem all_map {l : List α} {p : β → Bool} : (l.map f).all p = l.all (p ∘ f) := by
  induction l with simp | cons _ _ ih => rw [ih]
All Elements of Mapped List Satisfy Predicate iff Original List Satisfies Composed Predicate
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \beta \to \text{Bool}$, the statement that all elements of the mapped list $l.\text{map}\ f$ satisfy $p$ is equivalent to the statement that all elements of $l$ satisfy the composition $p \circ f$. In symbols: $$(\text{map}\ f\ l).\text{all}\ p = l.\text{all}\ (p \circ f).$$
List.any_filter theorem
{l : List α} {p q : α → Bool} : (filter p l).any q = l.any fun a => p a && q a
Full source
@[simp] theorem any_filter {l : List α} {p q : α → Bool} :
    (filter p l).any q = l.any fun a => p a && q a := by
  induction l with
  | nil => rfl
  | cons h t ih =>
    simp only [filter_cons]
    split <;> simp_all
Any Predicate on Filtered List Equals Any Conjunction Predicate on Original List
Informal description
For any list $l$ of elements of type $\alpha$ and any predicates $p, q : \alpha \to \text{Bool}$, the boolean value indicating whether any element in the filtered list $\text{filter}\ p\ l$ satisfies $q$ is equal to the boolean value indicating whether any element $a$ in $l$ satisfies both $p(a)$ and $q(a)$. In symbols: $$(\text{filter}\ p\ l).\text{any}\ q = l.\text{any}\ (\lambda a.\ p\ a \land q\ a)$$
List.any_filterMap theorem
{l : List α} {f : α → Option β} {p : β → Bool} : (filterMap f l).any p = l.any fun a => match f a with | some b => p b | none => false
Full source
@[simp] theorem any_filterMap {l : List α} {f : α → Option β} {p : β → Bool} :
    (filterMap f l).any p = l.any fun a => match f a with | some b => p b | none => false := by
  induction l with
  | nil => rfl
  | cons h t ih =>
    simp only [filterMap_cons]
    split <;> simp_all
`any` over `filterMap` equals `any` over mapped options
Informal description
For any list `l : List α`, function `f : α → Option β`, and predicate `p : β → Bool`, the boolean value `(filterMap f l).any p` is equal to `l.any (fun a ↦ match f a with | some b => p b | none => false)`. In other words, checking if any element in the `filterMap` result satisfies `p` is equivalent to checking if any element in the original list `l` has a `f`-image that both exists (is `some b`) and satisfies `p`.
List.all_filterMap theorem
{l : List α} {f : α → Option β} {p : β → Bool} : (filterMap f l).all p = l.all fun a => match f a with | some b => p b | none => true
Full source
@[simp] theorem all_filterMap {l : List α} {f : α → Option β} {p : β → Bool} :
    (filterMap f l).all p = l.all fun a => match f a with | some b => p b | none => true := by
  induction l with
  | nil => rfl
  | cons h t ih =>
    simp only [filterMap_cons]
    split <;> simp_all
Universal Quantification over `filterMap` Equals Universal Quantification over Mapped Options
Informal description
For any list $l : \text{List } \alpha$, function $f : \alpha \to \text{Option } \beta$, and predicate $p : \beta \to \text{Bool}$, the following equality holds: \[ (\text{filterMap } f l).\text{all } p = l.\text{all } \left( \lambda a, \begin{cases} p b & \text{if } f a = \text{some } b \\ \text{true} & \text{if } f a = \text{none} \end{cases} \right) \]
List.any_append theorem
{xs ys : List α} : (xs ++ ys).any f = (xs.any f || ys.any f)
Full source
@[simp] theorem any_append {xs ys : List α} : (xs ++ ys).any f = (xs.any f || ys.any f) := by
  induction xs with
  | nil => rfl
  | cons h t ih => simp_all [Bool.or_assoc]
Disjunction of `any` over List Concatenation
Informal description
For any lists `xs` and `ys` of type `List α` and any predicate `f : α → Bool`, the boolean value `(xs ++ ys).any f` is equal to `xs.any f || ys.any f`. In other words, checking if any element in the concatenated list `xs ++ ys` satisfies `f` is equivalent to checking if any element in `xs` satisfies `f` or any element in `ys` satisfies `f`.
List.all_append theorem
{xs ys : List α} : (xs ++ ys).all f = (xs.all f && ys.all f)
Full source
@[simp] theorem all_append {xs ys : List α} : (xs ++ ys).all f = (xs.all f && ys.all f) := by
  induction xs with
  | nil => rfl
  | cons h t ih => simp_all [Bool.and_assoc]
Universal Quantification over List Concatenation: $(xs ++ ys).\text{all } f = xs.\text{all } f \land ys.\text{all } f$
Informal description
For any lists $xs$ and $ys$ of type $\text{List } \alpha$ and any predicate $f : \alpha \to \text{Bool}$, the following equality holds: \[ (xs ++ ys).\text{all } f = (xs.\text{all } f) \land (ys.\text{all } f) \]
List.any_flatten theorem
{l : List (List α)} : l.flatten.any f = l.any (any · f)
Full source
@[simp] theorem any_flatten {l : List (List α)} : l.flatten.any f = l.any (any · f) := by
  induction l <;> simp_all
Disjunction of `any` over List Flattening: $\text{flatten}(l).\text{any } f = l.\text{any } (\lambda xs, xs.\text{any } f)$
Informal description
For any list of lists $l : \text{List}(\text{List } \alpha)$ and any predicate $f : \alpha \to \text{Bool}$, the boolean value $\text{flatten}(l).\text{any } f$ is equal to $l.\text{any } (\lambda xs, xs.\text{any } f)$. In other words, checking if any element in the flattened list $\text{flatten}(l)$ satisfies $f$ is equivalent to checking if any sublist in $l$ contains an element that satisfies $f$.
List.any_join abbrev
Full source
@[deprecated any_flatten (since := "2024-10-14")] abbrev any_join := @any_flatten
Disjunction of `any` over List Joining: $\text{join}(l).\text{any } f = l.\text{any } (\lambda xs, xs.\text{any } f)$
Informal description
For any list of lists $l : \text{List}(\text{List } \alpha)$ and any predicate $f : \alpha \to \text{Bool}$, the boolean value $\text{join}(l).\text{any } f$ is equal to $l.\text{any } (\lambda xs, xs.\text{any } f)$. In other words, checking if any element in the joined list $\text{join}(l)$ satisfies $f$ is equivalent to checking if any sublist in $l$ contains an element that satisfies $f$.
List.all_flatten theorem
{l : List (List α)} : l.flatten.all f = l.all (all · f)
Full source
@[simp] theorem all_flatten {l : List (List α)} : l.flatten.all f = l.all (all · f) := by
  induction l <;> simp_all
Universal Quantification over Flattened List: $\text{all } f \ (\text{flatten } l) = \text{all } (\text{all } f) \ l$
Informal description
For any list of lists $l : \text{List}(\text{List } \alpha)$ and any predicate $f : \alpha \to \text{Bool}$, the following equality holds: \[ \text{all } f \ (\text{flatten } l) = \text{all } (\lambda xs \Rightarrow \text{all } f \ xs) \ l \] where $\text{flatten } l$ concatenates all the sublists in $l$, and $\text{all } f \ xs$ checks if $f$ holds for all elements in $xs$.
List.all_join abbrev
Full source
@[deprecated all_flatten (since := "2024-10-14")] abbrev all_join := @all_flatten
Universal Quantification over Joined List: $\text{all } p \ (\text{join } l) = \text{all } (\text{all } p) \ l$
Informal description
For any list of lists $l : \text{List}(\text{List } \alpha)$ and any predicate $p : \alpha \to \text{Bool}$, the following equality holds: \[ \text{all } p \ (\text{join } l) = \text{all } (\lambda xs \Rightarrow \text{all } p \ xs) \ l \] where $\text{join } l$ concatenates all the sublists in $l$, and $\text{all } p \ xs$ checks if $p$ holds for all elements in $xs$.
List.any_flatMap theorem
{l : List α} {f : α → List β} : (l.flatMap f).any p = l.any fun a => (f a).any p
Full source
@[simp] theorem any_flatMap {l : List α} {f : α → List β} :
    (l.flatMap f).any p = l.any fun a => (f a).any p := by
  induction l <;> simp_all
Disjunction of `any` over List FlatMap
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and any function $f : \alpha \to \text{List}\,\beta$, the boolean value $\text{any}\,p\,(l.\text{flatMap}\,f)$ is equal to $\text{any}\,(\lambda a \Rightarrow \text{any}\,p\,(f\,a))\,l$. In other words, checking if any element in the flattened list obtained by applying $f$ to each element of $l$ satisfies the predicate $p$ is equivalent to checking if any element $a$ in $l$ has a corresponding list $f\,a$ that contains an element satisfying $p$.
List.all_flatMap theorem
{l : List α} {f : α → List β} : (l.flatMap f).all p = l.all fun a => (f a).all p
Full source
@[simp] theorem all_flatMap {l : List α} {f : α → List β} :
    (l.flatMap f).all p = l.all fun a => (f a).all p := by
  induction l <;> simp_all
Universal Quantification over FlatMapped Lists: $\text{all } p \circ \text{flatMap } f = \text{all } (\text{all } p \circ f)$
Informal description
For any list $l$ of type $\text{List } \alpha$, any function $f : \alpha \to \text{List } \beta$, and any predicate $p : \beta \to \text{Bool}$, the following equality holds: \[ \text{all } p \ (\text{flatMap } f \ l) = \text{all } (\lambda a \Rightarrow \text{all } p \ (f \ a)) \ l \] where: - $\text{flatMap } f \ l$ is the concatenation of all lists obtained by applying $f$ to each element of $l$, - $\text{all } p \ l$ checks if all elements in $l$ satisfy the predicate $p$.
List.any_reverse theorem
{l : List α} : l.reverse.any f = l.any f
Full source
@[simp] theorem any_reverse {l : List α} : l.reverse.any f = l.any f := by
  induction l <;> simp_all [Bool.or_comm]
Reversing a List Preserves the `any` Predicate: $\text{any}\,f\,(l.\text{reverse}) = \text{any}\,f\,l$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and any predicate $f : \alpha \to \text{Bool}$, the boolean value $\text{any}\,f\,(l.\text{reverse})$ is equal to $\text{any}\,f\,l$. In other words, checking if any element in the reversed list satisfies $f$ is equivalent to checking if any element in the original list satisfies $f$.
List.all_reverse theorem
{l : List α} : l.reverse.all f = l.all f
Full source
@[simp] theorem all_reverse {l : List α} : l.reverse.all f = l.all f := by
  induction l <;> simp_all [Bool.and_comm]
Universal Quantification Preserved Under List Reversal: $\text{all } f \circ \text{reverse} = \text{all } f$
Informal description
For any list $l$ of type $\text{List } \alpha$ and any predicate $f : \alpha \to \text{Bool}$, the following equality holds: \[ \text{all } f \ (l.\text{reverse}) = \text{all } f \ l \] where: - $\text{all } f \ l$ checks if all elements in $l$ satisfy the predicate $f$, - $l.\text{reverse}$ is the reversed list of $l$.
List.any_replicate theorem
{n : Nat} {a : α} : (replicate n a).any f = if n = 0 then false else f a
Full source
@[simp] theorem any_replicate {n : Nat} {a : α} :
    (replicate n a).any f = if n = 0 then false else f a := by
  cases n <;> simp [replicate_succ]
Predicate Any on Replicated List: $\text{any } f \ (\text{replicate } n \ a) = \text{if } n = 0 \text{ then false else } f(a)$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the predicate `f` applied to the list `replicate n a` (a list containing $n$ copies of $a$) satisfies: \[ \text{any } f \ (\text{replicate } n \ a) = \begin{cases} \text{false} & \text{if } n = 0 \\ f(a) & \text{otherwise} \end{cases} \]
List.all_replicate theorem
{n : Nat} {a : α} : (replicate n a).all f = if n = 0 then true else f a
Full source
@[simp] theorem all_replicate {n : Nat} {a : α} :
    (replicate n a).all f = if n = 0 then true else f a := by
  cases n <;> simp +contextual [replicate_succ]
Universal Quantification over Replicated List: $(\text{replicate } n\ a).\text{all } f = \text{ite}(n = 0, \text{true}, f(a))$
Informal description
For any natural number $n$ and element $a$ of type $\alpha$, the predicate `f` holds for all elements of the list `replicate n a` (which contains $n$ copies of $a$) if and only if either $n = 0$ (in which case the list is empty and the condition is vacuously true) or `f a` holds (when $n > 0$). In other words, $$(\text{replicate } n\ a).\text{all } f = \begin{cases} \text{true} & \text{if } n = 0 \\ f(a) & \text{otherwise.} \end{cases}$$
List.any_insert theorem
[BEq α] [LawfulBEq α] {l : List α} {a : α} : (l.insert a).any f = (f a || l.any f)
Full source
@[simp] theorem any_insert [BEq α] [LawfulBEq α] {l : List α} {a : α} :
    (l.insert a).any f = (f a || l.any f) := by
  simp [any_eq]
Insertion Preserves Any: $\text{any}(l.\text{insert}(a), f) = f(a) \lor \text{any}(l, f)$
Informal description
For any list $l$ of elements of type $\alpha$ with decidable equality, and any element $a \in \alpha$, the boolean evaluation of `any` over the list obtained by inserting $a$ into $l$ is equal to the boolean OR of $f(a)$ and the `any` evaluation over $l$. That is, $\text{any}(l.\text{insert}(a), f) = (f(a) \lor \text{any}(l, f))$.
List.all_insert theorem
[BEq α] [LawfulBEq α] {l : List α} {a : α} : (l.insert a).all f = (f a && l.all f)
Full source
@[simp] theorem all_insert [BEq α] [LawfulBEq α] {l : List α} {a : α} :
    (l.insert a).all f = (f a && l.all f) := by
  simp [all_eq]
Insertion Preserves Universal Quantification: $\text{all}(l.\text{insert}(a), f) = f(a) \land \text{all}(l, f)$
Informal description
For any list $l$ of elements of type $\alpha$ with decidable equality, and any element $a \in \alpha$, the boolean evaluation of `all` over the list obtained by inserting $a$ into $l$ is equal to the boolean AND of $f(a)$ and the `all` evaluation over $l$. That is, $\text{all}(l.\text{insert}(a), f) = (f(a) \land \text{all}(l, f))$.
List.get_cons_zero theorem
: get (a :: l) (0 : Fin (l.length + 1)) = a
Full source
theorem get_cons_zero : get (a::l) (0 : Fin (l.length + 1)) = a := rfl
First Element of Cons List: $(a :: l)[0] = a$
Informal description
For any element $a$ of type $\alpha$ and any list $l$ of elements of type $\alpha$, the element at index $0$ in the list obtained by prepending $a$ to $l$ is equal to $a$. That is, $(a :: l)[0] = a$.
List.get_cons_succ theorem
{as : List α} {h : i + 1 < (a :: as).length} : (a :: as).get ⟨i + 1, h⟩ = as.get ⟨i, Nat.lt_of_succ_lt_succ h⟩
Full source
theorem get_cons_succ {as : List α} {h : i + 1 < (a :: as).length} :
  (a :: as).get ⟨i+1, h⟩ = as.get ⟨i, Nat.lt_of_succ_lt_succ h⟩ := rfl
Successor Index Access in Cons List: $(a :: as)[i + 1] = as[i]$
Informal description
For any list `as` of elements of type `α`, any element `a` of type `α`, and any natural number `i` such that `i + 1` is less than the length of the list `a :: as`, the element at position `i + 1` in the list `a :: as` is equal to the element at position `i` in the list `as`. In mathematical notation: Given $as \in \text{List}(\alpha)$, $a \in \alpha$, and $i \in \mathbb{N}$ with $i + 1 < \text{length}(a :: as)$, we have $(a :: as)[i + 1] = as[i]$.
List.get_cons_succ' theorem
{as : List α} {i : Fin as.length} : (a :: as).get i.succ = as.get i
Full source
theorem get_cons_succ' {as : List α} {i : Fin as.length} :
  (a :: as).get i.succ = as.get i := rfl
Successor Index Access in Cons List
Informal description
For any list `as` of elements of type $\alpha$, any element $a$ of type $\alpha$, and any index $i$ of type `Fin as.length` (a natural number less than the length of `as`), the element at position `i.succ` in the list `a :: as` is equal to the element at position `i` in the list `as`. In other words, if $i$ is a valid index for `as`, then the $(i+1)$-th element of the list `a :: as` is the $i$-th element of `as$.
List.get_mk_zero theorem
: ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos_iff.mp h)
Full source
theorem get_mk_zero : ∀ {l : List α} (h : 0 < l.length), l.get ⟨0, h⟩ = l.head (length_pos_iff.mp h)
  | _::_, _ => rfl
First Element Equals Head in Non-Empty List: $l[0] = \text{head}(l)$
Informal description
For any non-empty list $l$ of elements of type $\alpha$ (i.e., $0 < \text{length}(l)$), the element at position $0$ in $l$ is equal to the head of the list.
List.get?_zero theorem
(l : List α) : l.get? 0 = l.head?
Full source
@[deprecated "Use `a[0]?` instead." (since := "2025-02-12")]
theorem get?_zero (l : List α) : l.get? 0 = l.head? := by cases l <;> rfl
First Element Access via `get?` Equals Head of List
Informal description
For any list $l$ of elements of type $\alpha$, the result of accessing the element at index $0$ via `get?` is equal to the head of the list (which may be `none` if the list is empty).
List.get_of_eq theorem
{l l' : List α} (h : l = l') (i : Fin l.length) : get l i = get l' ⟨i, h ▸ i.2⟩
Full source
/--
If one has `l.get i` in an expression (with `i : Fin l.length`) and `h : l = l'`,
`rw [h]` will give a "motive is not type correct" error, as it cannot rewrite the
`i : Fin l.length` to `Fin l'.length` directly. The theorem `get_of_eq` can be used to make
such a rewrite, with `rw [get_of_eq h]`.
-/
theorem get_of_eq {l l' : List α} (h : l = l') (i : Fin l.length) :
    get l i = get l' ⟨i, h ▸ i.2⟩ := by cases h; rfl
List Element Preservation Under Equality: $\text{get } l i = \text{get } l' \langle i, h \rangle$
Informal description
Given two lists $l$ and $l'$ of elements of type $\alpha$ such that $l = l'$, and an index $i$ of type $\text{Fin } l.\text{length}$ (i.e., a natural number less than the length of $l$), the element at position $i$ in $l$ is equal to the element at position $\langle i, h \rangle$ in $l'$, where $\langle i, h \rangle$ is the same index $i$ but with a proof that it is less than the length of $l'$ (which follows from $h : l = l'$).
List.get!_of_get? theorem
[Inhabited α] : ∀ {l : List α} {n}, get? l n = some a → get! l n = a
Full source
@[deprecated "Use `a[i]?` instead." (since := "2025-02-12")]
theorem get!_of_get? [Inhabited α] : ∀ {l : List α} {n}, get? l n = some a → get! l n = a
  | _a::_, 0, rfl => rfl
  | _::l, _+1, e => get!_of_get? (l := l) e
`get!` returns value when `get?` succeeds
Informal description
For any inhabited type $\alpha$, given a list $l$ of elements of type $\alpha$ and a natural number $n$, if the `get?` operation on $l$ at index $n$ returns `some a`, then the `get!` operation on $l$ at index $n$ returns $a$.
List.get!_len_le theorem
[Inhabited α] : ∀ {l : List α} {n}, length l ≤ n → l.get! n = (default : α)
Full source
@[deprecated "Use `a[i]!` instead." (since := "2025-02-12")]
theorem get!_len_le [Inhabited α] : ∀ {l : List α} {n}, length l ≤ n → l.get! n = (default : α)
  | [], _, _ => rfl
  | _ :: l, _+1, h => get!_len_le (l := l) <| Nat.le_of_succ_le_succ h
Default Value Returned by `get!` When Index Exceeds List Length
Informal description
For any inhabited type $\alpha$, given a list $l$ of elements of type $\alpha$ and a natural number $n$, if the length of $l$ is less than or equal to $n$, then the `get!` operation on $l$ at index $n$ returns the default value of $\alpha$.
List.getElem!_nil theorem
[Inhabited α] {n : Nat} : ([] : List α)[n]! = default
Full source
theorem getElem!_nil [Inhabited α] {n : Nat} : ([] : List α)[n]! = default := rfl
Default Value for Empty List Access via `get!`
Informal description
For any inhabited type $\alpha$ and natural number $n$, the element at position $n$ of the empty list (using the `get!` operation) is equal to the default value of $\alpha$.
List.getElem!_cons_zero theorem
[Inhabited α] {l : List α} : (a :: l)[0]! = a
Full source
theorem getElem!_cons_zero [Inhabited α] {l : List α} : (a::l)[0]! = a := by
  rw [getElem!_pos] <;> simp
Forced Access on Cons List at Zero Index Yields Head Element: $(a :: l)[0]! = a$
Informal description
For any inhabited type $\alpha$ and list $l$ of type $\text{List}\ \alpha$, the forced access operation on the cons list $(a :: l)$ at index $0$ returns the head element $a$, i.e., $(a :: l)[0]! = a$.
List.getElem!_cons_succ theorem
[Inhabited α] {l : List α} : (a :: l)[i + 1]! = l[i]!
Full source
theorem getElem!_cons_succ [Inhabited α] {l : List α} : (a::l)[i+1]! = l[i]! := by
  by_cases h : i < l.length
  · rw [getElem!_pos, getElem!_pos] <;> simp_all [Nat.succ_lt_succ_iff]
  · rw [getElem!_neg, getElem!_neg] <;> simp_all [Nat.succ_lt_succ_iff]
Forced Access on Cons List at Successor Index: $(a :: l)[i+1]! = l[i]!$
Informal description
For any inhabited type $\alpha$, list $l$ of type $\text{List}\ \alpha$, and natural number index $i$, the forced access operation on the cons list $(a :: l)$ at index $i+1$ equals the forced access operation on $l$ at index $i$, i.e., $(a :: l)[i+1]! = l[i]!$.
List.getElem!_of_getElem? theorem
[Inhabited α] : ∀ {l : List α} {i : Nat}, l[i]? = some a → l[i]! = a
Full source
theorem getElem!_of_getElem? [Inhabited α] : ∀ {l : List α} {i : Nat}, l[i]? = some a → l[i]! = a
  | _a::_, 0, _ => by
    rw [getElem!_pos] <;> simp_all
  | _::l, _+1, e => by
    simp at e
    simp_all [getElem!_of_getElem? (l := l) e]
Forced List Access Yields Element When Optional Access Succeeds: $l[i]! = a$ when $l[i]? = \text{some}\ a$
Informal description
For any inhabited type $\alpha$, list $l$ of type $\text{List}\ \alpha$, and natural number index $i$, if the optional indexing operation $l[i]?$ returns $\text{some}\ a$, then the forced access operation $l[i]!$ returns $a$.
List.ext_get theorem
{l₁ l₂ : List α} (hl : length l₁ = length l₂) (h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂
Full source
theorem ext_get {l₁ l₂ : List α} (hl : length l₁ = length l₂)
    (h : ∀ n h₁ h₂, get l₁ ⟨n, h₁⟩ = get l₂ ⟨n, h₂⟩) : l₁ = l₂ :=
  ext_getElem hl (by simp_all)
List Equality via Index-wise Element Access
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, if they have the same length and for every natural number $n$ and proofs $h_1 : n < \text{length}\,l_1$, $h_2 : n < \text{length}\,l_2$, the elements $l_1[n]$ and $l_2[n]$ are equal, then $l_1 = l_2$.
List.get_of_mem theorem
{a} {l : List α} (h : a ∈ l) : ∃ n, get l n = a
Full source
theorem get_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, get l n = a := by
  obtain ⟨n, h, e⟩ := getElem_of_mem h
  exact ⟨⟨n, h⟩, e⟩
Existence of Index for List Membership: $a \in l \implies \exists n, l[n] = a$
Informal description
For any element $a$ and list $l$ of type $\alpha$, if $a$ is a member of $l$ (i.e., $a \in l$), then there exists a valid index $n$ such that the element at position $n$ in $l$ equals $a$.
List.get?_of_mem theorem
{a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a
Full source
@[deprecated getElem?_of_mem (since := "2025-02-12")]
theorem get?_of_mem {a} {l : List α} (h : a ∈ l) : ∃ n, l.get? n = some a :=
  let ⟨⟨n, _⟩, e⟩ := get_of_mem h; ⟨n, e ▸ get?_eq_get _⟩
Existence of Valid Index for List Membership via Optional Access: $a \in l \implies \exists n, l[n]? = \text{some}(a)$
Informal description
For any element $a$ and list $l$ of type $\alpha$, if $a$ is a member of $l$ (i.e., $a \in l$), then there exists a natural number $n$ such that the optional element access $l[n]?$ returns $\text{some}(a)$.
List.get_mem theorem
: ∀ (l : List α) n, get l n ∈ l
Full source
theorem get_mem : ∀ (l : List α) n, getget l n ∈ l
  | _ :: _, ⟨0, _⟩ => .head ..
  | _ :: l, ⟨_+1, _⟩ => .tail _ (get_mem l ..)
Element at Valid Index Belongs to List
Informal description
For any list $l$ of elements of type $\alpha$ and any valid index $n$ (where $n$ is a natural number less than the length of $l$), the element obtained by `get l n` is a member of the list $l$.
List.mem_of_get? theorem
{l : List α} {n a} (e : l.get? n = some a) : a ∈ l
Full source
@[deprecated mem_of_getElem? (since := "2025-02-12")]
theorem mem_of_get? {l : List α} {n a} (e : l.get? n = some a) : a ∈ l :=
  let ⟨_, e⟩ := get?_eq_some_iff.1 e; e ▸ get_mem ..
Membership from Successful List Element Access
Informal description
For any list $l$ of elements of type $\alpha$, natural number $n$, and element $a$, if the optional element access $l[n]?$ returns $\text{some}(a)$, then $a$ is a member of the list $l$.
List.mem_iff_get theorem
{a} {l : List α} : a ∈ l ↔ ∃ n, get l n = a
Full source
theorem mem_iff_get {a} {l : List α} : a ∈ la ∈ l ↔ ∃ n, get l n = a :=
  ⟨get_of_mem, fun ⟨_, e⟩ => e ▸ get_mem ..⟩
List Membership Characterization via Indexed Access
Informal description
For any element $a$ and list $l$ of type $\alpha$, the element $a$ is a member of $l$ if and only if there exists a valid index $n$ (i.e., $n < \text{length}(l)$) such that the element at position $n$ in $l$ equals $a$. In other words: $$ a \in l \leftrightarrow \exists n \in \text{Fin}(\text{length}(l)),\ l[n] = a $$
List.mem_iff_get? theorem
{a} {l : List α} : a ∈ l ↔ ∃ n, l.get? n = some a
Full source
@[deprecated mem_iff_getElem? (since := "2025-02-12")]
theorem mem_iff_get? {a} {l : List α} : a ∈ la ∈ l ↔ ∃ n, l.get? n = some a := by
  simp [getElem?_eq_some_iff, Fin.exists_iff, mem_iff_get]
List Membership Characterization via Optional Indexed Access: $a \in l \leftrightarrow \exists n, l[n]? = a$
Informal description
For any element $a$ and list $l$ of type $\alpha$, the element $a$ is a member of $l$ if and only if there exists a natural number $n$ such that the optional lookup operation $l[n]?$ returns $\text{some}(a)$. In other words: $$ a \in l \leftrightarrow \exists n \in \mathbb{N},\ l[n]? = a $$
List.getElem_eq_getElem? abbrev
Full source
@[deprecated getElem_eq_getElem?_get (since := "2024-09-04")] abbrev getElem_eq_getElem? :=
  @getElem_eq_getElem?_get
Equality of List Indexing and Optional Lookup for Valid Indices: $l[i] = l[i]?.get$
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$ such that $i < \text{length}(l)$, the $i$-th element of $l$ equals the value obtained from the optional lookup $l[i]?$ when it is non-empty (i.e., $l[i] = l[i]?.get$).
List.join_eq_nil abbrev
Full source
@[deprecated flatten_eq_nil_iff (since := "2024-09-05")] abbrev join_eq_nil := @flatten_eq_nil_iff
Concatenation of Lists is Empty if and Only if All Sublists are Empty
Informal description
For any list of lists $L$ of elements of type $\alpha$, the concatenation of all lists in $L$ (denoted by $\text{join}(L)$) is the empty list if and only if every list $l$ in $L$ is itself empty. That is, $\text{join}(L) = [] \leftrightarrow \forall l \in L, l = []$.
List.join_ne_nil abbrev
Full source
@[deprecated flatten_ne_nil_iff (since := "2024-09-05")] abbrev join_ne_nil := @flatten_ne_nil_iff
Non-empty Concatenation of Lists iff Contains Non-empty Sublist
Informal description
For any list of lists $xss$ of elements of type $\alpha$, the concatenation of all lists in $xss$ (denoted by $\text{join}(xss)$) is non-empty if and only if there exists a non-empty list $xs$ in $xss$. That is, $\text{join}(xss) \neq [] \leftrightarrow \exists xs \in xss, xs \neq []$.
List.join_eq_cons_iff abbrev
Full source
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons_iff := @flatten_eq_cons_iff
Characterization of List Concatenation as Cons: $\text{join}(xss) = y :: ys$
Informal description
For a list of lists `xss` of elements of type $\alpha$, an element `y : α`, and a list `ys : List α$, the concatenation of all lists in `xss` (denoted $\text{join}(xss)$) equals the list `y :: ys` if and only if there exist lists `as`, `bs`, and `cs` such that: 1. `xss` can be written as the concatenation `as ++ (y :: bs) :: cs`, 2. Every list in `as` is empty, and 3. `ys` is equal to the concatenation `bs ++ cs.flatten`.
List.join_eq_cons abbrev
Full source
@[deprecated flatten_eq_cons_iff (since := "2024-09-05")] abbrev join_eq_cons := @flatten_eq_cons_iff
Characterization of Flattened List as Cons: $\text{flatten}(xss) = y :: ys$
Informal description
For a list of lists `xss` of elements of type $\alpha$, an element `y : α`, and a list `ys : List α$, the flattening of `xss` equals the list `y :: ys` if and only if there exist lists `as`, `bs`, and `cs` such that: 1. `xss` can be written as the concatenation `as ++ (y :: bs) :: cs`, 2. Every list in `as` is empty, and 3. `ys` is equal to the concatenation `bs ++ cs.flatten`.
List.join_eq_append abbrev
Full source
@[deprecated flatten_eq_append_iff (since := "2024-09-05")] abbrev join_eq_append := @flatten_eq_append_iff
Characterization of List Flattening as Concatenation: $\text{join}(xss) = ys \mathbin{+\kern-0.5em+} zs$
Informal description
For any list of lists `xss` of elements of type $\alpha$ and lists `ys`, `zs` of elements of type $\alpha$, the flattening of `xss` (denoted $\text{join}(xss)$) equals the concatenation of `ys` and `zs` (denoted $ys \mathbin{+\kern-0.5em+} zs$) if and only if either: 1. There exist lists `as` and `bs` such that `xss = as ++ bs`, `ys = \text{join}(as)`, and `zs = \text{join}(bs)`, or 2. There exist lists `as`, `bs`, `c`, `cs`, `ds` such that `xss = as ++ (bs ++ c :: cs) :: ds`, `ys = \text{join}(as) ++ bs`, and `zs = c :: cs ++ \text{join}(ds)`.
List.getElem?_mem abbrev
Full source
@[deprecated mem_of_getElem? (since := "2024-09-06")] abbrev getElem?_mem := @mem_of_getElem?
Membership from Optional Indexing: $l[i]? = \text{some}\,a \implies a \in l$
Informal description
For any list $l$ of type $\text{List}\,\alpha$, natural number index $i$, and element $a \in \alpha$, if the optional indexing operation $l[i]?$ returns $\text{some}\,a$, then $a$ is a member of $l$. In symbols: $$l[i]? = \text{some}\,a \implies a \in l$$
List.getElem_set_eq abbrev
Full source
@[deprecated getElem_set_self (since := "2024-09-04")] abbrev getElem_set_eq := @getElem_set_self
Element Replacement at Valid Index: $(l[i \mapsto a])[i] = a$
Informal description
For any list $l$ of elements of type $\alpha$, any natural number index $i$, and any element $a$ of type $\alpha$, if $i$ is a valid index for $l$ (i.e., $i < \text{length}(l)$), then the $i$-th element of the list obtained by replacing the $i$-th element of $l$ with $a$ equals $a$, i.e., $(l.\text{set}(i, a))[i] = a$.
List.getElem?_set_eq abbrev
Full source
@[deprecated getElem?_set_self (since := "2024-09-04")] abbrev getElem?_set_eq := @getElem?_set_self
Optional Indexing After List Replacement: $(l[i \mapsto a])[i]? = \text{some}(a)$ for Valid Indices
Informal description
For any list $l$ of elements of type $\alpha$, any natural number index $i$, and any element $a$ of type $\alpha$, if $i$ is a valid index for $l$ (i.e., $i < \text{length}(l)$), then the optional indexing operation on the modified list $(l.\text{set}(i, a))[i]?$ returns $\text{some}(a)$.
List.set_eq_nil abbrev
Full source
@[deprecated set_eq_nil_iff (since := "2024-09-05")] abbrev set_eq_nil := @set_eq_nil_iff
Empty List Preservation Under Element Replacement: $l[i \mapsto a] = [] \Rightarrow l = []$
Informal description
For any list $l$ of elements of type $\alpha$, any natural number index $i$, and any element $a \in \alpha$, if the list obtained by setting the $i$-th element of $l$ to $a$ is empty, then the original list $l$ is empty. In other words, $l[i \mapsto a] = []$ implies $l = []$.
List.join_nil abbrev
Full source
@[deprecated flatten_nil (since := "2024-10-14")] abbrev join_nil := @flatten_nil
Join of Empty List is Empty
Informal description
The join operation applied to the empty list results in the empty list, i.e., $\text{join}([]) = []$.
List.join_cons abbrev
Full source
@[deprecated flatten_cons (since := "2024-10-14")] abbrev join_cons := @flatten_cons
Join of Cons List Equals Append of Head and Join of Tail
Informal description
For any element $x$ of type $\alpha$ and any list $L$ of type $\text{List} (\text{List} \alpha)$, the join operation satisfies $\text{join}(x :: L) = x ++ \text{join}(L)$, where $::$ denotes list cons and $++$ denotes list append.
List.length_join abbrev
Full source
@[deprecated length_flatten (since := "2024-10-14")] abbrev length_join := @length_flatten
Length of Concatenated List Equals Sum of Sublist Lengths
Informal description
For any list of lists $L$ of elements of type $\alpha$, the length of the concatenated list $\text{join}(L)$ is equal to the sum of the lengths of the sublists in $L$. That is, $$ \text{length}(\text{join}(L)) = \sum_{l \in L} \text{length}(l). $$
List.join_singleton abbrev
Full source
@[deprecated flatten_singleton (since := "2024-10-14")] abbrev join_singleton := @flatten_singleton
Join of Singleton List Equals Its Element
Informal description
For any list $l$ of elements of type $\alpha$, the join operation on the singleton list containing $l$ is equal to $l$ itself, i.e., $\text{join}([l]) = l$.
List.mem_join abbrev
Full source
@[deprecated mem_flatten (since := "2024-10-14")] abbrev mem_join := @mem_flatten
Membership in Concatenated List: $a \in \text{join}(L) \leftrightarrow \exists l \in L, a \in l$
Informal description
For any list of lists $L$ of elements of type $\alpha$, an element $a$ belongs to the concatenated list $\text{join}(L)$ if and only if there exists a sublist $l \in L$ such that $a \in l$.
List.join_eq_nil_iff abbrev
Full source
@[deprecated flatten_eq_nil_iff (since := "2024-10-14")] abbrev join_eq_nil_iff := @flatten_eq_nil_iff
Concatenation of Lists is Empty if and Only if All Sublists are Empty
Informal description
For a list of lists $L$ of elements of type $\alpha$, the concatenation (join) of all lists in $L$ is the empty list if and only if every list $l$ in $L$ is itself empty. That is, $\text{join}(L) = [] \leftrightarrow \forall l \in L, l = []$.
List.join_ne_nil_iff abbrev
Full source
@[deprecated flatten_ne_nil_iff (since := "2024-10-14")] abbrev join_ne_nil_iff := @flatten_ne_nil_iff
Non-empty Concatenation of Lists iff Contains Non-empty Sublist
Informal description
For a list of lists `xss` of elements of type $\alpha$, the concatenation (join) of all lists in `xss` is non-empty if and only if there exists a non-empty sublist `xs` in `xss$. That is, $\text{join}(xss) \neq [] \leftrightarrow \exists xs \in xss, xs \neq []$.
List.exists_of_mem_join abbrev
Full source
@[deprecated exists_of_mem_flatten (since := "2024-10-14")] abbrev exists_of_mem_join := @exists_of_mem_flatten
Existence of Sublist Containing Element in Concatenated List
Informal description
For any element $a$ and list of lists $L$, if $a$ is a member of the concatenated list $\text{join}(L)$, then there exists a sublist $l \in L$ such that $a \in l$.
List.mem_join_of_mem abbrev
Full source
@[deprecated mem_flatten_of_mem (since := "2024-10-14")] abbrev mem_join_of_mem := @mem_flatten_of_mem
Element in Sublist Implies Element in Joined List
Informal description
For any list of lists $L$ of elements of type $\alpha$, if $a$ is an element of a sublist $l$ in $L$ (i.e., $a \in l$ and $l \in L$), then $a$ is an element of the joined list $\text{join}(L)$.
List.forall_mem_join abbrev
Full source
@[deprecated forall_mem_flatten (since := "2024-10-14")] abbrev forall_mem_join := @forall_mem_flatten
Universal Quantification over Joined List Equals Nested Universal Quantification
Informal description
For any predicate $p : \alpha \to \text{Prop}$ and list of lists $L : \text{List} (\text{List} \alpha)$, the following are equivalent: 1. For every element $x$ in the joined list $\text{join}\ L$, the proposition $p(x)$ holds. 2. For every sublist $l$ in $L$ and every element $x$ in $l$, the proposition $p(x)$ holds. In other words, $\forall x \in \text{join}\ L, p(x) \leftrightarrow \forall l \in L, \forall x \in l, p(x)$.
List.join_eq_bind abbrev
Full source
@[deprecated flatten_eq_flatMap (since := "2024-10-14")] abbrev join_eq_bind := @flatten_eq_flatMap
Join Equals Bind with Identity Function
Informal description
For any list of lists $L$ of elements of type $\alpha$, the concatenation (join) of $L$ is equal to the monadic bind operation of $L$ with the identity function. That is, $$\text{join}(L) = L \mathbin{>>=} \text{id}.$$
List.head?_join abbrev
Full source
@[deprecated head?_flatten (since := "2024-10-14")] abbrev head?_join := @head?_flatten
Head of Concatenated List as First Non-Empty Sublist Head
Informal description
For any list of lists $L$ of elements of type $\alpha$, the head of the concatenated list $\text{join}(L)$ (as an optional value) is equal to the first non-`none` result of applying $\text{head?}$ to each sublist in $L$. More precisely, $\text{head?}(\text{join}(L)) = \text{findSome?} (\lambda l, \text{head?}(l)) L$.
List.foldl_join abbrev
Full source
@[deprecated foldl_flatten (since := "2024-10-14")] abbrev foldl_join := @foldl_flatten
Left Fold Distributes Over List Concatenation
Informal description
For any binary operation $f : \beta \to \alpha \to \beta$, initial value $b \in \beta$, and list of lists $L : \text{List}(\text{List } \alpha)$, the left fold of the concatenated list $\text{join}(L)$ with operation $f$ and initial value $b$ is equal to the left fold of $L$ with the operation $\lambda b' \ l. \text{foldl } f \ b' \ l$ and initial value $b$. In symbols: $$\text{foldl } f \ b \ (\text{join } L) = \text{foldl } (\lambda b' \ l. \text{foldl } f \ b' \ l) \ b \ L$$
List.foldr_join abbrev
Full source
@[deprecated foldr_flatten (since := "2024-10-14")] abbrev foldr_join := @foldr_flatten
Right Fold Distributes Over List Concatenation
Informal description
For any binary operation $f : \alpha \to \beta \to \beta$, initial value $b \in \beta$, and list of lists $L : \text{List}(\text{List } \alpha)$, the right fold of the concatenated list $\text{join}(L)$ with operation $f$ and initial value $b$ is equal to the right fold of $L$ with the operation $\lambda l \ b'. \text{foldr } f \ b' \ l$ and initial value $b$. In symbols: $$\text{foldr } f \ b \ (\text{join } L) = \text{foldr } (\lambda l \ b'. \text{foldr } f \ b' \ l) \ b \ L$$
List.map_join abbrev
Full source
@[deprecated map_flatten (since := "2024-10-14")] abbrev map_join := @map_flatten
Map-Join Commutativity: $\text{map } f \circ \text{join} = \text{join} \circ \text{map } (\text{map } f)$
Informal description
For any function $f : \alpha \to \beta$ and any list of lists $L : \text{List}(\text{List} \alpha)$, mapping $f$ over the joined list $\text{join}(L)$ is equivalent to first mapping $f$ over each sublist in $L$ and then joining the result. That is, $$ \text{map } f (\text{join } L) = \text{join } (\text{map } (\text{map } f) L). $$
List.filterMap_join abbrev
Full source
@[deprecated filterMap_flatten (since := "2024-10-14")] abbrev filterMap_join := @filterMap_flatten
`filterMap` Commutes with List Concatenation
Informal description
For any function $f : \alpha \to \text{Option } \beta$ and any list of lists $L : \text{List } (\text{List } \alpha)$, applying the `filterMap` operation to the concatenated list is equivalent to first mapping `filterMap f` over each sublist in $L$ and then concatenating the results. That is, $$\text{filterMap } f (\text{join } L) = \text{join } (\text{map } (\text{filterMap } f) L).$$
List.filter_join abbrev
Full source
@[deprecated filter_flatten (since := "2024-10-14")] abbrev filter_join := @filter_flatten
Filter-Join Commutativity: $\text{filter } p \circ \text{join} = \text{join} \circ \text{map } (\text{filter } p)$
Informal description
For any predicate $p \colon \alpha \to \text{Bool}$ and any list of lists $L \colon \text{List}(\text{List} \ \alpha)$, filtering the concatenated list $\text{join}(L)$ with $p$ is equivalent to first filtering each sublist in $L$ with $p$ and then concatenating the result. That is, \[ \text{filter } p (\text{join } L) = \text{join } (\text{map } (\text{filter } p) L). \]
List.join_filter_not_isEmpty abbrev
Full source
@[deprecated flatten_filter_not_isEmpty (since := "2024-10-14")] abbrev join_filter_not_isEmpty := @flatten_filter_not_isEmpty
Flattening Non-Empty Sublists is Equivalent to Flattening All Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, flattening the sublists of $L$ that are non-empty is equal to flattening the entire list $L$. That is, \[ \text{flatten} \big(\text{filter} (\lambda l \Rightarrow \neg l.\text{isEmpty}) L\big) = \text{flatten} L. \]
List.join_filter_ne_nil abbrev
Full source
@[deprecated flatten_filter_ne_nil (since := "2024-10-14")] abbrev join_filter_ne_nil := @flatten_filter_ne_nil
Flattening Non-Empty Sublists Equals Flattening All Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, where the predicate "is not the empty list" is decidable, flattening the sublists of $L$ that are non-empty is equal to flattening the entire list $L$. That is, \[ \text{flatten} \big(\text{filter} (\lambda l \Rightarrow l \neq []) L\big) = \text{flatten} L. \]
List.join_append abbrev
Full source
@[deprecated flatten_append (since := "2024-10-14")] abbrev join_append := @flatten_append
Join Distributes Over List Concatenation: $\text{join}(L_1) \mathbin{+\kern-0.5em+} \text{join}(L_2) = \text{join}(L_1 \mathbin{+\kern-0.5em+} L_2)$
Informal description
For any two lists of lists $L_1$ and $L_2$ of elements of type $\alpha$, the concatenation of their joins (flattenings) is equal to the join of their concatenation: $\text{join}(L_1) \mathbin{+\kern-0.5em+} \text{join}(L_2) = \text{join}(L_1 \mathbin{+\kern-0.5em+} L_2)$.
List.join_concat abbrev
Full source
@[deprecated flatten_concat (since := "2024-10-14")] abbrev join_concat := @flatten_concat
Flattening of Concatenation with Singleton List: $\text{join}(L \mathbin{+\kern-0.5em+} [l]) = \text{join}(L) \mathbin{+\kern-0.5em+} l$
Informal description
For any list of lists $L$ of elements of type $\alpha$ and any list $l$ of elements of type $\alpha$, the flattening (join) of the concatenation $L \mathbin{+\kern-0.5em+} [l]$ is equal to the concatenation of the flattening of $L$ with $l$, i.e., $\text{join}(L \mathbin{+\kern-0.5em+} [l]) = \text{join}(L) \mathbin{+\kern-0.5em+} l$.
List.join_join abbrev
Full source
@[deprecated flatten_flatten (since := "2024-10-14")] abbrev join_join := @flatten_flatten
Double Flattening Equals Flattening of Mapped Flatten: $\text{flatten}(\text{flatten}(L)) = \text{flatten}(\text{map}(\text{flatten}, L))$
Informal description
For any list of lists of lists $L$ of elements of type $\alpha$, the flattening of the flattening of $L$ is equal to the flattening of the list obtained by mapping the flatten operation over each inner list in $L$. That is, $\text{flatten}(\text{flatten}(L)) = \text{flatten}(\text{map}(\text{flatten}, L))$.
List.join_eq_append_iff abbrev
Full source
@[deprecated flatten_eq_append_iff (since := "2024-10-14")] abbrev join_eq_append_iff := @flatten_eq_append_iff
Characterization of Flattening as Concatenation: $\text{flatten}(xss) = ys \mathbin{+\kern-0.5em+} zs$
Informal description
For a list of lists `xss` of elements of type $\alpha$ and two lists `ys`, `zs` of elements of type $\alpha$, the flattening of `xss` equals the concatenation `ys ++ zs` if and only if either: 1. There exist lists `as` and `bs` such that `xss = as ++ bs`, `ys = as.flatten`, and `zs = bs.flatten`, or 2. There exist lists `as`, `bs`, `c`, `cs`, `ds` such that `xss = as ++ (bs ++ c :: cs) :: ds`, `ys = as.flatten ++ bs`, and `zs = c :: cs ++ ds.flatten`.
List.join_replicate_nil abbrev
Full source
@[deprecated flatten_replicate_nil (since := "2024-10-14")] abbrev join_replicate_nil := @flatten_replicate_nil
Join of Replicated Empty Lists is Empty
Informal description
For any natural number $n$, the join (flatten) of a list consisting of $n$ empty lists is itself an empty list. That is, $\text{join}(\text{replicate}(n, [])) = []$.
List.join_replicate_singleton abbrev
Full source
@[deprecated flatten_replicate_singleton (since := "2024-10-14")] abbrev join_replicate_singleton := @flatten_replicate_singleton
Join of Replicated Singleton Lists Equals Replication of Elements
Informal description
For any natural number $n$ and any element $a$ of type $\alpha$, the join (flatten) of a list consisting of $n$ singleton lists $[a]$ is equal to the list of $n$ copies of $a$. That is, $$\text{join}(\text{replicate}(n, [a])) = \text{replicate}(n, a).$$
List.join_replicate_replicate abbrev
Full source
@[deprecated flatten_replicate_replicate (since := "2024-10-14")] abbrev join_replicate_replicate := @flatten_replicate_replicate
Flattening of Replicated Lists: $\text{join}(\text{replicate}(n, \text{replicate}(m, a))) = \text{replicate}(n \cdot m, a)$
Informal description
For any natural numbers $n$ and $m$ and any element $a$ of type $\alpha$, the flattening (join) of a list consisting of $n$ copies of the list containing $m$ copies of $a$ is equal to the list containing $n \times m$ copies of $a$. That is, $$\text{join}(\text{replicate}(n, \text{replicate}(m, a))) = \text{replicate}(n \cdot m, a).$$
List.reverse_join abbrev
Full source
@[deprecated reverse_flatten (since := "2024-10-14")] abbrev reverse_join := @reverse_flatten
Reverse of Concatenated List Equals Concatenated Reverse of Reversed Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, the reverse of the concatenated list $\text{join}(L)$ is equal to the concatenation of the reverses of the sublists in $L$ in reverse order, i.e., $$(\text{join}(L))^{\text{rev}} = \text{join}(\text{map}(\text{rev}, L^{\text{rev}})).$$
List.join_reverse abbrev
Full source
@[deprecated flatten_reverse (since := "2024-10-14")] abbrev join_reverse := @flatten_reverse
Concatenation of Reversed List Equals Reverse of Concatenated Reversed Sublists
Informal description
For any list of lists $L$ of elements of type $\alpha$, the concatenation of the reversed list $L^{\text{rev}}$ is equal to the reverse of the concatenation of the list obtained by reversing each sublist in $L$, i.e., $$\text{join}(L^{\text{rev}}) = (\text{join}(\text{map}(\text{rev}, L)))^{\text{rev}}.$$
List.getLast?_join abbrev
Full source
@[deprecated getLast?_flatten (since := "2024-10-14")] abbrev getLast?_join := @getLast?_flatten
Last Element of Concatenated List as Last Element of Last Sublist
Informal description
For any list of lists $L$ of elements of type $\alpha$, the last element of the concatenated list $\text{join}(L)$ (as an optional value) is equal to the last element of the last non-empty sublist in $L$, if such a sublist exists. Otherwise, it is `none`. In other words, $\text{getLast?}(\text{join}(L)) = \text{getLast?}(L.\text{getLast?} \mathbin{\text{>>=}} \text{id})$, where $\text{>>=}$ is the monadic bind operation for `Option`.
List.flatten_eq_bind abbrev
Full source
@[deprecated flatten_eq_flatMap (since := "2024-10-16")] abbrev flatten_eq_bind := @flatten_eq_flatMap
Flatten Equals Bind with Identity Function
Informal description
For any list of lists $L$ of elements of type $\alpha$, the flattening of $L$ is equal to the bind operation of $L$ with the identity function. That is, $$\text{flatten}(L) = L \mathbin{\text{bind}} \text{id}.$$
List.bind_def abbrev
Full source
@[deprecated flatMap_def (since := "2024-10-16")] abbrev bind_def := @flatMap_def
Bind Equals FlatMap for Lists
Informal description
For any list $l$ of type $\alpha$ and any function $f : \alpha \to \text{List } \beta$, the bind operation on $l$ with $f$ is equal to the flatMap operation on $l$ with $f$. That is, \[ l \mathbin{\text{bind}} f = \text{flatMap } f \, l. \]
List.bind_id abbrev
Full source
@[deprecated flatMap_id (since := "2024-10-16")] abbrev bind_id := @flatMap_id
Identity Bind Law for Lists: $L \mathbin{\text{bind}} \text{id} = L$
Informal description
For any list $L$ of type $\text{List } \alpha$, the bind operation with the identity function $\text{id}$ is equal to $L$ itself. That is, \[ L \mathbin{\text{bind}} \text{id} = L. \]
List.mem_bind abbrev
Full source
@[deprecated mem_flatMap (since := "2024-10-16")] abbrev mem_bind := @mem_flatMap
Membership in Bound List: $b \in l \mathbin{\text{bind}} f \leftrightarrow \exists a \in l, b \in f(a)$
Informal description
For any function $f : \alpha \to \text{List}\ \beta$, element $b : \beta$, and list $l : \text{List}\ \alpha$, the element $b$ is in the list obtained by binding $l$ with $f$ if and only if there exists an element $a \in l$ such that $b \in f(a)$. In other words, \[ b \in l \mathbin{\text{bind}} f \leftrightarrow \exists a \in l, b \in f(a). \]
List.exists_of_mem_bind abbrev
Full source
@[deprecated exists_of_mem_flatMap (since := "2024-10-16")] abbrev exists_of_mem_bind := @exists_of_mem_flatMap
Existence of Preimage in List Bind Operation: $b \in l \mathbin{\text{bind}} f \to \exists a \in l, b \in f(a)$
Informal description
For any element $b$ of type $\beta$, list $l$ of type $\text{List}\ \alpha$, and function $f : \alpha \to \text{List}\ \beta$, if $b$ is in the list obtained by binding $l$ with $f$ (i.e., $b \in l \mathbin{\text{bind}} f$), then there exists an element $a \in l$ such that $b \in f(a)$.
List.mem_bind_of_mem abbrev
Full source
@[deprecated mem_flatMap_of_mem (since := "2024-10-16")] abbrev mem_bind_of_mem := @mem_flatMap_of_mem
Membership in Bound List via Membership in Mapped List
Informal description
For any function $f : \alpha \to \text{List}\ \beta$, element $b : \beta$, list $l : \text{List}\ \alpha$, and element $a \in l$, if $b \in f(a)$, then $b \in l \mathbin{\text{bind}} f$.
List.bind_eq_nil_iff abbrev
Full source
@[deprecated flatMap_eq_nil_iff (since := "2024-10-16")] abbrev bind_eq_nil_iff := @flatMap_eq_nil_iff
Empty List from Bind Operation if and Only if All Mapped Lists are Empty
Informal description
For a list $l$ of elements of type $\alpha$ and a function $f : \alpha \to \text{List } \beta$, the bind operation (flatMap) on $l$ with $f$ results in the empty list if and only if for every element $x$ in $l$, the list $f(x)$ is empty. That is, \[ l \mathbin{>>=} f = [] \leftrightarrow \forall x \in l, f(x) = []. \]
List.forall_mem_bind abbrev
Full source
@[deprecated forall_mem_flatMap (since := "2024-10-16")] abbrev forall_mem_bind := @forall_mem_flatMap
Universal Quantifier over Bind Elements
Informal description
For a predicate $p : \beta \to \text{Prop}$, a list $l$ of elements of type $\alpha$, and a function $f : \alpha \to \text{List } \beta$, the following equivalence holds: \[ (\forall x \in l \mathbin{>>=} f, p(x)) \leftrightarrow (\forall a \in l, \forall b \in f(a), p(b)). \]
List.bind_singleton abbrev
Full source
@[deprecated flatMap_singleton (since := "2024-10-16")] abbrev bind_singleton := @flatMap_singleton
Bind of Singleton List Equals Function Application
Informal description
For any function $f : \alpha \to \text{List } \beta$ and any element $x \in \alpha$, the bind operation (flatMap) applied to the singleton list $[x]$ and $f$ equals $f(x)$. In other words, $[x] \mathbin{>>=} f = f(x)$.
List.bind_singleton' abbrev
Full source
@[deprecated flatMap_singleton' (since := "2024-10-16")] abbrev bind_singleton' := @flatMap_singleton'
FlatMap with Singleton Function Equals Map
Informal description
For any function $f : \alpha \to \text{List } \beta$ and any list $l$ of elements of type $\alpha$, the bind operation (flatMap) applied to $l$ with the function mapping each element $x$ to the singleton list $[f(x)]$ is equal to the list obtained by mapping $f$ over $l$. In other words, $\text{flatMap} (\lambda x \mapsto [f(x)]) l = \text{map } f l$.
List.head_bind abbrev
Full source
@[deprecated head?_flatMap (since := "2024-10-16")] abbrev head_bind := @head?_flatMap
Head of List Bind Operation Equals Head of First Non-Empty Mapped List
Informal description
For any list `l` of elements of type `α` and any function `f : α → List β`, the head of the bind operation (flatMap) applied to `l` and `f` (as an optional value) is equal to the head of the first non-empty list obtained by applying `f` to elements of `l`. In other words, $\text{head?}(l \mathbin{>>=} f) = \text{head?}(\text{join } (\text{map } f l)) = \text{head?}(\text{flatMap } f l)$.
List.bind_append abbrev
Full source
@[deprecated flatMap_append (since := "2024-10-16")] abbrev bind_append := @flatMap_append
Distributivity of List Bind over Concatenation
Informal description
For any lists $xs$ and $ys$ of elements of type $\alpha$, and any function $f : \alpha \to \text{List} \beta$, the bind operation (denoted by `>>=`) satisfies: \[ (xs ++ ys) >>= f = (xs >>= f) ++ (ys >>= f) \]
List.bind_assoc abbrev
Full source
@[deprecated flatMap_assoc (since := "2024-10-16")] abbrev bind_assoc := @flatMap_assoc
Associativity of Monadic Bind for Lists
Informal description
For any list $l$ of elements of type $\alpha$, and any functions $f : \alpha \to \text{List } \beta$ and $g : \beta \to \text{List } \gamma$, the following associativity property holds for the monadic bind operation: \[ (l \text{ >>= } f) \text{ >>= } g = l \text{ >>= } \big(x \mapsto f(x) \text{ >>= } g\big) \]
List.map_bind abbrev
Full source
@[deprecated map_flatMap (since := "2024-10-16")] abbrev map_bind := @map_flatMap
Interchange of `map` and monadic bind: $\text{map } f \circ \text{bind } g = \text{bind } (\text{map } f \circ g)$
Informal description
For any function $f : \alpha \to \beta$, any function $g : \beta \to \text{List } \gamma$, and any list $l : \text{List } \alpha$, the following equality holds: $$ \text{map } f (\text{bind } g\ l) = \text{bind } (fun\ b \mapsto \text{map } f (g\ b))\ l $$ where $\text{bind}$ is the monadic bind operation (equivalent to $\text{flatMap}$).
List.bind_map abbrev
Full source
@[deprecated flatMap_map (since := "2024-10-16")] abbrev bind_map := @flatMap_map
Monadic Bind-Map Composition Equality for Lists
Informal description
For any function $f : \alpha \to \beta$, any function $g : \beta \to \text{List } \gamma$, and any list $l : \text{List } \alpha$, the following equality holds: $$l.\text{bind } (g \circ f) = (l.\text{map } f).\text{bind } g$$ where $\text{bind}$ is the monadic bind operation (equivalent to $\text{flatMap}$) and $\circ$ denotes function composition.
List.map_eq_bind abbrev
Full source
@[deprecated map_eq_flatMap (since := "2024-10-16")] abbrev map_eq_bind := @map_eq_flatMap
Map as Monadic Bind of Singleton Lists: $\text{map } f = \text{bind } (\lambda x \mapsto [f x])$
Informal description
For any function $f : \alpha \to \beta$ and any list $l$ of elements of type $\alpha$, the map of $f$ over $l$ is equal to the monadic bind of the function $\lambda x \mapsto [f x]$ over $l$. In other words: $$\text{map } f\ l = \text{bind } (\lambda x \mapsto [f x])\ l$$ where $\text{bind}$ is the monadic bind operation (equivalent to $\text{flatMap}$).
List.filterMap_bind abbrev
Full source
@[deprecated filterMap_flatMap (since := "2024-10-16")] abbrev filterMap_bind := @filterMap_flatMap
Commutativity of `filterMap` and Monadic Bind for Lists
Informal description
For any list $l$ of type $\text{List } \alpha$, any function $f : \alpha \to \text{Option } \beta$, and any function $g : \beta \to \text{List } \gamma$, the following equality holds: $$\text{filterMap } f \left(\text{bind } g \, l\right) = \text{bind } \left(\lambda b, \text{filterMap } f (g \, b)\right) l$$ where $\text{bind}$ is the monadic bind operation (equivalent to $\text{flatMap}$) and $\text{filterMap } f$ applies $f$ to each element and collects the $\text{some}$ results.
List.filter_bind abbrev
Full source
@[deprecated filter_flatMap (since := "2024-10-16")] abbrev filter_bind := @filter_flatMap
Filter Commutes with Monadic Bind for Lists: $\text{filter } f \circ \text{bind } g = \text{bind } (g \circ \text{filter } f)$
Informal description
For any list $l$ of type $\text{List } \alpha$, any function $f : \alpha \to \text{Bool}$, and any function $g : \alpha \to \text{List } \beta$, the following equality holds: \[ \text{filter } f (\text{bind } g \, l) = \text{bind } (\lambda a, \text{filter } f (g \, a)) \, l \] where $\text{bind}$ is the monadic bind operation (equivalent to $\text{flatMap}$) and $\text{filter } f$ selects elements from a list that satisfy $f$.
List.bind_eq_foldl abbrev
Full source
@[deprecated flatMap_eq_foldl (since := "2024-10-16")] abbrev bind_eq_foldl := @flatMap_eq_foldl
Monadic Bind as Left Fold: $l \mathbin{>>=} f = \text{foldl} \ (\lambda \text{acc} \ a, \text{acc} \mathbin{+\!\!+} f \ a) \ [] \ l$
Informal description
For any list $l : \text{List } \alpha$ and any function $f : \alpha \to \text{List } \beta$, the monadic bind operation (equivalent to flatMap) can be expressed as a left fold: \[ l \mathbin{>>=} f = \text{foldl} \ (\lambda \text{acc} \ a, \text{acc} \mathbin{+\!\!+} f \ a) \ [] \ l \] where $\mathbin{>>=}$ denotes the bind operation and $\mathbin{+\!\!+}$ denotes list concatenation.
List.bind_replicate abbrev
Full source
@[deprecated flatMap_replicate (since := "2024-10-16")] abbrev bind_replicate := @flatMap_replicate
Bind Operation on Replicated List Equals Replication of Mapped Elements
Informal description
For any type $\alpha$, any natural number $n$, and any element $a \in \alpha$, the monadic bind operation (equivalent to flatMap) applied to a replicated list satisfies: \[ \text{replicate}\ n\ a \mathbin{>>=} f = \text{replicate}\ n\ (f\ a) \] where: - $\text{replicate}\ n\ a$ creates a list containing $n$ copies of $a$ - $\mathbin{>>=}$ denotes the bind operation (flatMap) - $f : \alpha \to \text{List}\ \beta$ is a function mapping elements of $\alpha$ to lists of $\beta$
List.reverse_bind abbrev
Full source
@[deprecated reverse_flatMap (since := "2024-10-16")] abbrev reverse_bind := @reverse_flatMap
Reverse of Bind Equals Bind of Reverse with Composed Reverse Function
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List} \beta$, the reverse of the bind operation (which is equivalent to flatMap) satisfies: \[ \text{reverse}(l \mathbin{>>=} f) = \text{reverse}(l) \mathbin{>>=} (\text{reverse} \circ f) \] where $\mathbin{>>=}$ denotes the bind operation (flatMap) and $\circ$ denotes function composition.
List.bind_reverse abbrev
Full source
@[deprecated flatMap_reverse (since := "2024-10-16")] abbrev bind_reverse := @flatMap_reverse
Reverse of Bind Equals Bind of Reverse with Composed Reverse Function
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List} \beta$, the bind operation (flatMap) applied to the reverse of $l$ satisfies: \[ l^{\text{reverse}} \mathbin{>>=} f = (l \mathbin{>>=} (\text{reverse} \circ f))^{\text{reverse}} \] where $\mathbin{>>=}$ denotes the bind operation (flatMap) and $\circ$ denotes function composition.
List.getLast?_bind abbrev
Full source
@[deprecated getLast?_flatMap (since := "2024-10-16")] abbrev getLast?_bind := @getLast?_flatMap
Last Element of Bind Operation as Find-Some on Reversed List
Informal description
For any list $l$ of elements of type $\alpha$ and any function $f : \alpha \to \text{List } \beta$, the last element of the bind operation (flatMap) applied to $l$ and $f$ (as an optional value) is equal to the first non-`none` result obtained by applying $\text{getLast?}$ to each $f(a)$ for $a$ in the reverse of $l$. In other words, $\text{getLast?}(l \mathbin{>>=} f) = \text{findSome? } (\lambda a \mapsto \text{getLast?}(f a)) (\text{reverse } l)$.
List.any_bind abbrev
Full source
@[deprecated any_flatMap (since := "2024-10-16")] abbrev any_bind := @any_flatMap
Disjunction of `any` over List Concatenation via Bind
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and any function $f : \alpha \to \text{List}\,\beta$, the boolean value $\text{any}\,p\,(l.\text{bind}\,f)$ is equal to $\text{any}\,(\lambda a \Rightarrow \text{any}\,p\,(f\,a))\,l$. In other words, checking if any element in the concatenated list obtained by applying $f$ to each element of $l$ satisfies the predicate $p$ is equivalent to checking if any element $a$ in $l$ has a corresponding list $f\,a$ that contains an element satisfying $p$.
List.all_bind abbrev
Full source
@[deprecated all_flatMap (since := "2024-10-16")] abbrev all_bind := @all_flatMap
Universal Quantification over Bound Lists: $\text{all } p \circ \text{bind } f = \text{all } (\text{all } p \circ f)$
Informal description
For any list `l : List α`, any function `f : α → List β`, and any predicate `p : β → Bool`, the following holds: \[ \text{all } p \ (\text{bind } f \ l) = \text{all } (λ a ⇒ \text{all } p \ (f \ a)) \ l \] where: - `bind f l` is equivalent to `flatMap f l` (the monadic bind operation for lists) - `all p l` checks if all elements in `l` satisfy the predicate `p`
List.get?_len_le abbrev
Full source
@[deprecated get?_eq_none (since := "2024-11-29")] abbrev get?_len_le := @getElem?_eq_none
Optional List Indexing Yields None for Out-of-Bounds Indices
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and any natural number index $i$, if the length of $l$ is less than or equal to $i$, then the optional indexing operation $l[i]?$ returns `none`.
List.getElem?_eq_some abbrev
Full source
@[deprecated getElem?_eq_some_iff (since := "2024-11-29")]
abbrev getElem?_eq_some := @getElem?_eq_some_iff
Characterization of Optional List Indexing: $l[i]? = \text{some}\,a \leftrightarrow i < \text{length}\,l \land l[i] = a$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and any natural number index $i$, the optional indexing operation $l[i]?$ returns $\text{some}\,a$ if and only if $i$ is a valid index for $l$ (i.e., $i < \text{length}\,l$) and the element at index $i$ in $l$ is equal to $a$. In symbols: $$l[i]? = \text{some}\,a \leftrightarrow i < \text{length}\,l \land l[i] = a$$
List.get?_eq_some abbrev
Full source
@[deprecated get?_eq_some_iff (since := "2024-11-29")]
abbrev get?_eq_some := @getElem?_eq_some_iff
Characterization of Optional List Indexing: $l[i]? = \text{some}\,a \leftrightarrow i < \text{length}\,l \land l[i] = a$
Informal description
For any list $l$ of type $\text{List}\,\alpha$ and natural number index $i$, the optional indexing operation $l[i]?$ returns $\text{some}\,a$ if and only if $i$ is a valid index for $l$ (i.e., $i < \text{length}\,l$) and the element at index $i$ in $l$ is equal to $a$. In symbols: $$l[i]? = \text{some}\,a \leftrightarrow i < \text{length}\,l \land l[i] = a$$
List.getElem?_eq theorem
(l : List α) (i : Nat) : l[i]? = if h : i < l.length then some l[i] else none
Full source
@[deprecated LawfulGetElem.getElem?_def (since := "2024-11-29")]
theorem getElem?_eq (l : List α) (i : Nat) :
    l[i]? = if h : i < l.length then some l[i] else none :=
  getElem?_def _ _
Characterization of Optional List Indexing via Conditional Expression
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$, the optional indexing operation $l[i]?$ equals $\text{some}\,l[i]$ if $i$ is a valid index for $l$ (i.e., $i < \text{length}\,l$), and equals $\text{none}$ otherwise. In symbols: $$l[i]? = \begin{cases} \text{some}\,l[i] & \text{if } i < \text{length}\,l \\ \text{none} & \text{otherwise} \end{cases}$$
List.getElem?_len_le abbrev
Full source
@[deprecated getElem?_eq_none (since := "2024-11-29")] abbrev getElem?_len_le := @getElem?_eq_none
Optional List Indexing Yields None for Out-of-Bounds Indices
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$, if the length of $l$ is less than or equal to $i$, then the optional indexing operation $l[i]?$ returns `none`.
List.isSome_getElem? theorem
{l : List α} {i : Nat} : l[i]?.isSome ↔ i < l.length
Full source
@[deprecated _root_.isSome_getElem? (since := "2024-12-09")]
theorem isSome_getElem? {l : List α} {i : Nat} : l[i]?l[i]?.isSome ↔ i < l.length := by
  simp
Optional List Indexing Yields Some if and only if Index is Valid
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$, the optional element access $l[i]?$ returns `some` value if and only if $i$ is less than the length of $l$.
List.isNone_getElem? theorem
{l : List α} {i : Nat} : l[i]?.isNone ↔ l.length ≤ i
Full source
@[deprecated _root_.isNone_getElem? (since := "2024-12-09")]
theorem isNone_getElem? {l : List α} {i : Nat} : l[i]?l[i]?.isNone ↔ l.length ≤ i := by
  simp
Characterization of `none` in Optional List Indexing: $l[i]? = \text{none} \leftrightarrow \text{length}(l) \leq i$
Informal description
For any list $l$ of type $\alpha$ and natural number index $i$, the optional indexing operation $l[i]?$ returns `none` if and only if the length of $l$ is less than or equal to $i$.