doc-next-gen

Init.Data.List.TakeDrop

Module docstring

{"# Lemmas about List.take and List.drop. ","### take and drop

Further results on List.take and List.drop, which rely on stronger automation in Nat, are given in Init.Data.List.TakeDrop. ","### takeWhile and dropWhile ","### splitAt ","### rotateLeft ","### rotateRight "}

List.take_cons theorem
{l : List α} (h : 0 < i) : (a :: l).take i = a :: l.take (i - 1)
Full source
theorem take_cons {l : List α} (h : 0 < i) : (a :: l).take i = a :: l.take (i - 1) := by
  cases i with
  | zero => exact absurd h (Nat.lt_irrefl _)
  | succ i => rfl
Take of Cons List: $\text{take}(i, a :: l) = a :: \text{take}(i-1, l)$ for $i > 0$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i > 0$, taking the first $i$ elements of the list $a :: l$ (formed by prepending $a$ to $l$) is equal to $a$ prepended to the first $i-1$ elements of $l$. That is, $\text{take}(i, a :: l) = a :: \text{take}(i-1, l)$.
List.drop_one theorem
: ∀ {l : List α}, l.drop 1 = l.tail
Full source
@[simp]
theorem drop_one : ∀ {l : List α}, l.drop 1 = l.tail
  | [] | _ :: _ => rfl
Drop One Equals Tail
Informal description
For any list $l$ of elements of type $\alpha$, dropping the first element of $l$ is equivalent to taking the tail of $l$, i.e., $\text{drop}\ 1\ l = \text{tail}\ l$.
List.take_append_drop theorem
: ∀ (i : Nat) (l : List α), l.take i ++ l.drop i = l
Full source
@[simp] theorem take_append_drop : ∀ (i : Nat) (l : List α), l.take i ++ l.drop i = l
  | 0, _ => rfl
  | _ + 1, [] => rfl
  | _ + 1, x :: _ => congrArg (cons x) (take_append_drop ..)
Reconstruction of List via Take and Drop: $\text{take}(i, l) \mathbin{+\kern-0.5em+} \text{drop}(i, l) = l$
Informal description
For any natural number $i$ and any list $l$ of elements of type $\alpha$, the concatenation of the first $i$ elements of $l$ (obtained via `take`) and the remaining elements after dropping the first $i$ elements (obtained via `drop`) reconstructs the original list $l$. That is, $\text{take}(i, l) \mathbin{+\kern-0.5em+} \text{drop}(i, l) = l$.
List.length_drop theorem
: ∀ {i : Nat} {l : List α}, (drop i l).length = l.length - i
Full source
@[simp] theorem length_drop : ∀ {i : Nat} {l : List α}, (drop i l).length = l.length - i
  | 0, _ => rfl
  | succ i, [] => Eq.symm (Nat.zero_sub (succ i))
  | succ i, x :: l => calc
    length (drop (i + 1) (x :: l)) = length l - i := length_drop (i := i) (l := l)
    _ = succ (length l) - succ i := (Nat.succ_sub_succ_eq_sub (length l) i).symm
Length of Dropped List: $|\text{drop}(i, l)| = |l| - i$
Informal description
For any natural number $i$ and any list $l$ of elements of type $\alpha$, the length of the list obtained by dropping the first $i$ elements of $l$ is equal to the length of $l$ minus $i$, i.e., $|\text{drop}(i, l)| = |l| - i$.
List.drop_of_length_le theorem
{l : List α} (h : l.length ≤ i) : l.drop i = []
Full source
theorem drop_of_length_le {l : List α} (h : l.length ≤ i) : l.drop i = [] :=
  length_eq_zero_iff.1 (length_drop .. ▸ Nat.sub_eq_zero_of_le h)
Empty Drop for Lists with Sufficiently Large Index
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, if the length of $l$ is less than or equal to $i$, then dropping the first $i$ elements of $l$ results in the empty list, i.e., $\text{drop}(i, l) = []$.
List.length_lt_of_drop_ne_nil theorem
{l : List α} {i} (h : drop i l ≠ []) : i < l.length
Full source
theorem length_lt_of_drop_ne_nil {l : List α} {i} (h : dropdrop i l ≠ []) : i < l.length :=
  gt_of_not_le (mt drop_of_length_le h)
Non-empty Drop Implies Index Less Than List Length
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, if the result of dropping the first $i$ elements of $l$ is not the empty list, then $i$ is strictly less than the length of $l$, i.e., if $\text{drop}(i, l) \neq []$ then $i < |l|$.
List.take_of_length_le theorem
{l : List α} (h : l.length ≤ i) : take i l = l
Full source
theorem take_of_length_le {l : List α} (h : l.length ≤ i) : take i l = l := by
  have := take_append_drop i l
  rw [drop_of_length_le h, append_nil] at this; exact this
Full List Preservation under Take Operation: $\text{take}(i, l) = l$ when $|l| \leq i$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, if the length of $l$ is less than or equal to $i$, then taking the first $i$ elements of $l$ results in the original list $l$ itself, i.e., $\text{take}(i, l) = l$.
List.lt_length_of_take_ne_self theorem
{l : List α} {i} (h : l.take i ≠ l) : i < l.length
Full source
theorem lt_length_of_take_ne_self {l : List α} {i} (h : l.take i ≠ l) : i < l.length :=
  gt_of_not_le (mt take_of_length_le h)
Index Bound from Take Operation Inequality: $i < |l|$ when $\text{take}(i, l) \neq l$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, if taking the first $i$ elements of $l$ does not yield the entire list $l$ (i.e., $\text{take}(i, l) \neq l$), then $i$ is strictly less than the length of $l$, i.e., $i < |l|$.
List.drop_length theorem
{l : List α} : l.drop l.length = []
Full source
@[simp] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
$\text{drop}(|l|, l) = []$ (Empty drop at full length)
Informal description
For any list $l$ of elements of type $\alpha$, dropping the first $n$ elements where $n$ is the length of $l$ results in the empty list, i.e., $\text{drop}(|l|, l) = []$.
List.take_length theorem
{l : List α} : l.take l.length = l
Full source
@[simp] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
Full List Preservation under Take Operation: $\text{take}(|l|, l) = l$
Informal description
For any list $l$ of elements of type $\alpha$, taking the first $n$ elements where $n$ is the length of $l$ results in the original list $l$, i.e., $\text{take}(|l|, l) = l$.
List.getElem_cons_drop theorem
: ∀ {l : List α} {i : Nat} (h : i < l.length), l[i] :: drop (i + 1) l = drop i l
Full source
@[simp]
theorem getElem_cons_drop : ∀ {l : List α} {i : Nat} (h : i < l.length),
    l[i]l[i] :: drop (i + 1) l = drop i l
  | _::_, 0, _ => rfl
  | _::_, _+1, h => getElem_cons_drop (Nat.add_one_lt_add_one_iff.mp h)
List Decomposition via Index and Drop: $\text{drop}\ i\ l = l[i] :: \text{drop}\ (i+1)\ l$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number index $i$ such that $i$ is less than the length of $l$, the list obtained by dropping the first $i$ elements of $l$ is equal to the list constructed by prepending the $i$-th element of $l$ to the list obtained by dropping the first $i+1$ elements of $l$. In other words, $\text{drop}\ i\ l = l[i] :: \text{drop}\ (i+1)\ l$.
List.drop_eq_getElem_cons theorem
{i} {l : List α} (h : i < l.length) : drop i l = l[i] :: drop (i + 1) l
Full source
theorem drop_eq_getElem_cons {i} {l : List α} (h : i < l.length) : drop i l = l[i]l[i] :: drop (i + 1) l :=
  (getElem_cons_drop h).symm
List Decomposition via Index and Drop: $\text{drop}\ i\ l = l[i] :: \text{drop}\ (i+1)\ l$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number index $i$ such that $i$ is less than the length of $l$, the list obtained by dropping the first $i$ elements of $l$ is equal to the list constructed by prepending the $i$-th element of $l$ to the list obtained by dropping the first $i+1$ elements of $l$. In other words, $\text{drop}\ i\ l = l[i] :: \text{drop}\ (i+1)\ l$.
List.getElem?_take_of_lt theorem
{l : List α} {i j : Nat} (h : i < j) : (l.take j)[i]? = l[i]?
Full source
@[simp]
theorem getElem?_take_of_lt {l : List α} {i j : Nat} (h : i < j) : (l.take j)[i]? = l[i]? := by
  induction j generalizing l i with
  | zero =>
    exact absurd h (Nat.not_lt_of_le i.zero_le)
  | succ _ hj =>
    cases l with
    | nil => simp only [take_nil]
    | cons hd tl =>
      cases i
      · simp
      · simpa using hj (Nat.lt_of_succ_lt_succ h)
Optional Indexing Preserved Under Taking Sublist: $(l.take\ j)[i]? = l[i]?$ for $i < j$
Informal description
For any list $l$ of elements of type $\alpha$ and natural numbers $i$ and $j$ such that $i < j$, the optional indexing operation on the first $j$ elements of $l$ at position $i$ is equal to the optional indexing operation on $l$ at position $i$, i.e., $(l.take\ j)[i]? = l[i]?$.
List.getElem?_take_of_succ theorem
{l : List α} {i : Nat} : (l.take (i + 1))[i]? = l[i]?
Full source
theorem getElem?_take_of_succ {l : List α} {i : Nat} : (l.take (i + 1))[i]? = l[i]? := by simp
Optional Indexing Preserved Under Taking Sublist: $(l.\text{take}\ (i+1))[i]? = l[i]?$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the optional indexing operation on the first $i+1$ elements of $l$ at position $i$ is equal to the optional indexing operation on $l$ at position $i$, i.e., $(l.\text{take}\ (i+1))[i]? = l[i]?$.
List.drop_drop theorem
{i : Nat} : ∀ {j} {l : List α}, drop i (drop j l) = drop (j + i) l
Full source
@[simp] theorem drop_drop {i : Nat} : ∀ {j} {l : List α}, drop i (drop j l) = drop (j + i) l
  | j, [] => by simp
  | 0, l => by simp
  | j + 1, a :: l =>
    calc
      drop i (drop (j + 1) (a :: l)) = drop i (drop j l) := rfl
      _ = drop (j + i) l := drop_drop
      _ = drop ((j + 1) + i) (a :: l) := by rw [Nat.add_right_comm]; rfl
Composition of Drop Operations: $\text{drop}\ i \circ \text{drop}\ j = \text{drop}\ (j + i)$
Informal description
For any natural numbers $i$ and $j$, and any list $l$ of elements of type $\alpha$, dropping the first $i$ elements after dropping the first $j$ elements of $l$ is equivalent to dropping the first $j + i$ elements of $l$. In other words: $$\text{drop}\ i\ (\text{drop}\ j\ l) = \text{drop}\ (j + i)\ l$$
List.drop_add_one_eq_tail_drop theorem
{l : List α} : l.drop (i + 1) = (l.drop i).tail
Full source
theorem drop_add_one_eq_tail_drop {l : List α} : l.drop (i + 1) = (l.drop i).tail := by
  rw [← drop_drop, drop_one]
Drop-Tail Relation: $\text{drop}\ (i+1)\ l = \text{tail}\ (\text{drop}\ i\ l)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, dropping the first $i+1$ elements of $l$ is equivalent to taking the tail of the list obtained by dropping the first $i$ elements of $l$. In other words: $$\text{drop}\ (i+1)\ l = \text{tail}\ (\text{drop}\ i\ l)$$
List.take_drop theorem
: ∀ {i j : Nat} {l : List α}, take i (drop j l) = drop j (take (j + i) l)
Full source
theorem take_drop : ∀ {i j : Nat} {l : List α}, take i (drop j l) = drop j (take (j + i) l)
  | _, 0, _ => by simp
  | _, _, [] => by simp
  | _, _+1, _ :: _ => by simpa [Nat.succ_add, take_succ_cons, drop_succ_cons] using take_drop ..
Take-Drop Commutation: $\text{take}\ i \circ \text{drop}\ j = \text{drop}\ j \circ \text{take}\ (j + i)$
Informal description
For any natural numbers $i$ and $j$, and any list $l$ of elements of type $\alpha$, taking the first $i$ elements after dropping the first $j$ elements of $l$ is equivalent to dropping the first $j$ elements after taking the first $j + i$ elements of $l$. In other words: $$\text{take}\ i\ (\text{drop}\ j\ l) = \text{drop}\ j\ (\text{take}\ (j + i)\ l)$$
List.tail_drop theorem
{l : List α} {i : Nat} : (l.drop i).tail = l.drop (i + 1)
Full source
@[simp]
theorem tail_drop {l : List α} {i : Nat} : (l.drop i).tail = l.drop (i + 1) := by
  induction l generalizing i with
  | nil => simp
  | cons hd tl hl =>
    cases i
    · simp
    · simp [hl]
Tail of Dropped List Equals Drop with Incremented Index: $\text{tail}(\text{drop}\ i\ l) = \text{drop}\ (i+1)\ l$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the tail of the list obtained by dropping the first $i$ elements of $l$ is equal to the list obtained by dropping the first $i+1$ elements of $l$. In other words, $\text{tail}(\text{drop}\ i\ l) = \text{drop}\ (i+1)\ l$.
List.drop_tail theorem
{l : List α} {i : Nat} : l.tail.drop i = l.drop (i + 1)
Full source
@[simp]
theorem drop_tail {l : List α} {i : Nat} : l.tail.drop i = l.drop (i + 1) := by
  rw [Nat.add_comm, ← drop_drop, drop_one]
Tail-Drop Relation: $\text{drop}\ i \circ \text{tail} = \text{drop}\ (i+1)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, dropping the first $i$ elements from the tail of $l$ is equivalent to dropping the first $i+1$ elements from $l$ itself. In other words: $$\text{drop}\ i\ (\text{tail}\ l) = \text{drop}\ (i + 1)\ l$$
List.drop_eq_nil_iff theorem
{l : List α} {i : Nat} : l.drop i = [] ↔ l.length ≤ i
Full source
@[simp]
theorem drop_eq_nil_iff {l : List α} {i : Nat} : l.drop i = [] ↔ l.length ≤ i := by
  refine ⟨fun h => ?_, drop_eq_nil_of_le⟩
  induction i generalizing l with
  | zero =>
    simp only [drop] at h
    simp [h]
  | succ i hi =>
    cases l
    · simp
    · simp only [drop] at h
      simpa [Nat.succ_le_succ_iff] using hi h
Drop Yields Empty List iff Index Exceeds Length: $\text{drop}(i, l) = [] \leftrightarrow |l| \leq i$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the list obtained by dropping the first $i$ elements of $l$ is empty if and only if the length of $l$ is less than or equal to $i$. In other words, $\text{drop}(i, l) = [] \leftrightarrow \text{length}(l) \leq i$.
List.drop_eq_nil_iff_le abbrev
Full source
@[deprecated drop_eq_nil_iff (since := "2024-09-10")] abbrev drop_eq_nil_iff_le := @drop_eq_nil_iff
Empty Drop Condition: $\text{drop}(i, l) = [] \leftrightarrow |l| \leq i$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $i$, the list obtained by dropping the first $i$ elements of $l$ is empty if and only if the length of $l$ is less than or equal to $i$. In other words, $\text{drop}(i, l) = [] \leftrightarrow \text{length}(l) \leq i$.
List.take_eq_nil_iff theorem
{l : List α} {k : Nat} : l.take k = [] ↔ k = 0 ∨ l = []
Full source
@[simp]
theorem take_eq_nil_iff {l : List α} {k : Nat} : l.take k = [] ↔ k = 0 ∨ l = [] := by
  cases l <;> cases k <;> simp [Nat.succ_ne_zero]
Empty Take Condition: $\text{take}(k, l) = [] \leftrightarrow k = 0 \lor l = []$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number $k$, the first $k$ elements of $l$ form the empty list if and only if either $k = 0$ or $l$ is the empty list. In other words, $\text{take}(k, l) = [] \leftrightarrow k = 0 \lor l = []$.
List.drop_eq_nil_of_eq_nil theorem
: ∀ {as : List α} {i}, as = [] → as.drop i = []
Full source
theorem drop_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.drop i = []
  | _, _, rfl => drop_nil
Drop of Empty List is Empty
Informal description
For any list $as$ of type $\alpha$ and any natural number $i$, if $as$ is the empty list, then dropping the first $i$ elements from $as$ results in the empty list, i.e., $\text{drop}\ i\ [] = []$.
List.ne_nil_of_drop_ne_nil theorem
{as : List α} {i : Nat} (h : as.drop i ≠ []) : as ≠ []
Full source
theorem ne_nil_of_drop_ne_nil {as : List α} {i : Nat} (h: as.drop i ≠ []) : as ≠ [] :=
  mt drop_eq_nil_of_eq_nil h
Non-Empty Drop Implies Non-Empty List
Informal description
For any list $as$ of type $\alpha$ and any natural number $i$, if the result of dropping the first $i$ elements from $as$ is not the empty list, then $as$ itself is not the empty list. In other words, if $\text{drop}(i, as) \neq []$, then $as \neq []$.
List.take_eq_nil_of_eq_nil theorem
: ∀ {as : List α} {i}, as = [] → as.take i = []
Full source
theorem take_eq_nil_of_eq_nil : ∀ {as : List α} {i}, as = [] → as.take i = []
  | _, _, rfl => take_nil
Taking from Empty List Yields Empty List
Informal description
For any list $as$ of type $\alpha$ and any natural number $i$, if $as$ is the empty list, then taking the first $i$ elements of $as$ results in the empty list, i.e., $\text{take}(i, as) = []$.
List.ne_nil_of_take_ne_nil theorem
{as : List α} {i : Nat} (h : as.take i ≠ []) : as ≠ []
Full source
theorem ne_nil_of_take_ne_nil {as : List α} {i : Nat} (h : as.take i ≠ []) : as ≠ [] :=
  mt take_eq_nil_of_eq_nil h
Non-empty Prefix Implies Non-empty List
Informal description
For any list $as$ of type $\alpha$ and any natural number $i$, if the first $i$ elements of $as$ is not the empty list, then $as$ itself is not the empty list.
List.take_set theorem
{l : List α} {i j : Nat} {a : α} : (l.set j a).take i = (l.take i).set j a
Full source
theorem take_set {l : List α} {i j : Nat} {a : α} :
    (l.set j a).take i = (l.take i).set j a := by
  induction i generalizing l j with
  | zero => simp
  | succ _ hi =>
    cases l with
    | nil => simp
    | cons hd tl => cases j <;> simp_all
Commutation of List Prefix and Element Modification: $(l.\text{set}(j, a)).\text{take}(i) = (l.\text{take}(i)).\text{set}(j, a)$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$, and element $a \in \alpha$, taking the first $i$ elements of the list obtained by setting the $j$-th element of $l$ to $a$ is equal to setting the $j$-th element of the first $i$ elements of $l$ to $a$. In other words, the operations of taking a prefix and modifying an element commute when the modification index is within bounds.
List.set_take abbrev
Full source
@[deprecated take_set (since := "2025-02-17")]
abbrev set_take := @take_set
Commutation of List Prefix and Element Modification: $(l.\text{take}(i)).\text{set}(j, a) = (l.\text{set}(i + j, a)).\text{take}(i)$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$, and element $a \in \alpha$, setting the $j$-th element of the first $i$ elements of $l$ to $a$ is equal to taking the first $i$ elements of the list obtained by setting the $(i + j)$-th element of $l$ to $a$. In other words, $(l.\text{take}(i)).\text{set}(j, a) = (l.\text{set}(i + j, a)).\text{take}(i)$.
List.drop_set theorem
{l : List α} {i j : Nat} {a : α} : (l.set j a).drop i = if j < i then l.drop i else (l.drop i).set (j - i) a
Full source
theorem drop_set {l : List α} {i j : Nat} {a : α} :
    (l.set j a).drop i = if j < i then l.drop i else (l.drop i).set (j - i) a := by
  induction i generalizing l j with
  | zero => simp
  | succ _ hi =>
    cases l with
    | nil => simp
    | cons hd tl =>
      cases j
      · simp_all
      · simp only [hi, set_cons_succ, drop_succ_cons, succ_lt_succ_iff]
        congr 2
        exact (Nat.add_sub_add_right ..).symm
Interaction of List Drop and Element Modification: $(l.\text{set}(j, a)).\text{drop}(i)$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$, and element $a \in \alpha$, dropping the first $i$ elements from the list obtained by setting the $j$-th element of $l$ to $a$ is equal to: - $l.\text{drop}(i)$ if $j < i$, or - $(l.\text{drop}(i)).\text{set}(j - i, a)$ otherwise. In other words, $$(l.\text{set}(j, a)).\text{drop}(i) = \begin{cases} l.\text{drop}(i) & \text{if } j < i \\ (l.\text{drop}(i)).\text{set}(j - i, a) & \text{otherwise} \end{cases}$$
List.set_drop theorem
{l : List α} {i j : Nat} {a : α} : (l.drop i).set j a = (l.set (i + j) a).drop i
Full source
theorem set_drop {l : List α} {i j : Nat} {a : α} :
    (l.drop i).set j a = (l.set (i + j) a).drop i := by
  rw [drop_set, if_neg, add_sub_self_left]
  exact (Nat.not_lt).2 (le_add_right ..)
Modification-Drop Commutation: $(l.\text{drop}(i)).\text{set}(j, a) = (l.\text{set}(i + j, a)).\text{drop}(i)$
Informal description
For any list $l$ of elements of type $\alpha$, natural numbers $i$ and $j$, and element $a \in \alpha$, modifying the $j$-th element of the list obtained by dropping the first $i$ elements of $l$ to $a$ is equal to dropping the first $i$ elements of the list obtained by modifying the $(i + j)$-th element of $l$ to $a$. In other words, $$(l.\text{drop}(i)).\text{set}(j, a) = (l.\text{set}(i + j, a)).\text{drop}(i).$$
List.take_concat_get theorem
{l : List α} {i : Nat} (h : i < l.length) : (l.take i).concat l[i] = l.take (i + 1)
Full source
theorem take_concat_get {l : List α} {i : Nat} (h : i < l.length) :
    (l.take i).concat l[i] = l.take (i+1) :=
  Eq.symm <| (append_left_inj _).1 <| (take_append_drop (i+1) l).trans <| by
    rw [concat_eq_append, append_assoc, singleton_append, getElem_cons_drop_succ_eq_drop, take_append_drop]
List Reconstruction via Take and Append: $\text{take}(i, l).\text{concat}(l[i]) = \text{take}(i+1, l)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number index $i$ such that $i < \text{length}(l)$, the list obtained by taking the first $i$ elements of $l$ and then appending the $i$-th element of $l$ is equal to taking the first $i+1$ elements of $l$. In other words: $$(\text{take}(l, i)).\text{concat}(l[i]) = \text{take}(l, i+1)$$
List.take_append_getElem theorem
{l : List α} {i : Nat} (h : i < l.length) : (l.take i) ++ [l[i]] = l.take (i + 1)
Full source
@[simp] theorem take_append_getElem {l : List α} {i : Nat} (h : i < l.length) :
    (l.take i) ++ [l[i]] = l.take (i+1) := by
  simpa using take_concat_get h
List Reconstruction via Take and Append: $\text{take}(i, l) +\!\!+ [l[i]] = \text{take}(i+1, l)$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number index $i$ such that $i < \text{length}(l)$, the concatenation of the first $i$ elements of $l$ with the singleton list containing the $i$-th element of $l$ is equal to the first $i+1$ elements of $l$. In other words: $$(\text{take}(l, i)) +\!\!+ [l[i]] = \text{take}(l, i+1)$$
List.take_succ_eq_append_getElem theorem
{i} {l : List α} (h : i < l.length) : l.take (i + 1) = l.take i ++ [l[i]]
Full source
theorem take_succ_eq_append_getElem {i} {l : List α} (h : i < l.length) : l.take (i + 1) = l.take i ++ [l[i]] :=
  (take_append_getElem h).symm
List Reconstruction via Take and Append: $\text{take}(i+1, l) = \text{take}(i, l) +\!\!+ [l[i]]$
Informal description
For any list $l$ of elements of type $\alpha$ and any natural number index $i$ such that $i < \text{length}(l)$, the first $i+1$ elements of $l$ can be obtained by concatenating the first $i$ elements of $l$ with the singleton list containing the $i$-th element of $l$. In other words: $$\text{take}(l, i+1) = \text{take}(l, i) +\!\!+ [l[i]]$$
List.take_append_getLast theorem
(l : List α) (h : l ≠ []) : (l.take (l.length - 1)) ++ [l.getLast h] = l
Full source
@[simp] theorem take_append_getLast (l : List α) (h : l ≠ []) :
    (l.take (l.length - 1)) ++ [l.getLast h] = l := by
  rw [getLast_eq_getElem]
  cases l
  · contradiction
  · simp
List Reconstruction via Take and Last Element: $\text{take}(|l| - 1, l) +\!\!+ [\text{last}(l)] = l$
Informal description
For any non-empty list $l$ of elements of type $\alpha$, the concatenation of the first $|l| - 1$ elements of $l$ with the singleton list containing the last element of $l$ reconstructs the original list $l$, i.e., $$(\text{take}(l, |l| - 1)) +\!\!+ [\text{getLast}(l, h)] = l$$ where $h$ is a proof that $l$ is non-empty.
List.take_append_getLast? theorem
(l : List α) : (l.take (l.length - 1)) ++ l.getLast?.toList = l
Full source
@[simp] theorem take_append_getLast? (l : List α) :
    (l.take (l.length - 1)) ++ l.getLast?.toList = l := by
  match l with
  | [] => simp
  | x :: xs =>
    simpa using take_append_getLast (x :: xs) (by simp)
List Reconstruction via Take and Optional Last Element: $\text{take}(|l| - 1, l) +\!\!+ \text{toList}(\text{getLast?}(l)) = l$
Informal description
For any list $l$ of elements of type $\alpha$, the concatenation of the first $|l| - 1$ elements of $l$ with the singleton list containing the last element of $l$ (or the empty list if $l$ is empty) reconstructs the original list $l$, i.e., $$\text{take}(l, |l| - 1) +\!\!+ \text{toList}(\text{getLast?}(l)) = l$$ where $\text{getLast?}(l)$ returns the last element of $l$ as an optional value and $\text{toList}$ converts this optional value to a list.
List.drop_left theorem
: ∀ {l₁ l₂ : List α}, drop (length l₁) (l₁ ++ l₂) = l₂
Full source
theorem drop_left : ∀ {l₁ l₂ : List α}, drop (length l₁) (l₁ ++ l₂) = l₂
  | [], _ => rfl
  | _ :: l₁, _ => drop_left (l₁ := l₁)
Drop of Concatenated Lists: $\text{drop}(|l_1|, l_1 ++ l_2) = l_2$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, dropping the first $|l_1|$ elements from the concatenated list $l_1 ++ l_2$ results in the list $l_2$, where $|l_1|$ denotes the length of $l_1$.
List.drop_left' theorem
{l₁ l₂ : List α} {i} (h : length l₁ = i) : drop i (l₁ ++ l₂) = l₂
Full source
@[simp]
theorem drop_left' {l₁ l₂ : List α} {i} (h : length l₁ = i) : drop i (l₁ ++ l₂) = l₂ := by
  rw [← h]; apply drop_left
Drop of Concatenated Lists with Explicit Length Condition: $\text{drop}(i, l_1 \mathbin{+\kern-0.5em+} l_2) = l_2$ when $|l_1| = i$
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, and any natural number $i$ such that the length of $l_1$ equals $i$, dropping the first $i$ elements from the concatenated list $l_1 \mathbin{+\kern-0.5em+} l_2$ results in the list $l_2$.
List.take_left theorem
: ∀ {l₁ l₂ : List α}, take (length l₁) (l₁ ++ l₂) = l₁
Full source
theorem take_left : ∀ {l₁ l₂ : List α}, take (length l₁) (l₁ ++ l₂) = l₁
  | [], _ => rfl
  | a :: _, _ => congrArg (cons a) take_left
Take Preserves Prefix in List Concatenation
Informal description
For any two lists $l_1$ and $l_2$ of type $\alpha$, taking the first $\text{length}(l_1)$ elements of the concatenated list $l_1 \mathbin{+\kern-0.5em+} l_2$ yields $l_1$.
List.take_left' theorem
{l₁ l₂ : List α} {i} (h : length l₁ = i) : take i (l₁ ++ l₂) = l₁
Full source
@[simp]
theorem take_left' {l₁ l₂ : List α} {i} (h : length l₁ = i) : take i (l₁ ++ l₂) = l₁ := by
  rw [← h]; apply take_left
Prefix Preservation in List Concatenation via Take with Length Condition
Informal description
For any two lists $l_1$ and $l_2$ of elements of type $\alpha$, and any natural number $i$ such that the length of $l_1$ equals $i$, taking the first $i$ elements of the concatenated list $l_1 \mathbin{+\kern-0.5em+} l_2$ yields $l_1$.
List.take_succ theorem
{l : List α} {i : Nat} : l.take (i + 1) = l.take i ++ l[i]?.toList
Full source
theorem take_succ {l : List α} {i : Nat} : l.take (i + 1) = l.take i ++ l[i]?.toList := by
  induction l generalizing i with
  | nil =>
    simp only [take_nil, Option.toList, getElem?_nil, append_nil]
  | cons hd tl hl =>
    cases i
    · simp only [take, Option.toList, getElem?_cons_zero, nil_append]
    · simp only [take, hl, getElem?_cons_succ, cons_append]
Recursive relation for $\text{take}(l, i+1)$ in terms of $\text{take}(l, i)$ and $l[i]?$
Informal description
For any list $l$ of type $\alpha$ and natural number $i$, taking the first $i+1$ elements of $l$ is equal to the concatenation of the first $i$ elements of $l$ with the singleton list containing the $i$-th element of $l$ (if it exists), i.e., $$\text{take}(l, i+1) = \text{take}(l, i) +\!\!\!+ [l[i]?]$$ where $[l[i]?]$ denotes the optional $i$-th element converted to a list (empty if out of bounds).
List.dropLast_eq_take theorem
{l : List α} : l.dropLast = l.take (l.length - 1)
Full source
theorem dropLast_eq_take {l : List α} : l.dropLast = l.take (l.length - 1) := by
  cases l with
  | nil => simp [dropLast]
  | cons x l =>
    induction l generalizing x <;> simp_all [dropLast]
Equivalence of Dropping Last Element and Taking All But Last Element
Informal description
For any list $l$ of elements of type $\alpha$, removing the last element of $l$ is equivalent to taking the first $\text{length}(l) - 1$ elements of $l$, i.e., \[ \text{dropLast}(l) = \text{take}(l, \text{length}(l) - 1). \]
List.map_take theorem
{f : α → β} : ∀ {l : List α} {i : Nat}, (l.take i).map f = (l.map f).take i
Full source
@[simp] theorem map_take {f : α → β} :
    ∀ {l : List α} {i : Nat}, (l.take i).map f = (l.map f).take i
  | [], i => by simp
  | _, 0 => by simp
  | _ :: tl, n + 1 => by dsimp; rw [map_take]
Commutativity of Map and Take: $\text{map } f \circ \text{take } i = \text{take } i \circ \text{map } f$
Informal description
For any function $f : \alpha \to \beta$, list $l$ of type $\text{List } \alpha$, and natural number $i$, mapping $f$ over the first $i$ elements of $l$ is equivalent to taking the first $i$ elements of the list obtained by mapping $f$ over $l$. In other words: \[ \text{map } f (\text{take } i\ l) = \text{take } i (\text{map } f\ l) \]
List.map_drop theorem
{f : α → β} : ∀ {l : List α} {i : Nat}, (l.drop i).map f = (l.map f).drop i
Full source
@[simp] theorem map_drop {f : α → β} :
    ∀ {l : List α} {i : Nat}, (l.drop i).map f = (l.map f).drop i
  | [], i => by simp
  | l, 0 => by simp
  | _ :: tl, n + 1 => by
    dsimp
    rw [map_drop]
Commutativity of Map and Drop: $\text{map } f \circ \text{drop } i = \text{drop } i \circ \text{map } f$
Informal description
For any function $f : \alpha \to \beta$, list $l$ of elements of type $\alpha$, and natural number $i$, the map of $f$ over the list obtained by dropping the first $i$ elements of $l$ is equal to the list obtained by dropping the first $i$ elements of the map of $f$ over $l$. In other words: \[ \text{map } f (\text{drop } i \, l) = \text{drop } i (\text{map } f \, l) \]
List.takeWhile_cons theorem
{p : α → Bool} {a : α} {l : List α} : (a :: l).takeWhile p = if p a then a :: l.takeWhile p else []
Full source
theorem takeWhile_cons {p : α → Bool} {a : α} {l : List α} :
    (a :: l).takeWhile p = if p a then a :: l.takeWhile p else [] := by
  simp only [takeWhile]
  by_cases h: p a <;> simp [h]
Recursive Definition of $\text{takeWhile}$ for Cons List
Informal description
For any predicate $p : \alpha \to \text{Bool}$, element $a : \alpha$, and list $l : \text{List } \alpha$, the result of applying $\text{takeWhile}$ to the list $a :: l$ is equal to $a :: \text{takeWhile } p \, l$ if $p(a)$ is true, and the empty list $[]$ otherwise. In other words: \[ \text{takeWhile } p \, (a :: l) = \begin{cases} a :: \text{takeWhile } p \, l & \text{if } p(a) = \text{true} \\ [] & \text{otherwise} \end{cases} \]
List.takeWhile_cons_of_pos theorem
{p : α → Bool} {a : α} {l : List α} (h : p a) : (a :: l).takeWhile p = a :: l.takeWhile p
Full source
@[simp] theorem takeWhile_cons_of_pos {p : α → Bool} {a : α} {l : List α} (h : p a) :
    (a :: l).takeWhile p = a :: l.takeWhile p := by
  simp [takeWhile_cons, h]
Initial Segment Preservation under Predicate for Nonempty Lists
Informal description
For any predicate $p : \alpha \to \text{Bool}$, element $a \in \alpha$, and list $l \in \text{List } \alpha$, if $p(a)$ holds, then the initial segment of the list $a :: l$ satisfying $p$ is equal to $a$ followed by the initial segment of $l$ satisfying $p$. That is: \[ \text{takeWhile } p \, (a :: l) = a :: \text{takeWhile } p \, l \]
List.takeWhile_cons_of_neg theorem
{p : α → Bool} {a : α} {l : List α} (h : ¬p a) : (a :: l).takeWhile p = []
Full source
@[simp] theorem takeWhile_cons_of_neg {p : α → Bool} {a : α} {l : List α} (h : ¬ p a) :
    (a :: l).takeWhile p = [] := by
  simp [takeWhile_cons, h]
Empty TakeWhile for Falsity at Head: $\text{takeWhile } p \, (a :: l) = []$ when $\neg p(a)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, element $a : \alpha$, and list $l : \text{List } \alpha$, if $p(a)$ is false, then the result of applying $\text{takeWhile}$ to the list $a :: l$ is the empty list $[]$.
List.dropWhile_cons theorem
: (x :: xs : List α).dropWhile p = if p x then xs.dropWhile p else x :: xs
Full source
theorem dropWhile_cons :
    (x :: xs : List α).dropWhile p = if p x then xs.dropWhile p else x :: xs := by
  split <;> simp_all [dropWhile]
Recursive Definition of `dropWhile` on Cons List
Informal description
For any predicate $p : \alpha \to \mathtt{Bool}$ and any list of the form $x :: xs$ (a head element $x$ followed by tail list $xs$), the result of `dropWhile p (x :: xs)` is equal to `xs.dropWhile p` if $p(x)$ is true, and equal to $x :: xs$ otherwise.
List.dropWhile_cons_of_pos theorem
{a : α} {l : List α} (h : p a) : (a :: l).dropWhile p = l.dropWhile p
Full source
@[simp] theorem dropWhile_cons_of_pos {a : α} {l : List α} (h : p a) :
    (a :: l).dropWhile p = l.dropWhile p := by
  simp [dropWhile_cons, h]
DropWhile on Cons List When Predicate Holds: $\mathtt{dropWhile}\, p\, (a :: l) = \mathtt{dropWhile}\, p\, l$ if $p(a)$
Informal description
For any predicate $p : \alpha \to \mathtt{Bool}$ and any list of the form $a :: l$ (a head element $a$ followed by tail list $l$), if $p(a)$ holds, then dropping elements from the list while $p$ holds results in the same as dropping elements from $l$ while $p$ holds, i.e., $\mathtt{dropWhile}\, p\, (a :: l) = \mathtt{dropWhile}\, p\, l$.
List.dropWhile_cons_of_neg theorem
{a : α} {l : List α} (h : ¬p a) : (a :: l).dropWhile p = a :: l
Full source
@[simp] theorem dropWhile_cons_of_neg {a : α} {l : List α} (h : ¬ p a) :
    (a :: l).dropWhile p = a :: l := by
  simp [dropWhile_cons, h]
`dropWhile` preserves list when head element fails predicate
Informal description
For any predicate $p : \alpha \to \mathtt{Bool}$, element $a \in \alpha$, and list $l$ of type $\alpha$, if $p(a)$ is false, then dropping elements from the list $a :: l$ while $p$ holds results in the original list $a :: l$.
List.head?_takeWhile theorem
{p : α → Bool} {l : List α} : (l.takeWhile p).head? = l.head?.filter p
Full source
theorem head?_takeWhile {p : α → Bool} {l : List α} : (l.takeWhile p).head? = l.head?.filter p := by
  cases l with
  | nil => rfl
  | cons x xs =>
    simp only [takeWhile_cons, head?_cons, Option.filter_some]
    split <;> simp
First Element of Take-While List Equals Filtered First Element
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l : \text{List } \alpha$, the first element of the list obtained by taking elements from $l$ while $p$ holds is equal to the first element of $l$ filtered by $p$. In other words: \[ \text{head?}(\text{takeWhile } p \, l) = \text{filter } p \, (\text{head? } l) \]
List.head_takeWhile theorem
{p : α → Bool} {l : List α} (w) : (l.takeWhile p).head w = l.head (by rintro rfl; simp_all)
Full source
theorem head_takeWhile {p : α → Bool} {l : List α} (w) :
    (l.takeWhile p).head w = l.head (by rintro rfl; simp_all) := by
  cases l with
  | nil => rfl
  | cons x xs =>
    simp only [takeWhile_cons, head_cons]
    simp only [takeWhile_cons] at w
    split <;> simp_all
Head of Take-While Equals Head of Original List
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and list $l : \text{List } \alpha$, if the list $\text{takeWhile } p \, l$ is non-empty (with witness $w$), then the head of $\text{takeWhile } p \, l$ equals the head of $l$.
List.head?_dropWhile_not theorem
(p : α → Bool) (l : List α) : match (l.dropWhile p).head? with | some x => p x = false | none => True
Full source
theorem head?_dropWhile_not (p : α → Bool) (l : List α) :
    match (l.dropWhile p).head? with | some x => p x = false | none => True := by
  induction l with
  | nil => simp
  | cons x xs ih =>
    simp only [dropWhile_cons]
    split <;> rename_i h <;> split at h <;> simp_all
Head of `dropWhile` List Satisfies Negated Predicate or List is Empty
Informal description
For any predicate $p : \alpha \to \mathtt{Bool}$ and any list $l$ of elements of type $\alpha$, the following holds: - If the list obtained by dropping the longest prefix of $l$ where $p$ holds (i.e., `l.dropWhile p`) has a first element $x$, then $p(x) = \mathtt{false}$. - If `l.dropWhile p` is empty, then the statement is vacuously true.
List.head_dropWhile_not theorem
(p : α → Bool) {l : List α} (w) : p ((l.dropWhile p).head w) = false
Full source
theorem head_dropWhile_not (p : α → Bool) {l : List α} (w) :
    p ((l.dropWhile p).head w) = false := by
  simpa [head?_eq_head, w] using head?_dropWhile_not p l
First Element After Dropping Satisfies Negated Predicate
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any non-empty list $l$ of elements of type $\alpha$, the first element of the list obtained by dropping the longest prefix of $l$ where $p$ holds satisfies $\neg p(x)$. In other words, if $x$ is the head of $\text{dropWhile}\ p\ l$, then $p(x) = \text{false}$.
List.takeWhile_map theorem
{f : α → β} {p : β → Bool} {l : List α} : (l.map f).takeWhile p = (l.takeWhile (p ∘ f)).map f
Full source
theorem takeWhile_map {f : α → β} {p : β → Bool} {l : List α} :
    (l.map f).takeWhile p = (l.takeWhile (p ∘ f)).map f := by
  induction l with
  | nil => rfl
  | cons x xs ih =>
    simp only [map_cons, takeWhile_cons]
    split <;> simp_all
Mapping Commutes with Take-While: $\text{takeWhile } p \circ \text{map } f = \text{map } f \circ \text{takeWhile } (p \circ f)$
Informal description
For any function $f : \alpha \to \beta$, predicate $p : \beta \to \text{Bool}$, and list $l : \text{List } \alpha$, the following equality holds: \[ \text{takeWhile } p \, (l.\text{map } f) = (\text{takeWhile } (p \circ f) \, l).\text{map } f \] In other words, taking elements from the mapped list while $p$ holds is equivalent to first taking elements from the original list while $p \circ f$ holds, and then mapping $f$ over the result.
List.dropWhile_map theorem
{f : α → β} {p : β → Bool} {l : List α} : (l.map f).dropWhile p = (l.dropWhile (p ∘ f)).map f
Full source
theorem dropWhile_map {f : α → β} {p : β → Bool} {l : List α} :
    (l.map f).dropWhile p = (l.dropWhile (p ∘ f)).map f := by
  induction l with
  | nil => rfl
  | cons x xs ih =>
    simp only [map_cons, dropWhile_cons]
    split <;> simp_all
Mapping Commutes with Drop-While: $(f \circ l).\text{dropWhile}\ p = (l.\text{dropWhile}\ (p \circ f)) \circ f$
Informal description
For any function $f : \alpha \to \beta$, predicate $p : \beta \to \mathtt{Bool}$, and list $l : \text{List}\ \alpha$, the following equality holds: $$(l.\text{map}\ f).\text{dropWhile}\ p = (l.\text{dropWhile}\ (p \circ f)).\text{map}\ f$$
List.takeWhile_filterMap theorem
{f : α → Option β} {p : β → Bool} {l : List α} : (l.filterMap f).takeWhile p = (l.takeWhile fun a => (f a).all p).filterMap f
Full source
theorem takeWhile_filterMap {f : α → Option β} {p : β → Bool} {l : List α} :
    (l.filterMap f).takeWhile p = (l.takeWhile fun a => (f a).all p).filterMap f := by
  induction l with
  | nil => rfl
  | cons x xs ih =>
    simp only [filterMap_cons]
    split <;> rename_i h
    · simp only [takeWhile_cons, h]
      split <;> simp_all
    · simp [takeWhile_cons, h, ih]
      split <;> simp_all [filterMap_cons]
Commutativity of $\text{takeWhile}$ and $\text{filterMap}$ with Predicate Lifting
Informal description
For any function $f : \alpha \to \text{Option } \beta$, predicate $p : \beta \to \text{Bool}$, and list $l$ of elements in $\alpha$, the following equality holds: \[ \text{takeWhile } p \ (\text{filterMap } f \ l) = \text{filterMap } f \ (\text{takeWhile } (a \mapsto \text{Option.all } p \ (f a)) \ l) \] Here, $\text{filterMap } f \ l$ applies $f$ to each element of $l$ and collects all $\text{some } b$ results, while $\text{takeWhile } p$ takes the longest prefix of a list where all elements satisfy $p$. The function $\text{Option.all } p$ checks if an optional value is either $\text{none}$ or satisfies $p$ when it is $\text{some } b$.
List.dropWhile_filterMap theorem
{f : α → Option β} {p : β → Bool} {l : List α} : (l.filterMap f).dropWhile p = (l.dropWhile fun a => (f a).all p).filterMap f
Full source
theorem dropWhile_filterMap {f : α → Option β} {p : β → Bool} {l : List α} :
    (l.filterMap f).dropWhile p = (l.dropWhile fun a => (f a).all p).filterMap f := by
  induction l with
  | nil => rfl
  | cons x xs ih =>
    simp only [filterMap_cons]
    split <;> rename_i h
    · simp only [dropWhile_cons, h]
      split <;> simp_all
    · simp [dropWhile_cons, h, ih]
      split <;> simp_all [filterMap_cons]
Commutativity of `dropWhile` and `filterMap`: $\text{dropWhile } p \circ \text{filterMap } f = \text{filterMap } f \circ \text{dropWhile } (\text{Option.all } p \circ f)$
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{dropWhile } p \circ \text{filterMap } f \ l = \text{filterMap } f \circ \text{dropWhile } (\lambda a, \text{Option.all } p (f a)) \ l \] where $\text{filterMap } f$ applies $f$ to each element of $l$ and collects the $\text{some } b$ results, and $\text{dropWhile } q$ removes the longest prefix of elements satisfying $q$.
List.takeWhile_filter theorem
{p q : α → Bool} {l : List α} : (l.filter p).takeWhile q = (l.takeWhile fun a => !p a || q a).filter p
Full source
theorem takeWhile_filter {p q : α → Bool} {l : List α} :
    (l.filter p).takeWhile q = (l.takeWhile fun a => !p a!p a || q a).filter p := by
  simp [← filterMap_eq_filter, takeWhile_filterMap]
