File: .lake/packages/lean4/src/lean/Init/Data/List/Basic.lean

full_name: List.length_nil
code: @[simp] theorem length_nil : length ([] : List α) = 0 
goal: List.nil.length = 0

full_name: List.length_singleton
code: @[simp 1100] theorem length_singleton (a : α) : length [a] = 1 
goal: (a :: List.nil).length = 1

full_name: List.length_cons
code: @[simp] theorem length_cons {α} (a : α) (as : List α) : (cons a as).length = as.length + 1 
goal: (a :: as).length = as.length + 1

full_name: List.length_set
code: @[simp] theorem length_set (as : List α) (i : Nat) (a : α) : (as.set i a).length = as.length 
goal: (as.set i a).length = as.length

full_name: List.foldl_nil
code: @[simp] theorem foldl_nil : [].foldl f b = b 
goal: ∀ {α : Type u_1} {β : Type u_2} {f : α → β → α} {b : α}, List.foldl f b List.nil = b

full_name: List.foldl_cons
code: @[simp] theorem foldl_cons (l : List α) (b : β) : (a :: l).foldl f b = l.foldl f (f b a) 
goal: List.foldl f b (a :: l) = List.foldl f (f b a) l

full_name: List.length_concat
code: @[simp] theorem length_concat (as : List α) (a : α) : (concat as a).length = as.length + 1 
goal: (as.concat a).length = as.length + 1

full_name: List.of_concat_eq_concat
code: theorem of_concat_eq_concat {as bs : List α} {a b : α} (h : as.concat a = bs.concat b) : as = bs ∧ a = b 
goal: as = bs ∧ a = b

full_name: List.beq
code: /--
The equality relation on lists asserts that they have the same length
and they are pairwise `BEq`.
-/
protected def beq [BEq α] : List α → List α → Bool
  
goal: List α → List α → Bool

full_name: List.«instBEq_.lake»
code: instance [BEq α] : BEq (List α) 
goal: BEq (List α)

full_name: List.«instLawfulBEq_.lake»
code: instance [BEq α] [LawfulBEq α] : LawfulBEq (List α) 
goal: LawfulBEq (List α)

full_name: List.isEqv
code: /--
`O(min |as| |bs|)`. Returns true if `as` and `bs` have the same length,
and they are pairwise related by `eqv`.
-/
@[specialize] def isEqv : (as bs : List α) → (eqv : α → α → Bool) → Bool
  
goal: Bool

full_name: List.isEqv_nil_nil
code: @[simp] theorem isEqv_nil_nil : isEqv ([] : List α) [] eqv = true 
goal: List.nil.isEqv List.nil eqv = true

full_name: List.isEqv_nil_cons
code: @[simp] theorem isEqv_nil_cons : isEqv ([] : List α) (a::as) eqv = false 
goal: List.nil.isEqv (a :: as) eqv = false

full_name: List.isEqv_cons_nil
code: @[simp] theorem isEqv_cons_nil : isEqv (a::as : List α) [] eqv = false 
goal: (a :: as).isEqv List.nil eqv = false

full_name: List.isEqv_cons₂
code: theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv) 
goal: ∀ {α : Type u_1} {a : α} {as : List α} {b : α} {bs : List α} {eqv : α → α → Bool},
  (a :: as).isEqv (b :: bs) eqv = (eqv a b && as.isEqv bs eqv)

full_name: List.lt
code: /--
The lexicographic order on lists.
`[] < a::as`, and `a::as < b::bs` if `a < b` or if `a` and `b` are equivalent and `as < bs`.
-/
inductive lt [LT α] : List α → List α → Prop where
  /-- `[]` is the smallest element in the order. -/
  | nil  (b : α) (bs : List α) : lt [] (b::bs)
  /-- If `a < b` then `a::as < b::bs`. -/
  | head {a : α} (as : List α) {b : α} (bs : List α) : a < b → lt (a::as) (b::bs)
  /-- If `a` and `b` are equivalent and `as < bs`, then `a::as < b::bs`. -/
  | tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → lt as bs → lt (a::as) (b::bs)
goal: List α → List α → Prop

full_name: List.lt.tail
code: /--
The lexicographic order on lists.
`[] < a::as`, and `a::as < b::bs` if `a < b` or if `a` and `b` are equivalent and `as < bs`.
-/
inductive lt [LT α] : List α → List α → Prop where
  /-- `[]` is the smallest element in the order. -/
  | nil  (b : α) (bs : List α) : lt [] (b::bs)
  /-- If `a < b` then `a::as < b::bs`. -/
  | head {a : α} (as : List α) {b : α} (bs : List α) : a < b → lt (a::as) (b::bs)
  /-- If `a` and `b` are equivalent and `as < bs`, then `a::as < b::bs`. -/
  | tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → lt as bs → lt (a::as) (b::bs)
goal: ¬a < b → ¬b < a → as.lt bs → (a :: as).lt (b :: bs)

full_name: List.lt.head
code: /--
The lexicographic order on lists.
`[] < a::as`, and `a::as < b::bs` if `a < b` or if `a` and `b` are equivalent and `as < bs`.
-/
inductive lt [LT α] : List α → List α → Prop where
  /-- `[]` is the smallest element in the order. -/
  | nil  (b : α) (bs : List α) : lt [] (b::bs)
  /-- If `a < b` then `a::as < b::bs`. -/
  | head {a : α} (as : List α) {b : α} (bs : List α) : a < b → lt (a::as) (b::bs)
  /-- If `a` and `b` are equivalent and `as < bs`, then `a::as < b::bs`. -/
  | tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → lt as bs → lt (a::as) (b::bs)
goal: a < b → (a :: as).lt (b :: bs)

full_name: List.lt.nil
code: /--
The lexicographic order on lists.
`[] < a::as`, and `a::as < b::bs` if `a < b` or if `a` and `b` are equivalent and `as < bs`.
-/
inductive lt [LT α] : List α → List α → Prop where
  /-- `[]` is the smallest element in the order. -/
  | nil  (b : α) (bs : List α) : lt [] (b::bs)
  /-- If `a < b` then `a::as < b::bs`. -/
  | head {a : α} (as : List α) {b : α} (bs : List α) : a < b → lt (a::as) (b::bs)
  /-- If `a` and `b` are equivalent and `as < bs`, then `a::as < b::bs`. -/
  | tail {a : α} {as : List α} {b : α} {bs : List α} : ¬ a < b → ¬ b < a → lt as bs → lt (a::as) (b::bs)
goal: List.nil.lt (b :: bs)

full_name: List.«instLT_.lake»
code: instance [LT α] : LT (List α) 
goal: LT (List α)

full_name: List.hasDecidableLt
code: instance hasDecidableLt [LT α] [h : DecidableRel (α := α) (· < ·)] : (l₁ l₂ : List α) → Decidable (l₁ < l₂)
  
goal: Decidable (l₁ < l₂)

full_name: List.le
code: /-- The lexicographic order on lists. -/
@[reducible] protected def le [LT α] (a b : List α) : Prop 
goal: Prop

full_name: List.«instLEOfLT_.lake»
code: instance [LT α] : LE (List α) 
goal: LE (List α)

full_name: List.«instDecidableLeOfDecidableRelLt_.lake»
code: instance [LT α] [DecidableRel ((· < ·) : α → α → Prop)] : (l₁ l₂ : List α) → Decidable (l₁ ≤ l₂) 
goal: Decidable (l₁ ≤ l₂)

full_name: List.get?
code: /--
Returns the `i`-th element in the list (zero-based).