Commutativity of $\text{filter}$ and $\text{takeWhile}$ with Predicate Combination
Informal description
For any predicates $p, q : \alpha \to \text{Bool}$ and any list $l$ of elements in $\alpha$, the following equality holds: \[ \text{filter } p \ (\text{takeWhile } q \ l) = \text{filter } p \ (\text{takeWhile } (a \mapsto \neg p(a) \lor q(a)) \ l) \] where $\text{filter } p$ selects elements satisfying $p$ and $\text{takeWhile } q$ takes the longest prefix of $l$ where all elements satisfy $q$.
List.dropWhile_filter theorem
{p q : α → Bool} {l : List α} : (l.filter p).dropWhile q = (l.dropWhile fun a => !p a || q a).filter p
Full source
theorem dropWhile_filter {p q : α → Bool} {l : List α} :
    (l.filter p).dropWhile q = (l.dropWhile fun a => !p a!p a || q a).filter p := by
  simp [← filterMap_eq_filter, dropWhile_filterMap]
Commutativity of `dropWhile` and `filter`: $\text{dropWhile } q \circ \text{filter } p = \text{filter } p \circ \text{dropWhile } (\neg p \lor q)$
Informal description
For any predicates $p, q : \alpha \to \text{Bool}$ and any list $l : \text{List } \alpha$, the following equality holds: \[ \text{dropWhile } q \circ \text{filter } p \ l = \text{filter } p \circ \text{dropWhile } (\lambda a, \neg p(a) \lor q(a)) \ l \] where $\text{filter } p$ selects elements of $l$ satisfying $p$, and $\text{dropWhile } r$ removes the longest prefix of elements satisfying $r$.
List.takeWhile_append_dropWhile theorem
{p : α → Bool} : ∀ {l : List α}, takeWhile p l ++ dropWhile p l = l
Full source
@[simp] theorem takeWhile_append_dropWhile {p : α → Bool} :
    ∀ {l : List α}, takeWhile p l ++ dropWhile p l = l
  | [] => rfl
  | x :: xs => by simp [takeWhile, dropWhile]; cases p x <;> simp [takeWhile_append_dropWhile]
Decomposition of List into TakeWhile and DropWhile: $(\text{takeWhile } p \, l) \mathbin{+\!\!+} (\text{dropWhile } p \, l) = l$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and any list $l : \text{List } \alpha$, the concatenation of the longest prefix of $l$ where $p$ holds for all elements (`takeWhile p l`) and the remaining suffix of $l$ after dropping this prefix (`dropWhile p l`) equals the original list $l$. In other words, $(\text{takeWhile } p \, l) \mathbin{+\!\!+} (\text{dropWhile } p \, l) = l$.
List.takeWhile_append theorem
{xs ys : List α} : (xs ++ ys).takeWhile p = if (xs.takeWhile p).length = xs.length then xs ++ ys.takeWhile p else xs.takeWhile p
Full source
theorem takeWhile_append {xs ys : List α} :
    (xs ++ ys).takeWhile p =
      if (xs.takeWhile p).length = xs.length then xs ++ ys.takeWhile p else xs.takeWhile p := by
  induction xs with
  | nil => simp
  | cons x xs ih =>
    simp only [cons_append, takeWhile_cons]
    split
    · simp_all only [length_cons, add_one_inj]
      split <;> rfl
    · simp_all
TakeWhile of Concatenated Lists: $\text{takeWhile } p \, (xs \mathbin{+\!\!+} ys)$
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and lists $xs, ys : \text{List } \alpha$, the result of applying $\text{takeWhile}$ to the concatenated list $xs \mathbin{+\!\!+} ys$ is given by: \[ \text{takeWhile } p \, (xs \mathbin{+\!\!+} ys) = \begin{cases} xs \mathbin{+\!\!+} \text{takeWhile } p \, ys & \text{if } \text{length}(\text{takeWhile } p \, xs) = \text{length}(xs) \\ \text{takeWhile } p \, xs & \text{otherwise} \end{cases} \]
List.takeWhile_append_of_pos theorem
{p : α → Bool} {l₁ l₂ : List α} (h : ∀ a ∈ l₁, p a) : (l₁ ++ l₂).takeWhile p = l₁ ++ l₂.takeWhile p
Full source
@[simp] theorem takeWhile_append_of_pos {p : α → Bool} {l₁ l₂ : List α} (h : ∀ a ∈ l₁, p a) :
    (l₁ ++ l₂).takeWhile p = l₁ ++ l₂.takeWhile p := by
  induction l₁ with
  | nil => simp
  | cons x xs ih => simp_all [takeWhile_cons]