If the index is out of bounds (`i ≥ as.length`), this function returns `none`.
Also see `get`, `getD` and `get!`.
-/
def get? : (as : List α) → (i : Nat) → Option α
  
goal: Option α

full_name: List.get?_nil
code: @[simp] theorem get?_nil : @get? α [] n = none 
goal: List.nil.get? n = none

full_name: List.get?_cons_zero
code: @[simp] theorem get?_cons_zero : @get? α (a::l) 0 = some a 
goal: (a :: l).get? 0 = some a

full_name: List.get?_cons_succ
code: @[simp] theorem get?_cons_succ : @get? α (a::l) (n+1) = get? l n 
goal: (a :: l).get? (n + 1) = l.get? n

full_name: List.ext_get?
code: theorem ext_get? : ∀ {l₁ l₂ : List α}, (∀ n, l₁.get? n = l₂.get? n) → l₁ = l₂
  
goal: (∀ (n : Nat), l₁.get? n = l₂.get? n) → l₁ = l₂

full_name: List.ext
code: /-- Deprecated alias for `ext_get?`. The preferred extensionality theorem is now `ext_getElem?`. -/
@[deprecated (since := "2024-06-07")] abbrev ext 
goal: (∀ (n : Nat), l₁.get? n = l₂.get? n) → l₁ = l₂

full_name: List.getD
code: /--
Returns the `i`-th element in the list (zero-based).

If the index is out of bounds (`i ≥ as.length`), this function returns `fallback`.
See also `get?` and `get!`.
-/
def getD (as : List α) (i : Nat) (fallback : α) : α 
goal: α

full_name: List.getD_nil
code: @[simp] theorem getD_nil : getD [] n d = d 
goal: ∀ {α : Type u_1} {d : α}, List.nil.getD n d = d

full_name: List.getD_cons_zero
code: @[simp] theorem getD_cons_zero : getD (x :: xs) 0 d = x 
goal: ∀ {α : Type u_1} {x : α} {xs : List α} {d : α}, (x :: xs).getD 0 d = x

full_name: List.getD_cons_succ
code: @[simp] theorem getD_cons_succ : getD (x :: xs) (n + 1) d = getD xs n d 
goal: ∀ {α : Type u_1} {x : α} {xs : List α} {n : Nat} {d : α}, (x :: xs).getD (n + 1) d = xs.getD n d

full_name: List.getLast
code: /--
Returns the last element of a non-empty list.
-/
def getLast : ∀ (as : List α), as ≠ [] → α
  
goal: as ≠ List.nil → α

full_name: List.getLast?
code: /--
Returns the last element in the list.

If the list is empty, this function returns `none`.
Also see `getLastD` and `getLast!`.
-/
def getLast? : List α → Option α
  
goal: List α → Option α

full_name: List.getLast?_nil
code: @[simp] theorem getLast?_nil : @getLast? α [] = none 
goal: List.nil.getLast? = none

full_name: List.getLastD
code: /--
Returns the last element in the list.

If the list is empty, this function returns `fallback`.
Also see `getLast?` and `getLast!`.
-/
def getLastD : (as : List α) → (fallback : α) → α
  
goal: α

full_name: List.getLastD_nil
code: @[simp] theorem getLastD_nil (a) : @getLastD α [] a = a 
goal: List.nil.getLastD a = a

full_name: List.getLastD_cons
code: @[simp] theorem getLastD_cons (a b l) : @getLastD α (b::l) a = getLastD l b 
goal: (b :: l).getLastD a = l.getLastD b

full_name: List.head
code: /--
Returns the first element of a non-empty list.
-/
def head : (as : List α) → as ≠ [] → α
  
goal: as ≠ List.nil → α

full_name: List.head_cons
code: @[simp] theorem head_cons : @head α (a::l) h = a 
goal: (a :: l).head h = a

full_name: List.head?
code: /--
Returns the first element in the list.

If the list is empty, this function returns `none`.
Also see `headD` and `head!`.
-/
def head? : List α → Option α
  
goal: List α → Option α

full_name: List.head?_nil
code: @[simp] theorem head?_nil : @head? α [] = none 
goal: List.nil.head? = none

full_name: List.head?_cons
code: @[simp] theorem head?_cons : @head? α (a::l) = some a 
goal: (a :: l).head? = some a

full_name: List.headD
code: /--
Returns the first element in the list.

If the list is empty, this function returns `fallback`.
Also see `head?` and `head!`.
-/
def headD : (as : List α) → (fallback : α) → α
  
goal: α

full_name: List.headD_nil
code: @[simp 1100] theorem headD_nil : @headD α [] d = d 
goal: List.nil.headD d = d

full_name: List.headD_cons
code: @[simp 1100] theorem headD_cons : @headD α (a::l) d = a 
goal: (a :: l).headD d = a

full_name: List.tail?
code: /--
Drops the first element of the list.

If the list is empty, this function returns `none`.
Also see `tailD` and `tail!`.
-/
def tail? : List α → Option (List α)
  
goal: List α → Option (List α)

full_name: List.tail?_nil
code: @[simp] theorem tail?_nil : @tail? α [] = none 
goal: List.nil.tail? = none

full_name: List.tail?_cons
code: @[simp] theorem tail?_cons : @tail? α (a::l) = some l 
goal: (a :: l).tail? = some l

full_name: List.tailD
code: /--
Drops the first element of the list.

If the list is empty, this function returns `fallback`.
Also see `head?` and `head!`.
-/
def tailD (list fallback : List α) : List α 
goal: List α

full_name: List.tailD_nil
code: @[simp 1100] theorem tailD_nil : @tailD α [] l' = l' 
goal: List.nil.tailD l' = l'

full_name: List.tailD_cons
code: @[simp 1100] theorem tailD_cons : @tailD α (a::l) l' = l 
goal: (a :: l).tailD l' = l

full_name: List.map
code: /--
`O(|l|)`. `map f l` applies `f` to each element of the list.
* `map f [a, b, c] = [f a, f b, f c]`
-/
@[specialize] def map (f : α → β) : List α → List β
  
goal: List α → List β

full_name: List.map_nil
code: @[simp] theorem map_nil {f : α → β} : map f [] = [] 
goal: List.map f List.nil = List.nil

full_name: List.map_cons
code: @[simp] theorem map_cons (f : α → β) a l : map f (a :: l) = f a :: map f l 
goal: List.map f (a :: l) = f a :: List.map f l

full_name: List.filter
code: /--
`O(|l|)`. `filter f l` returns the list of elements in `l` for which `f` returns true.
```
filter (· > 2) [1, 2, 5, 2, 7, 7] = [5, 7, 7]
```
-/
def filter (p : α → Bool) : List α → List α
  
goal: List α → List α

full_name: List.filter_nil
code: @[simp] theorem filter_nil (p : α → Bool) : filter p [] = [] 
goal: List.filter p List.nil = List.nil

full_name: List.filterMap
code: /--
`O(|l|)`. `filterMap f l` takes a function `f : α → Option β` and applies it to each element of `l`;
the resulting non-`none` values are collected to form the output list.
```
filterMap
  (fun x => if x > 2 then some (2 * x) else none)
  [1, 2, 5, 2, 7, 7]
= [10, 14, 14]
```
-/
@[specialize] def filterMap (f : α → Option β) : List α → List β
  
goal: List α → List β

full_name: List.filterMap_nil
code: @[simp] theorem filterMap_nil (f : α → Option β) : filterMap f [] = [] 
goal: List.filterMap f List.nil = List.nil

full_name: List.filterMap_cons
code: theorem filterMap_cons (f : α → Option β) (a : α) (l : List α) :
    filterMap f (a :: l) =
      match f a with
      | none => filterMap f l
      | some b => b :: filterMap f l 