TakeWhile Preserves Concatenation When Predicate Holds on First List
Informal description
For any predicate $p : \alpha \to \text{Bool}$ and lists $l_1, l_2 : \text{List } \alpha$, if $p(a)$ holds for every element $a$ in $l_1$, then the initial segment of the concatenated list $l_1 \mathbin{+\!\!+} l_2$ satisfying $p$ is equal to $l_1$ concatenated with the initial segment of $l_2$ satisfying $p$. That is: \[ \text{takeWhile } p \, (l_1 \mathbin{+\!\!+} l_2) = l_1 \mathbin{+\!\!+} \text{takeWhile } p \, l_2 \]
List.dropWhile_append theorem
{xs ys : List α} : (xs ++ ys).dropWhile p = if (xs.dropWhile p).isEmpty then ys.dropWhile p else xs.dropWhile p ++ ys
Full source
theorem dropWhile_append {xs ys : List α} :
    (xs ++ ys).dropWhile p =
      if (xs.dropWhile p).isEmpty then ys.dropWhile p else xs.dropWhile p ++ ys := by
  induction xs with
  | nil => simp
  | cons _ _ ih =>
    simp only [cons_append, dropWhile_cons]
    split <;> simp_all
Behavior of `dropWhile` on concatenated lists
Informal description
For any lists `xs` and `ys` of elements of type `α` and any predicate `p : α → Bool`, the result of applying `dropWhile p` to the concatenated list `xs ++ ys` is equal to `ys.dropWhile p` if `xs.dropWhile p` is empty, and equal to `xs.dropWhile p ++ ys` otherwise.
List.dropWhile_append_of_pos theorem
{p : α → Bool} {l₁ l₂ : List α} (h : ∀ a ∈ l₁, p a) : (l₁ ++ l₂).dropWhile p = l₂.dropWhile p
Full source
@[simp] theorem dropWhile_append_of_pos {p : α → Bool} {l₁ l₂ : List α} (h : ∀ a ∈ l₁, p a) :
    (l₁ ++ l₂).dropWhile p = l₂.dropWhile p := by
  induction l₁ with
  | nil => simp
  | cons x xs ih => simp_all [dropWhile_cons]
DropWhile on Concatenated Lists When Predicate Holds for First List: $\mathtt{dropWhile}\, p\, (l_1 ++ l_2) = \mathtt{dropWhile}\, p\, l_2$ if $\forall a \in l_1, p(a)$
Informal description
For any predicate $p : \alpha \to \mathtt{Bool}$ and any lists $l_1$ and $l_2$ of elements of type $\alpha$, if $p(a)$ holds for every element $a$ in $l_1$, then dropping elements from the concatenated list $l_1 ++ l_2$ while $p$ holds results in the same as dropping elements from $l_2$ while $p$ holds, i.e., $\mathtt{dropWhile}\, p\, (l_1 ++ l_2) = \mathtt{dropWhile}\, p\, l_2$.
List.takeWhile_replicate_eq_filter theorem
{p : α → Bool} : (replicate n a).takeWhile p = (replicate n a).filter p
Full source
@[simp] theorem takeWhile_replicate_eq_filter {p : α → Bool} :
    (replicate n a).takeWhile p = (replicate n a).filter p := by
  induction n with
  | zero => simp
  | succ n ih =>
    simp only [replicate_succ, takeWhile_cons]
    split <;> simp_all
Equality of `takeWhile` and `filter` on Replicated Lists
Informal description
For any predicate $p : \alpha \to \text{Bool}$, natural number $n$, and element $a \in \alpha$, the list obtained by taking elements from the replicated list $\text{replicate}\ n\ a$ while $p$ holds is equal to the result of filtering the same replicated list with $p$. That is, \[ \text{takeWhile}\ p\ (\text{replicate}\ n\ a) = \text{filter}\ p\ (\text{replicate}\ n\ a). \]
List.takeWhile_replicate theorem
{p : α → Bool} : (replicate n a).takeWhile p = if p a then replicate n a else []
Full source
theorem takeWhile_replicate {p : α → Bool} :
    (replicate n a).takeWhile p = if p a then replicate n a else [] := by
  rw [takeWhile_replicate_eq_filter, filter_replicate]