goal: List.filterMap f (a :: l) =
  match f a with
  | none => List.filterMap f l
  | some b => b :: List.filterMap f l

full_name: List.foldr
code: /--
`O(|l|)`. Applies function `f` to all of the elements of the list, from right to left.
* `foldr f init [a, b, c] = f a <| f b <| f c <| init`
-/
@[specialize] def foldr (f : α → β → β) (init : β) : List α → β
  
goal: List α → β

full_name: List.foldr_nil
code: @[simp] theorem foldr_nil : [].foldr f b = b 
goal: ∀ {α : Type u_1} {α_1 : Type u_2} {f : α → α_1 → α_1} {b : α_1}, List.foldr f b List.nil = b

full_name: List.foldr_cons
code: @[simp] theorem foldr_cons (l : List α) : (a :: l).foldr f b = f a (l.foldr f b) 
goal: ∀ {α_1 : Type u_1} {f : α → α_1 → α_1} {b : α_1} (l : List α), List.foldr f b (a :: l) = f a (List.foldr f b l)

full_name: List.reverseAux
code: /-- Auxiliary for `List.reverse`. `List.reverseAux l r = l.reverse ++ r`, but it is defined directly. -/
def reverseAux : List α → List α → List α
  
goal: List α → List α → List α

full_name: List.reverseAux_nil
code: @[simp] theorem reverseAux_nil : reverseAux [] r = r 
goal: ∀ {α : Type u_1} {r : List α}, List.nil.reverseAux r = r

full_name: List.reverseAux_cons
code: @[simp] theorem reverseAux_cons : reverseAux (a::l) r = reverseAux l (a::r) 
goal: ∀ {α : Type u_1} {a : α} {l r : List α}, (a :: l).reverseAux r = l.reverseAux (a :: r)

full_name: List.reverse
code: /--
`O(|as|)`. Reverse of a list:
* `[1, 2, 3, 4].reverse = [4, 3, 2, 1]`

Note that because of the "functional but in place" optimization implemented by Lean's compiler,
this function works without any allocations provided that the input list is unshared:
it simply walks the linked list and reverses all the node pointers.
-/
def reverse (as : List α) : List α 
goal: List α

full_name: List.reverse_nil
code: @[simp] theorem reverse_nil : reverse ([] : List α) = [] 
goal: List.nil.reverse = List.nil

full_name: List.reverseAux_reverseAux
code: theorem reverseAux_reverseAux (as bs cs : List α) : reverseAux (reverseAux as bs) cs = reverseAux bs (reverseAux (reverseAux as []) cs) 
goal: (as.reverseAux bs).reverseAux cs = bs.reverseAux ((as.reverseAux List.nil).reverseAux cs)

full_name: List.append
code: /--
`O(|xs|)`: append two lists. `[1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]`.
It takes time proportional to the first list.
-/
protected def append : (xs ys : List α) → List α
  
goal: List α

full_name: List.appendTR
code: /-- Tail-recursive version of `List.append`.

Most of the tail-recursive implementations are in `Init.Data.List.Impl`,
but `appendTR` must be set up immediately,
because otherwise `Append (List α)` instance below will not use it.
-/
def appendTR (as bs : List α) : List α 
goal: List α

full_name: List.append_eq_appendTR
code: @[csimp] theorem append_eq_appendTR : @List.append = @appendTR 
goal: @List.append = @List.appendTR

full_name: List.«instAppend_.lake»
code: instance : Append (List α) 
goal: Append (List α)

full_name: List.append_eq
code: @[simp] theorem append_eq (as bs : List α) : List.append as bs = as ++ bs 
goal: as.append bs = as ++ bs

full_name: List.nil_append
code: @[simp] theorem nil_append (as : List α) : [] ++ as = as 
goal: List.nil ++ as = as

full_name: List.cons_append
code: @[simp] theorem cons_append (a : α) (as bs : List α) : (a::as) ++ bs = a::(as ++ bs) 
goal: a :: as ++ bs = a :: (as ++ bs)

full_name: List.append_nil
code: @[simp] theorem append_nil (as : List α) : as ++ [] = as 
goal: as ++ List.nil = as

full_name: List.«instLawfulIdentityHAppendNil_.lake»
code: instance : Std.LawfulIdentity (α := List α) (· ++ ·) [] 
goal: Std.LawfulIdentity (fun x x_1 => x ++ x_1) List.nil

full_name: List.length_append
code: @[simp] theorem length_append (as bs : List α) : (as ++ bs).length = as.length + bs.length 
goal: (as ++ bs).length = as.length + bs.length

full_name: List.append_assoc
code: @[simp] theorem append_assoc (as bs cs : List α) : (as ++ bs) ++ cs = as ++ (bs ++ cs) 
goal: as ++ bs ++ cs = as ++ (bs ++ cs)

full_name: List.«instAssociativeHAppend_.lake»
code: instance : Std.Associative (α := List α) (· ++ ·) 
goal: Std.Associative fun x x_1 => x ++ x_1

full_name: List.append_cons
code: theorem append_cons (as : List α) (b : α) (bs : List α) : as ++ b :: bs = as ++ [b] ++ bs 
goal: as ++ b :: bs = as ++ b :: List.nil ++ bs

full_name: List.concat_eq_append
code: @[simp] theorem concat_eq_append (as : List α) (a : α) : as.concat a = as ++ [a] 
goal: as.concat a = as ++ a :: List.nil

full_name: List.reverseAux_eq_append
code: theorem reverseAux_eq_append (as bs : List α) : reverseAux as bs = reverseAux as [] ++ bs 
goal: as.reverseAux bs = as.reverseAux List.nil ++ bs

full_name: List.reverse_cons
code: @[simp] theorem reverse_cons (a : α) (as : List α) : reverse (a :: as) = reverse as ++ [a] 
goal: (a :: as).reverse = as.reverse ++ a :: List.nil

full_name: List.join
code: /--
`O(|join L|)`. `join L` concatenates all the lists in `L` into one list.
* `join [[a], [], [b, c], [d, e, f]] = [a, b, c, d, e, f]`
-/
def join : List (List α) → List α
  
goal: List (List α) → List α

full_name: List.join_nil
code: @[simp] theorem join_nil : List.join ([] : List (List α)) = [] 
goal: List.nil.join = List.nil

full_name: List.join_cons
code: @[simp] theorem join_cons : (l :: ls).join = l ++ ls.join 
goal: ∀ {α : Type u_1} {l : List α} {ls : List (List α)}, (l :: ls).join = l ++ ls.join

full_name: List.pure
code: /-- `pure x = [x]` is the `pure` operation of the list monad. -/
@[inline] protected def pure {α : Type u} (a : α) : List α 
goal: List α

full_name: List.bind
code: /--
`bind xs f` is the bind operation of the list monad. It applies `f` to each element of `xs`
to get a list of lists, and then concatenates them all together.
* `[2, 3, 2].bind range = [0, 1, 0, 1, 2, 0, 1]`
-/
@[inline] protected def bind {α : Type u} {β : Type v} (a : List α) (b : α → List β) : List β 
goal: List β

full_name: List.bind_nil
code: @[simp] theorem bind_nil (f : α → List β) : List.bind [] f = [] 
goal: List.nil.bind f = List.nil

full_name: List.bind_cons
code: @[simp] theorem bind_cons x xs (f : α → List β) :
  List.bind (x :: xs) f = f x ++ List.bind xs f 
goal: (x :: xs).bind f = f x ++ xs.bind f

full_name: List.nil_bind
code: @[deprecated bind_nil (since := "2024-06-15")] abbrev nil_bind 
goal: List.nil.bind f = List.nil