$\text{takeWhile}$ on Replicated List: $\text{takeWhile}\ 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 \in \alpha$, the list obtained by taking elements from the replicated list $\text{replicate}\ n\ a$ while $p$ holds is equal to: - $\text{replicate}\ n\ a$ if $p(a)$ is true, - the empty list $[]$ otherwise.
List.dropWhile_replicate_eq_filter_not theorem
{p : α → Bool} : (replicate n a).dropWhile p = (replicate n a).filter (fun a => !p a)
Full source
@[simp] theorem dropWhile_replicate_eq_filter_not {p : α → Bool} :
    (replicate n a).dropWhile p = (replicate n a).filter (fun a => !p a) := by
  induction n with
  | zero => simp
  | succ n ih =>
    simp only [replicate_succ, dropWhile_cons]
    split <;> simp_all
Equivalence of `dropWhile` and `filter` on Replicated Lists: $\text{dropWhile}_p = \text{filter}_{\neg p}$
Informal description
For any predicate $p : \alpha \to \text{Bool}$, natural number $n$, and element $a : \alpha$, dropping the longest prefix of the replicated list $\text{replicate}\ n\ a$ where $p$ holds is equivalent to filtering the list by the negation of $p$. That is: \[ \text{dropWhile}_p (\text{replicate}\ n\ a) = \text{filter}\ (\lambda x, \neg p\ x)\ (\text{replicate}\ n\ a) \]
List.dropWhile_replicate theorem
{p : α → Bool} : (replicate n a).dropWhile p = if p a then [] else replicate n a
Full source
theorem dropWhile_replicate {p : α → Bool} :
    (replicate n a).dropWhile p = if p a then [] else replicate n a := by
  simp only [dropWhile_replicate_eq_filter_not, filter_replicate]
  split <;> simp_all
Behavior of `dropWhile` on Replicated Lists: $\text{dropWhile}_p(\text{replicate}(n, a)) = \text{if } p(a) \text{ then } [] \text{ else } \text{replicate}(n, a)$
Informal description
For any predicate $p : \alpha \to \{\text{true}, \text{false}\}$, natural number $n$, and element $a \in \alpha$, the result of dropping the longest prefix of the list $\text{replicate}(n, a)$ (which consists of $n$ copies of $a$) where $p$ holds is: - the empty list $[]$ if $p(a) = \text{true}$, - the original replicated list $\text{replicate}(n, a)$ otherwise.
List.take_takeWhile theorem
{l : List α} {p : α → Bool} : (l.takeWhile p).take i = (l.take i).takeWhile p
Full source
theorem take_takeWhile {l : List α} {p : α → Bool} :
    (l.takeWhile p).take i = (l.take i).takeWhile p := by
  induction l generalizing i with
  | nil => simp
  | cons x xs ih =>
    by_cases h : p x <;> cases i <;> simp [takeWhile_cons, h, ih, take_succ_cons]
Commutativity of `take` and `takeWhile`: $\text{take}_i \circ \text{takeWhile}_p = \text{takeWhile}_p \circ \text{take}_i$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, taking the first $i$ elements of the initial segment of $l$ satisfying $p$ is equivalent to taking the initial segment of the first $i$ elements of $l$ that satisfy $p$. In other words: \[ \text{take}_i (\text{takeWhile}_p \, l) = \text{takeWhile}_p (\text{take}_i \, l) \]
List.all_takeWhile theorem
{l : List α} : (l.takeWhile p).all p = true
Full source
@[simp] theorem all_takeWhile {l : List α} : (l.takeWhile p).all p = true := by
  induction l with
  | nil => rfl
  | cons h _ ih => by_cases p h <;> simp_all