full_name: List.cons_bind
code: @[deprecated bind_cons (since := "2024-06-15")] abbrev cons_bind 
goal: (x :: xs).bind f = f x ++ xs.bind f

full_name: List.replicate
code: /--
`replicate n a` is `n` copies of `a`:
* `replicate 5 a = [a, a, a, a, a]`
-/
def replicate : (n : Nat) → (a : α) → List α
  
goal: List α

full_name: List.replicate_zero
code: @[simp] theorem replicate_zero : replicate 0 a = [] 
goal: ∀ {α : Type u_1} {a : α}, List.replicate 0 a = List.nil

full_name: List.replicate_succ
code: theorem replicate_succ (a : α) (n) : replicate (n+1) a = a :: replicate n a 
goal: List.replicate (n + 1) a = a :: List.replicate n a

full_name: List.length_replicate
code: @[simp] theorem length_replicate (n : Nat) (a : α) : (replicate n a).length = n 
goal: (List.replicate n a).length = n

full_name: List.«instEmptyCollection_.lake»
code: instance : EmptyCollection (List α) 
goal: EmptyCollection (List α)

full_name: List.empty_eq
code: @[simp] theorem empty_eq : (∅ : List α) = [] 
goal: ∅ = List.nil

full_name: List.isEmpty
code: /--
`O(1)`. `isEmpty l` is true if the list is empty.
* `isEmpty [] = true`
* `isEmpty [a] = false`
* `isEmpty [a, b] = false`
-/
def isEmpty : List α → Bool
  
goal: List α → Bool

full_name: List.isEmpty_nil
code: @[simp] theorem isEmpty_nil : ([] : List α).isEmpty = true 
goal: List.nil.isEmpty = true

full_name: List.isEmpty_cons
code: @[simp] theorem isEmpty_cons : (x :: xs : List α).isEmpty = false 
goal: (x :: xs).isEmpty = false

full_name: List.elem
code: /--
`O(|l|)`. `elem a l` or `l.contains a` is true if there is an element in `l` equal to `a`.

* `elem 3 [1, 4, 2, 3, 3, 7] = true`
* `elem 5 [1, 4, 2, 3, 3, 7] = false`
-/
def elem [BEq α] (a : α) : List α → Bool
  
goal: List α → Bool

full_name: List.elem_nil
code: @[simp] theorem elem_nil [BEq α] : ([] : List α).elem a = false 
goal: List.elem a List.nil = false

full_name: List.elem_cons
code: theorem elem_cons [BEq α] {a : α} :
    (b::bs).elem a = match a == b with | true => true | false => bs.elem a 
goal: List.elem a (b :: bs) =
  match a == b with
  | true => true
  | false => List.elem a bs

full_name: List.notElem
code: /-- `notElem a l` is `!(elem a l)`. -/
@[deprecated (since := "2024-06-15")]
def notElem [BEq α] (a : α) (as : List α) : Bool 
goal: Bool

full_name: List.contains
code: @[inherit_doc elem] abbrev contains [BEq α] (as : List α) (a : α) : Bool 
goal: Bool

full_name: List.contains_nil
code: @[simp] theorem contains_nil [BEq α] : ([] : List α).contains a = false 
goal: List.nil.contains a = false

full_name: List.Mem
code: /--
`a ∈ l` is a predicate which asserts that `a` is in the list `l`.
Unlike `elem`, this uses `=` instead of `==` and is suited for mathematical reasoning.
* `a ∈ [x, y, z] ↔ a = x ∨ a = y ∨ a = z`
-/
inductive Mem (a : α) : List α → Prop
  /-- The head of a list is a member: `a ∈ a :: as`. -/
  | head (as : List α) : Mem a (a::as)
  /-- A member of the tail of a list is a member of the list: `a ∈ l → a ∈ b :: l`. -/
  | tail (b : α) {as : List α} : Mem a as → Mem a (b::as)
goal: List α → Prop

full_name: List.Mem.tail
code: /--
`a ∈ l` is a predicate which asserts that `a` is in the list `l`.
Unlike `elem`, this uses `=` instead of `==` and is suited for mathematical reasoning.
* `a ∈ [x, y, z] ↔ a = x ∨ a = y ∨ a = z`
-/
inductive Mem (a : α) : List α → Prop
  /-- The head of a list is a member: `a ∈ a :: as`. -/
  | head (as : List α) : Mem a (a::as)
  /-- A member of the tail of a list is a member of the list: `a ∈ l → a ∈ b :: l`. -/
  | tail (b : α) {as : List α} : Mem a as → Mem a (b::as)
goal: List.Mem a as → List.Mem a (b :: as)

full_name: List.Mem.head
code: /--
`a ∈ l` is a predicate which asserts that `a` is in the list `l`.
Unlike `elem`, this uses `=` instead of `==` and is suited for mathematical reasoning.
* `a ∈ [x, y, z] ↔ a = x ∨ a = y ∨ a = z`
-/
inductive Mem (a : α) : List α → Prop
  /-- The head of a list is a member: `a ∈ a :: as`. -/
  | head (as : List α) : Mem a (a::as)
  /-- A member of the tail of a list is a member of the list: `a ∈ l → a ∈ b :: l`. -/
  | tail (b : α) {as : List α} : Mem a as → Mem a (b::as)
goal: List.Mem a (a :: as)

full_name: List.«instMembership_.lake»
code: instance : Membership α (List α) 
goal: Membership α (List α)

full_name: List.mem_of_elem_eq_true
code: theorem mem_of_elem_eq_true [BEq α] [LawfulBEq α] {a : α} {as : List α} : elem a as = true → a ∈ as 
goal: List.elem a as = true → a ∈ as

full_name: List.elem_eq_true_of_mem
code: theorem elem_eq_true_of_mem [BEq α] [LawfulBEq α] {a : α} {as : List α} (h : a ∈ as) : elem a as = true 
goal: List.elem a as = true

full_name: List.«instDecidableMemOfLawfulBEq_.lake»
code: instance [BEq α] [LawfulBEq α] (a : α) (as : List α) : Decidable (a ∈ as) 
goal: Decidable (a ∈ as)

full_name: List.mem_append_of_mem_left
code: theorem mem_append_of_mem_left {a : α} {as : List α} (bs : List α) : a ∈ as → a ∈ as ++ bs 
goal: a ∈ as → a ∈ as ++ bs

full_name: List.mem_append_of_mem_right
code: theorem mem_append_of_mem_right {b : α} {bs : List α} (as : List α) : b ∈ bs → b ∈ as ++ bs 
goal: b ∈ bs → b ∈ as ++ bs

full_name: List.decidableBEx
code: instance decidableBEx (p : α → Prop) [DecidablePred p] :
    ∀ l : List α, Decidable (Exists fun x => x ∈ l ∧ p x)
  
goal: Decidable (Exists fun x => x ∈ l ∧ p x)

full_name: List.decidableBAll
code: instance decidableBAll (p : α → Prop) [DecidablePred p] :
    ∀ l : List α, Decidable (∀ x, x ∈ l → p x)
  
goal: Decidable (∀ (x : α), x ∈ l → p x)

full_name: List.take
code: /--
`O(min n |xs|)`. Returns the first `n` elements of `xs`, or the whole list if `n` is too large.
* `take 0 [a, b, c, d, e] = []`
* `take 3 [a, b, c, d, e] = [a, b, c]`
* `take 6 [a, b, c, d, e] = [a, b, c, d, e]`
-/
def take : Nat → List α → List α
  
goal: Nat → List α → List α

full_name: List.take_nil
code: @[simp] theorem take_nil : ([] : List α).take i = [] 
goal: List.take i List.nil = List.nil

full_name: List.take_zero
code: @[simp] theorem take_zero (l : List α) : l.take 0 = [] 
goal: List.take 0 l = List.nil

full_name: List.take_cons_succ
code: @[simp] theorem take_cons_succ : (a::as).take (i+1) = a :: as.take i 
goal: ∀ {α : Type u_1} {a : α} {as : List α} {i : Nat}, List.take (i + 1) (a :: as) = a :: List.take i as

full_name: List.drop
code: /--
`O(min n |xs|)`. Removes the first `n` elements of `xs`.
* `drop 0 [a, b, c, d, e] = [a, b, c, d, e]`
* `drop 3 [a, b, c, d, e] = [d, e]`
* `drop 6 [a, b, c, d, e] = []`
-/
def drop : Nat → List α → List α
  
goal: Nat → List α → List α

full_name: List.drop_nil
code: @[simp] theorem drop_nil : ([] : List α).drop i = [] 
goal: List.drop i List.nil = List.nil

full_name: List.drop_zero
code: @[simp] theorem drop_zero (l : List α) : l.drop 0 = l 
goal: List.drop 0 l = l

full_name: List.drop_succ_cons
code: @[simp] theorem drop_succ_cons : (a :: l).drop (n + 1) = l.drop n 
goal: ∀ {α : Type u_1} {a : α} {l : List α} {n : Nat}, List.drop (n + 1) (a :: l) = List.drop n l

full_name: List.drop_eq_nil_of_le
code: theorem drop_eq_nil_of_le {as : List α} {i : Nat} (h : as.length ≤ i) : as.drop i = [] 
goal: List.drop i as = List.nil

full_name: List.takeWhile
code: /--
`O(|xs|)`. Returns the longest initial segment of `xs` for which `p` returns true.
* `takeWhile (· > 5) [7, 6, 4, 8] = [7, 6]`
* `takeWhile (· > 5) [7, 6, 6, 8] = [7, 6, 6, 8]`
-/
def takeWhile (p : α → Bool) : (xs : List α) → List α
  
goal: List α

full_name: List.takeWhile_nil
code: @[simp] theorem takeWhile_nil : ([] : List α).takeWhile p = [] 
goal: List.takeWhile p List.nil = List.nil

full_name: List.dropWhile
code: /--
`O(|l|)`. `dropWhile p l` removes elements from the list until it finds the first element
for which `p` returns false; this element and everything after it is returned.
```
dropWhile (· < 4) [1, 3, 2, 4, 2, 7, 4] = [4, 2, 7, 4]
```
-/
def dropWhile (p : α → Bool) : List α → List α
  
goal: List α → List α

full_name: List.dropWhile_nil
code: @[simp] theorem dropWhile_nil : ([] : List α).dropWhile p = [] 
goal: List.dropWhile p List.nil = List.nil

full_name: List.partition
code: /--
`O(|l|)`. `partition p l` calls `p` on each element of `l`, partitioning the list into two lists
`(l_true, l_false)` where `l_true` has the elements where `p` was true
and `l_false` has the elements where `p` is false.
`partition p l = (filter p l, filter (not ∘ p) l)`, but it is slightly more efficient
since it only has to do one pass over the list.
```
partition (· > 2) [1, 2, 5, 2, 7, 7] = ([5, 7, 7], [1, 2, 2])
```
-/
@[inline] def partition (p : α → Bool) (as : List α) : List α × List α 
goal: List α × List α

full_name: List.partition.loop
code: /--
`O(|l|)`. `partition p l` calls `p` on each element of `l`, partitioning the list into two lists
`(l_true, l_false)` where `l_true` has the elements where `p` was true
and `l_false` has the elements where `p` is false.
`partition p l = (filter p l, filter (not ∘ p) l)`, but it is slightly more efficient
since it only has to do one pass over the list.
```
partition (· > 2) [1, 2, 5, 2, 7, 7] = ([5, 7, 7], [1, 2, 2])
```
-/
@[inline] def partition (p : α → Bool) (as : List α) : List α × List α 
goal: List α → List α × List α → List α × List α

full_name: List.dropLast
code: /--
Removes the last element of the list.
* `dropLast [] = []`
* `dropLast [a] = []`
* `dropLast [a, b, c] = [a, b]`
-/
def dropLast {α} : List α → List α
  
goal: List α → List α

full_name: List.dropLast_nil
code: @[simp] theorem dropLast_nil : ([] : List α).dropLast = [] 
goal: List.nil.dropLast = List.nil

full_name: List.dropLast_single
code: @[simp] theorem dropLast_single : [x].dropLast = [] 
goal: ∀ {α : Type u_1} {x : α}, (x :: List.nil).dropLast = List.nil

full_name: List.dropLast_cons₂
code: @[simp] theorem dropLast_cons₂ :
    (x::y::zs).dropLast = x :: (y::zs).dropLast 
goal: ∀ {α : Type u_1} {x y : α} {zs : List α}, (x :: y :: zs).dropLast = x :: (y :: zs).dropLast

full_name: List.length_dropLast_cons
code: @[simp] theorem length_dropLast_cons (a : α) (as : List α) : (a :: as).dropLast.length = as.length 
goal: (a :: as).dropLast.length = as.length

full_name: List.isPrefixOf
code: /--  `isPrefixOf l₁ l₂` returns `true` Iff `l₁` is a prefix of `l₂`.
That is, there exists a `t` such that `l₂ == l₁ ++ t`. -/
def isPrefixOf [BEq α] : List α → List α → Bool
  
goal: List α → List α → Bool

full_name: List.isPrefixOf_nil_left
code: @[simp] theorem isPrefixOf_nil_left [BEq α] : isPrefixOf ([] : List α) l = true 
goal: List.nil.isPrefixOf l = true

full_name: List.isPrefixOf_cons_nil
code: @[simp] theorem isPrefixOf_cons_nil [BEq α] : isPrefixOf (a::as) ([] : List α) = false 
goal: (a :: as).isPrefixOf List.nil = false

full_name: List.isPrefixOf_cons₂
code: theorem isPrefixOf_cons₂ [BEq α] {a : α} :
    isPrefixOf (a::as) (b::bs) = (a == b && isPrefixOf as bs) 
goal: (a :: as).isPrefixOf (b :: bs) = (a == b && as.isPrefixOf bs)

full_name: List.isPrefixOf?
code: /-- `isPrefixOf? l₁ l₂` returns `some t` when `l₂ == l₁ ++ t`. -/
def isPrefixOf? [BEq α] : List α → List α → Option (List α)
  
goal: List α → List α → Option (List α)

full_name: List.isSuffixOf
code: /--  `isSuffixOf l₁ l₂` returns `true` Iff `l₁` is a suffix of `l₂`.
That is, there exists a `t` such that `l₂ == t ++ l₁`. -/
def isSuffixOf [BEq α] (l₁ l₂ : List α) : Bool 
goal: Bool

full_name: List.isSuffixOf_nil_left
code: @[simp] theorem isSuffixOf_nil_left [BEq α] : isSuffixOf ([] : List α) l = true 
goal: List.nil.isSuffixOf l = true

full_name: List.isSuffixOf?
code: /-- `isSuffixOf? l₁ l₂` returns `some t` when `l₂ == t ++ l₁`.-/
def isSuffixOf? [BEq α] (l₁ l₂ : List α) : Option (List α) 
goal: Option (List α)