All Elements in Initial Segment Satisfy Predicate: $\text{all } p (\text{takeWhile } p \, l) = \text{true}$
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \text{Bool}$, the result of applying the `all` function to the initial segment `takeWhile p l` (which consists of the longest prefix of $l$ where all elements satisfy $p$) and the predicate $p$ is always `true`. In other words, all elements in `takeWhile p l` satisfy $p$.
List.any_dropWhile theorem
{l : List α} : (l.dropWhile p).any (fun x => !p x) = !l.all p
Full source
@[simp] theorem any_dropWhile {l : List α} :
    (l.dropWhile p).any (fun x => !p x) = !l.all p := by
  induction l with
  | nil => rfl
  | cons h _ ih => by_cases p h <;> simp_all
Existence of Non-Satisfying Element in Remainder After `dropWhile` is Equivalent to Not All Elements Satisfy Predicate
Informal description
For any list $l$ of elements of type $\alpha$ and any predicate $p : \alpha \to \mathtt{Bool}$, the existence of an element in the remaining list after dropping the longest prefix where $p$ holds that satisfies $\neg p$ is equivalent to the negation of the statement that all elements in $l$ satisfy $p$. In other words, $(\mathtt{dropWhile}\, p\, l).\mathtt{any}\, (\lambda x, \neg p x) = \neg (l.\mathtt{all}\, p)$.
List.replace_takeWhile theorem
[BEq α] [LawfulBEq α] {l : List α} {p : α → Bool} (h : p a = p b) : (l.takeWhile p).replace a b = (l.replace a b).takeWhile p
Full source
theorem replace_takeWhile [BEq α] [LawfulBEq α] {l : List α} {p : α → Bool} (h : p a = p b) :
    (l.takeWhile p).replace a b = (l.replace a b).takeWhile p := by
  induction l with
  | nil => rfl
  | cons x xs ih =>
    simp only [takeWhile_cons, replace_cons]
    split <;> rename_i h₁ <;> split <;> rename_i h₂
    · simp_all
    · simp [replace_cons, h₂, takeWhile_cons, h₁, ih]
    · simp_all
    · simp_all
Commutation of List Replacement and TakeWhile under Predicate Preservation: $(l.\text{takeWhile } p).\text{replace } a \, b = (l.\text{replace } a \, b).\text{takeWhile } p$ when $p(a) = p(b)$
Informal description
Let $\alpha$ be a type with a lawful boolean equality relation, and let $l$ be a list of elements of type $\alpha$. For any predicate $p : \alpha \to \text{Bool}$ and elements $a, b \in \alpha$ such that $p(a) = p(b)$, replacing $a$ with $b$ in the initial segment of $l$ satisfying $p$ is equivalent to first replacing $a$ with $b$ in $l$ and then taking the initial segment satisfying $p$. That is: \[ (l.\text{takeWhile } p).\text{replace } a \, b = (l.\text{replace } a \, b).\text{takeWhile } p \]
List.splitAt_eq theorem
{i : Nat} {l : List α} : splitAt i l = (l.take i, l.drop i)
Full source
@[simp] theorem splitAt_eq {i : Nat} {l : List α} : splitAt i l = (l.take i, l.drop i) := by
  rw [splitAt, splitAt_go, reverse_nil, nil_append]
  split <;> simp_all [take_of_length_le, drop_of_length_le]
Split-Take-Drop Equality: $\text{splitAt}(i, l) = (\text{take}(i, l), \text{drop}(i, l))$
Informal description
For any natural number $i$ and any list $l$ of elements of type $\alpha$, the result of splitting $l$ at index $i$ is equal to the pair consisting of the first $i$ elements of $l$ and the remaining elements after dropping the first $i$ elements, i.e., $\text{splitAt}(i, l) = (\text{take}(i, l), \text{drop}(i, l))$.
List.rotateLeft_zero theorem
{l : List α} : rotateLeft l 0 = l
Full source
@[simp] theorem rotateLeft_zero {l : List α} : rotateLeft l 0 = l := by
  simp [rotateLeft]
Left Rotation by Zero Preserves List: $\text{rotateLeft}(l, 0) = l$
Informal description
For any list $l$ of elements of type $\alpha$, rotating $l$ left by $0$ positions leaves the list unchanged, i.e., $\text{rotateLeft}(l, 0) = l$.
List.rotateRight_zero theorem
{l : List α} : rotateRight l 0 = l
Full source
@[simp] theorem rotateRight_zero {l : List α} : rotateRight l 0 = l := by
  simp [rotateRight]
Right Rotation by Zero Preserves List: $\text{rotateRight}(l, 0) = l$
Informal description
For any list $l$ of elements of type $\alpha$, rotating $l$ to the right by $0$ positions leaves the list unchanged, i.e., $\text{rotateRight}(l, 0) = l$.