full_name: List.rotateLeft
code: /--
`O(n)`. Rotates the elements of `xs` to the left such that the element at
`xs[i]` rotates to `xs[(i - n) % l.length]`.
* `rotateLeft [1, 2, 3, 4, 5] 3 = [4, 5, 1, 2, 3]`
* `rotateLeft [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
* `rotateLeft [1, 2, 3, 4, 5] = [2, 3, 4, 5, 1]`
-/
def rotateLeft (xs : List α) (n : Nat := 1) : List α 
goal: List α

full_name: List.rotateLeft_nil
code: @[simp] theorem rotateLeft_nil : ([] : List α).rotateLeft n = [] 
goal: List.nil.rotateLeft n = List.nil

full_name: List.rotateRight
code: /--
`O(n)`. Rotates the elements of `xs` to the right such that the element at
`xs[i]` rotates to `xs[(i + n) % l.length]`.
* `rotateRight [1, 2, 3, 4, 5] 3 = [3, 4, 5, 1, 2]`
* `rotateRight [1, 2, 3, 4, 5] 5 = [1, 2, 3, 4, 5]`
* `rotateRight [1, 2, 3, 4, 5] = [5, 1, 2, 3, 4]`
-/
def rotateRight (xs : List α) (n : Nat := 1) : List α 
goal: List α

full_name: List.rotateRight_nil
code: @[simp] theorem rotateRight_nil : ([] : List α).rotateRight n = [] 
goal: List.nil.rotateRight n = List.nil

full_name: List.replace
code: /--
`O(|l|)`. `replace l a b` replaces the first element in the list equal to `a` with `b`.

* `replace [1, 4, 2, 3, 3, 7] 3 6 = [1, 4, 2, 6, 3, 7]`
* `replace [1, 4, 2, 3, 3, 7] 5 6 = [1, 4, 2, 3, 3, 7]`
-/
def replace [BEq α] : List α → α → α → List α
  
goal: List α → α → α → List α

full_name: List.replace_nil
code: @[simp] theorem replace_nil [BEq α] : ([] : List α).replace a b = [] 
goal: List.nil.replace a b = List.nil

full_name: List.replace_cons
code: theorem replace_cons [BEq α] {a : α} :
    (a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c 
goal: (a :: as).replace b c =
  match b == a with
  | true => c :: as
  | false => a :: as.replace b c

full_name: List.insert
code: /-- Inserts an element into a list without duplication. -/
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α 
goal: List α

full_name: List.erase
code: /--
`O(|l|)`. `erase l a` removes the first occurrence of `a` from `l`.
* `erase [1, 5, 3, 2, 5] 5 = [1, 3, 2, 5]`
* `erase [1, 5, 3, 2, 5] 6 = [1, 5, 3, 2, 5]`
-/
protected def erase {α} [BEq α] : List α → α → List α
  
goal: List α → α → List α

full_name: List.erase_nil
code: @[simp] theorem erase_nil [BEq α] (a : α) : [].erase a = [] 
goal: List.nil.erase a = List.nil

full_name: List.erase_cons
code: theorem erase_cons [BEq α] (a b : α) (l : List α) :
    (b :: l).erase a = if b == a then l else b :: l.erase a 
goal: (b :: l).erase a = ite ((b == a) = true) l (b :: l.erase a)

full_name: List.eraseIdx
code: /--
`O(i)`. `eraseIdx l i` removes the `i`'th element of the list `l`.
* `erase [a, b, c, d, e] 0 = [b, c, d, e]`
* `erase [a, b, c, d, e] 1 = [a, c, d, e]`
* `erase [a, b, c, d, e] 5 = [a, b, c, d, e]`
-/
def eraseIdx : List α → Nat → List α
  
goal: List α → Nat → List α

full_name: List.eraseIdx_nil
code: @[simp] theorem eraseIdx_nil : ([] : List α).eraseIdx i = [] 
goal: List.nil.eraseIdx i = List.nil

full_name: List.eraseIdx_cons_zero
code: @[simp] theorem eraseIdx_cons_zero : (a::as).eraseIdx 0 = as 
goal: ∀ {α : Type u_1} {a : α} {as : List α}, (a :: as).eraseIdx 0 = as

full_name: List.eraseIdx_cons_succ
code: @[simp] theorem eraseIdx_cons_succ : (a::as).eraseIdx (i+1) = a :: as.eraseIdx i 
goal: ∀ {α : Type u_1} {a : α} {as : List α} {i : Nat}, (a :: as).eraseIdx (i + 1) = a :: as.eraseIdx i

full_name: List.find?
code: /--
`O(|l|)`. `find? p l` returns the first element for which `p` returns true,
or `none` if no such element is found.

* `find? (· < 5) [7, 6, 5, 8, 1, 2, 6] = some 1`
* `find? (· < 1) [7, 6, 5, 8, 1, 2, 6] = none`
-/
def find? (p : α → Bool) : List α → Option α
  
goal: List α → Option α

full_name: List.find?_nil
code: @[simp] theorem find?_nil : ([] : List α).find? p = none 
goal: List.find? p List.nil = none

full_name: List.find?_cons
code: theorem find?_cons : (a::as).find? p = match p a with | true => some a | false => as.find? p 
goal: ∀ {α : Type u_1} {a : α} {as : List α} {p : α → Bool},
  List.find? p (a :: as) =
    match p a with
    | true => some a
    | false => List.find? p as

full_name: List.findSome?
code: /--
`O(|l|)`. `findSome? f l` applies `f` to each element of `l`, and returns the first non-`none` result.

* `findSome? (fun x => if x < 5 then some (10 * x) else none) [7, 6, 5, 8, 1, 2, 6] = some 10`
-/
def findSome? (f : α → Option β) : List α → Option β
  
goal: List α → Option β

full_name: List.findSome?_nil
code: @[simp] theorem findSome?_nil : ([] : List α).findSome? f = none 
goal: ∀ {α_1 : Type u_1} {f : α → Option α_1}, List.findSome? f List.nil = none

full_name: List.findSome?_cons
code: theorem findSome?_cons {f : α → Option β} :
    (a::as).findSome? f = match f a with | some b => some b | none => as.findSome? f 
goal: List.findSome? f (a :: as) =
  match f a with
  | some b => some b
  | none => List.findSome? f as

full_name: List.lookup
code: /--
`O(|l|)`. `lookup a l` treats `l : List (α × β)` like an association list,
and returns the first `β` value corresponding to an `α` value in the list equal to `a`.

* `lookup 3 [(1, 2), (3, 4), (3, 5)] = some 4`
* `lookup 2 [(1, 2), (3, 4), (3, 5)] = none`
-/
def lookup [BEq α] : α → List (α × β) → Option β
  
goal: α → List (α × β) → Option β

full_name: List.lookup_nil
code: @[simp] theorem lookup_nil [BEq α] : ([] : List (α × β)).lookup a = none 
goal: List.lookup a List.nil = none

full_name: List.lookup_cons
code: theorem lookup_cons [BEq α] {k : α} :
    ((k,b)::es).lookup a = match a == k with | true => some b | false => es.lookup a 
goal: ∀ {β : Type u_1} {b : β} {es : List (α × β)} {a : α} [inst : BEq α] {k : α},
  List.lookup a ({ fst := k, snd := b } :: es) =
    match a == k with
    | true => some b
    | false => List.lookup a es

full_name: List.any
code: /--
`O(|l|)`. Returns true if `p` is true for any element of `l`.
* `any p [a, b, c] = p a || p b || p c`

Short-circuits upon encountering the first `true`.
-/
def any : List α → (α → Bool) → Bool
  
goal: List α → (α → Bool) → Bool

full_name: List.any_nil
code: @[simp] theorem any_nil : [].any f = false 
goal: ∀ {α : Type u_1} {f : α → Bool}, List.nil.any f = false

full_name: List.any_cons
code: @[simp] theorem any_cons : (a::l).any f = (f a || l.any f) 
goal: ∀ {α : Type u_1} {a : α} {l : List α} {f : α → Bool}, (a :: l).any f = (f a || l.any f)

full_name: List.all
code: /--
`O(|l|)`. Returns true if `p` is true for every element of `l`.
* `all p [a, b, c] = p a && p b && p c`

Short-circuits upon encountering the first `false`.
-/
def all : List α → (α → Bool) → Bool
  
goal: List α → (α → Bool) → Bool

full_name: List.all_nil
code: @[simp] theorem all_nil : [].all f = true 
goal: ∀ {α : Type u_1} {f : α → Bool}, List.nil.all f = true

full_name: List.all_cons
code: @[simp] theorem all_cons : (a::l).all f = (f a && l.all f) 
goal: ∀ {α : Type u_1} {a : α} {l : List α} {f : α → Bool}, (a :: l).all f = (f a && l.all f)

full_name: List.or
code: /--
`O(|l|)`. Returns true if `true` is an element of the list of booleans `l`.
* `or [a, b, c] = a || b || c`
-/
def or (bs : List Bool) : Bool 
goal: Bool

full_name: List.or_nil
code: @[simp] theorem or_nil : [].or = false 
goal: List.nil.or = false

full_name: List.or_cons
code: @[simp] theorem or_cons : (a::l).or = (a || l.or) 
goal: (a :: l).or = (a || l.or)

full_name: List.and
code: /--
`O(|l|)`. Returns true if every element of `l` is the value `true`.
* `and [a, b, c] = a && b && c`
-/
def and (bs : List Bool) : Bool 
goal: Bool

full_name: List.and_nil
code: @[simp] theorem and_nil : [].and = true 
goal: List.nil.and = true

full_name: List.and_cons
code: @[simp] theorem and_cons : (a::l).and = (a && l.and) 
goal: (a :: l).and = (a && l.and)

full_name: List.zipWith
code: /--
`O(min |xs| |ys|)`. Applies `f` to the two lists in parallel, stopping at the shorter list.
* `zipWith f [x₁, x₂, x₃] [y₁, y₂, y₃, y₄] = [f x₁ y₁, f x₂ y₂, f x₃ y₃]`
-/
@[specialize] def zipWith (f : α → β → γ) : (xs : List α) → (ys : List β) → List γ
  
goal: List γ

full_name: List.zipWith_nil_left
code: @[simp] theorem zipWith_nil_left {f : α → β → γ} : zipWith f [] l = [] 
goal: List.zipWith f List.nil l = List.nil

full_name: List.zipWith_nil_right
code: @[simp] theorem zipWith_nil_right {f : α → β → γ} : zipWith f l [] = [] 
goal: List.zipWith f l List.nil = List.nil

full_name: List.zipWith_cons_cons
code: @[simp] theorem zipWith_cons_cons {f : α → β → γ} :
    zipWith f (a :: as) (b :: bs) = f a b :: zipWith f as bs 
goal: List.zipWith f (a :: as) (b :: bs) = f a b :: List.zipWith f as bs

full_name: List.zip
code: /--
`O(min |xs| |ys|)`. Combines the two lists into a list of pairs, with one element from each list.
The longer list is truncated to match the shorter list.
* `zip [x₁, x₂, x₃] [y₁, y₂, y₃, y₄] = [(x₁, y₁), (x₂, y₂), (x₃, y₃)]`
-/
def zip : List α → List β → List (Prod α β) 
goal: List α → List β → List (α × β)

full_name: List.zip_nil_left
code: @[simp] theorem zip_nil_left : zip ([] : List α) (l : List β)  = [] 
goal: List.nil.zip l = List.nil

full_name: List.zip_nil_right
code: @[simp] theorem zip_nil_right : zip (l : List α) ([] : List β)  = [] 
goal: l.zip List.nil = List.nil

full_name: List.zip_cons_cons
code: @[simp] theorem zip_cons_cons : zip (a :: as) (b :: bs) = (a, b) :: zip as bs 
goal: ∀ {α : Type u_1} {a : α} {as : List α} {α_1 : Type u_2} {b : α_1} {bs : List α_1},
  (a :: as).zip (b :: bs) = { fst := a, snd := b } :: as.zip bs

full_name: List.zipWithAll
code: /--
`O(max |xs| |ys|)`.
Version of `List.zipWith` that continues to the end of both lists,
passing `none` to one argument once the shorter list has run out.
-/
def zipWithAll (f : Option α → Option β → γ) : List α → List β → List γ
  
goal: List α → List β → List γ

full_name: List.zipWithAll_nil_right
code: @[simp] theorem zipWithAll_nil_right :
    zipWithAll f as [] = as.map fun a => f (some a) none 
goal: ∀ {α : Type u_1} {α_1 : Type u_2} {α_2 : Type u_3} {f : Option α → Option α_1 → α_2} {as : List α},
  List.zipWithAll f as List.nil = List.map (fun a => f (some a) none) as

full_name: List.zipWithAll_nil_left
code: @[simp] theorem zipWithAll_nil_left :
    zipWithAll f [] bs = bs.map fun b => f none (some b) 
goal: ∀ {α : Type u_1} {α_1 : Type u_2} {α_2 : Type u_3} {f : Option α → Option α_1 → α_2} {bs : List α_1},
  List.zipWithAll f List.nil bs = List.map (fun b => f none (some b)) bs

full_name: List.zipWithAll_cons_cons
code: @[simp] theorem zipWithAll_cons_cons :
    zipWithAll f (a :: as) (b :: bs) = f (some a) (some b) :: zipWithAll f as bs 
goal: ∀ {α : Type u_1} {α_1 : Type u_2} {α_2 : Type u_3} {f : Option α → Option α_1 → α_2} {a : α} {as : List α} {b : α_1}
  {bs : List α_1}, List.zipWithAll f (a :: as) (b :: bs) = f (some a) (some b) :: List.zipWithAll f as bs

full_name: List.unzip
code: /--
`O(|l|)`. Separates a list of pairs into two lists containing the first components and second components.
* `unzip [(x₁, y₁), (x₂, y₂), (x₃, y₃)] = ([x₁, x₂, x₃], [y₁, y₂, y₃])`
-/
def unzip : List (α × β) → List α × List β
  
goal: List (α × β) → List α × List β

full_name: List.unzip_nil
code: @[simp] theorem unzip_nil : ([] : List (α × β)).unzip = ([], []) 
goal: List.nil.unzip = { fst := List.nil, snd := List.nil }

full_name: List.unzip_cons
code: @[simp] theorem unzip_cons {h : α × β} :
    (h :: t).unzip = match unzip t with | (al, bl) => (h.1::al, h.2::bl) 
goal: (h :: t).unzip =
  match t.unzip with
  | { fst := al, snd := bl } => { fst := h.fst :: al, snd := h.snd :: bl }

full_name: List.range
code: /--
`O(n)`. `range n` is the numbers from `0` to `n` exclusive, in increasing order.
* `range 5 = [0, 1, 2, 3, 4]`
-/
def range (n : Nat) : List Nat 
goal: List Nat

full_name: List.range.loop
code: /--
`O(n)`. `range n` is the numbers from `0` to `n` exclusive, in increasing order.
* `range 5 = [0, 1, 2, 3, 4]`
-/
def range (n : Nat) : List Nat 
goal: Nat → List Nat → List Nat

full_name: List.range_zero
code: @[simp] theorem range_zero : range 0 = [] 
goal: List.range 0 = List.nil

full_name: List.iota
code: /--
`O(n)`. `iota n` is the numbers from `1` to `n` inclusive, in decreasing order.
* `iota 5 = [5, 4, 3, 2, 1]`
-/
def iota : Nat → List Nat
  
goal: Nat → List Nat

full_name: List.iota_zero
code: @[simp] theorem iota_zero : iota 0 = [] 
goal: List.iota 0 = List.nil

full_name: List.iota_succ
code: @[simp] theorem iota_succ : iota (i+1) = (i+1) :: iota i 
goal: List.iota (i + 1) = (i + 1) :: List.iota i

full_name: List.enumFrom
code: /--
`O(|l|)`. `enumFrom n l` is like `enum` but it allows you to specify the initial index.
* `enumFrom 5 [a, b, c] = [(5, a), (6, b), (7, c)]`
-/
def enumFrom : Nat → List α → List (Nat × α)
  
goal: Nat → List α → List (Nat × α)

full_name: List.enumFrom_nil
code: @[simp] theorem enumFrom_nil : ([] : List α).enumFrom i = [] 
goal: List.enumFrom i List.nil = List.nil

full_name: List.enumFrom_cons
code: @[simp] theorem enumFrom_cons : (a::as).enumFrom i = (i, a) :: as.enumFrom (i+1) 
goal: ∀ {α : Type u_1} {a : α} {as : List α} {i : Nat},
  List.enumFrom i (a :: as) = { fst := i, snd := a } :: List.enumFrom (i + 1) as

full_name: List.enum
code: /--
`O(|l|)`. `enum l` pairs up each element with its index in the list.
* `enum [a, b, c] = [(0, a), (1, b), (2, c)]`
-/
def enum : List α → List (Nat × α) 
goal: List α → List (Nat × α)

full_name: List.enum_nil
code: @[simp] theorem enum_nil : ([] : List α).enum = [] 
goal: List.nil.enum = List.nil

full_name: List.minimum?
code: /--
Returns the smallest element of the list, if it is not empty.
* `[].minimum? = none`
* `[4].minimum? = some 4`
* `[1, 4, 2, 10, 6].minimum? = some 1`
-/
def minimum? [Min α] : List α → Option α
  
goal: List α → Option α

full_name: List.maximum?
code: /--
Returns the largest element of the list, if it is not empty.
* `[].maximum? = none`
* `[4].maximum? = some 4`
* `[1, 4, 2, 10, 6].maximum? = some 10`
-/
def maximum? [Max α] : List α → Option α
  
goal: List α → Option α

full_name: List.intersperse
code: /--
`O(|l|)`. `intersperse sep l` alternates `sep` and the elements of `l`:
* `intersperse sep [] = []`
* `intersperse sep [a] = [a]`
* `intersperse sep [a, b] = [a, sep, b]`
* `intersperse sep [a, b, c] = [a, sep, b, sep, c]`
-/
def intersperse (sep : α) : List α → List α
  
goal: List α → List α

full_name: List.intersperse_nil
code: @[simp] theorem intersperse_nil (sep : α) : ([] : List α).intersperse sep = [] 
goal: List.intersperse sep List.nil = List.nil

full_name: List.intersperse_single
code: @[simp] theorem intersperse_single (sep : α) : [x].intersperse sep = [x] 
goal: List.intersperse sep (x :: List.nil) = x :: List.nil

full_name: List.intersperse_cons₂
code: @[simp] theorem intersperse_cons₂ (sep : α) :
    (x::y::zs).intersperse sep = x::sep::((y::zs).intersperse sep) 
goal: List.intersperse sep (x :: y :: zs) = x :: sep :: List.intersperse sep (y :: zs)

full_name: List.intercalate
code: /--
`O(|xs|)`. `intercalate sep xs` alternates `sep` and the elements of `xs`:
* `intercalate sep [] = []`
* `intercalate sep [a] = a`
* `intercalate sep [a, b] = a ++ sep ++ b`
* `intercalate sep [a, b, c] = a ++ sep ++ b ++ sep ++ c`
-/
def intercalate (sep : List α) (xs : List (List α)) : List α 
goal: List α

full_name: List.eraseDups
code: /-- `O(|l|^2)`. Erase duplicated elements in the list.
Keeps the first occurrence of duplicated elements.
* `eraseDups [1, 3, 2, 2, 3, 5] = [1, 3, 2, 5]`
-/
def eraseDups {α} [BEq α] (as : List α) : List α 
goal: List α

full_name: List.eraseDups.loop
code: /-- `O(|l|^2)`. Erase duplicated elements in the list.
Keeps the first occurrence of duplicated elements.
* `eraseDups [1, 3, 2, 2, 3, 5] = [1, 3, 2, 5]`
-/
def eraseDups {α} [BEq α] (as : List α) : List α 
goal: List α → List α → List α

full_name: List.eraseReps.loop
code: /--
`O(|l|)`. Erase repeated adjacent elements. Keeps the first occurrence of each run.
* `eraseReps [1, 3, 2, 2, 2, 3, 5] = [1, 3, 2, 3, 5]`
-/
def eraseReps {α} [BEq α] : List α → List α
  
goal: α → List α → List α → List α

full_name: List.eraseReps
code: /--
`O(|l|)`. Erase repeated adjacent elements. Keeps the first occurrence of each run.
* `eraseReps [1, 3, 2, 2, 2, 3, 5] = [1, 3, 2, 3, 5]`
-/
def eraseReps {α} [BEq α] : List α → List α
  
goal: List α → List α

full_name: List.span.loop
code: /--
`O(|l|)`. `span p l` splits the list `l` into two parts, where the first part
contains the longest initial segment for which `p` returns true
and the second part is everything else.

* `span (· > 5) [6, 8, 9, 5, 2, 9] = ([6, 8, 9], [5, 2, 9])`
* `span (· > 10) [6, 8, 9, 5, 2, 9] = ([], [6, 8, 9, 5, 2, 9])`
-/
@[inline] def span (p : α → Bool) (as : List α) : List α × List α 
goal: List α → List α → List α × List α

full_name: List.span
code: /--
`O(|l|)`. `span p l` splits the list `l` into two parts, where the first part
contains the longest initial segment for which `p` returns true
and the second part is everything else.

* `span (· > 5) [6, 8, 9, 5, 2, 9] = ([6, 8, 9], [5, 2, 9])`
* `span (· > 10) [6, 8, 9, 5, 2, 9] = ([], [6, 8, 9, 5, 2, 9])`
-/
@[inline] def span (p : α → Bool) (as : List α) : List α × List α 
goal: List α × List α

full_name: List.groupBy
code: /--
`O(|l|)`. `groupBy R l` splits `l` into chains of elements
such that adjacent elements are related by `R`.

* `groupBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
* `groupBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
-/
@[specialize] def groupBy (R : α → α → Bool) : List α → List (List α)
  
goal: List α → List (List α)

full_name: List.groupBy.loop
code: /--
`O(|l|)`. `groupBy R l` splits `l` into chains of elements
such that adjacent elements are related by `R`.

* `groupBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]`
* `groupBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]`
-/
@[specialize] def groupBy (R : α → α → Bool) : List α → List (List α)
  
goal: List α → α → List α → List (List α) → List (List α)

full_name: List.removeAll
code: /-- `O(|xs|)`. Computes the "set difference" of lists,
by filtering out all elements of `xs` which are also in `ys`.
* `removeAll [1, 1, 5, 1, 2, 4, 5] [1, 2, 2] = [5, 4, 5]`
 -/
def removeAll [BEq α] (xs ys : List α) : List α 
goal: List α