14.15. Linked Lists🔗

Linked lists, implemented as the inductive type List, contain an ordered sequence of elements. Unlike arrays, Lean compiles lists according to the ordinary rules for inductive types; however, some operations on lists are replaced by tail-recursive equivalents in compiled code using the csimp mechanism. Lean provides syntax for both literal lists and the constructor List.cons.

🔗inductive type
List.{u} (α : Type u) : Type u

List α is the type of ordered lists with elements of type α. It is implemented as a linked list.

List α is isomorphic to Array α, but they are useful for different things:

  • List α is easier for reasoning, and Array α is modeled as a wrapper around List α

  • List α works well as a persistent data structure, when many copies of the tail are shared. When the value is not shared, Array α will have better performance because it can do destructive updates.

Constructors

nil.{u} {α : Type u} : List α

[] is the empty list.

Conventions for notations in identifiers:

  • The recommended spelling of [] in identifiers is nil.

cons.{u} {α : Type u} (head : α) (tail : List α) : List α

If a : α and l : List α, then cons a l, or a :: l, is the list whose first element is a and with l as the rest of the list.

Conventions for notations in identifiers:

  • The recommended spelling of :: in identifiers is cons.

  • The recommended spelling of [a] in identifiers is singleton.

14.15.1. Syntax🔗

List literals are written in square brackets, with the elements of the list separated by commas. The constructor List.cons that adds an element to the front of a list is represented by the infix operator «term_::_» : termIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the list whose first element is `a` and with `l` as the rest of the list. Conventions for notations in identifiers: * The recommended spelling of `::` in identifiers is `cons`.::. The syntax for lists can be used both in ordinary terms and in patterns.

syntaxList Literals
term ::= ...
    | The syntax `[a, b, c]` is shorthand for `a :: b :: c :: []`, or
`List.cons a (List.cons b (List.cons c List.nil))`. It allows conveniently constructing
list literals.

For lists of length at least 64, an alternative desugaring strategy is used
which uses let bindings as intermediates as in
`let left := [d, e, f]; a :: b :: c :: left` to avoid creating very deep expressions.
Note that this changes the order of evaluation, although it should not be observable
unless you use side effecting operations like `dbg_trace`.


Conventions for notations in identifiers:

 * The recommended spelling of `[]` in identifiers is `nil`.

 * The recommended spelling of `[a]` in identifiers is `singleton`.[term,*]

The syntax [a, b, c] is shorthand for a :: b :: c :: [], or List.cons a (List.cons b (List.cons c List.nil)). It allows conveniently constructing list literals.

For lists of length at least 64, an alternative desugaring strategy is used which uses let bindings as intermediates as in let left := [d, e, f]; a :: b :: c :: left to avoid creating very deep expressions. Note that this changes the order of evaluation, although it should not be observable unless you use side effecting operations like dbg_trace.

Conventions for notations in identifiers:

  • The recommended spelling of [] in identifiers is nil.

  • The recommended spelling of [a] in identifiers is singleton.

syntaxList Construction
term ::= ...
    | If `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the
list whose first element is `a` and with `l` as the rest of the list. 

Conventions for notations in identifiers:

 * The recommended spelling of `::` in identifiers is `cons`.term :: term

If a : α and l : List α, then cons a l, or a :: l, is the list whose first element is a and with l as the rest of the list.

Conventions for notations in identifiers:

  • The recommended spelling of :: in identifiers is cons.

Constructing Lists

All of these examples are equivalent:

example : List Nat := [1, 2, 3] example : List Nat := 1 :: [2, 3] example : List Nat := 1 :: 2 :: [3] example : List Nat := 1 :: 2 :: 3 :: [] example : List Nat := 1 :: 2 :: 3 :: .nil example : List Nat := 1 :: 2 :: .cons 3 .nil example : List Nat := .cons 1 (.cons 2 (.cons 3 .nil))
Pattern Matching and Lists

All of these functions are equivalent:

def split : List α List α × List α | [] => ([], []) | [x] => ([x], []) | x :: x' :: xs => let (ys, zs) := split xs (x :: ys, x' :: zs) def split' : List α List α × List α | .nil => (.nil, .nil) | x :: [] => (.singleton x, .nil) | x :: x' :: xs => let (ys, zs) := split xs (x :: ys, x' :: zs) def split'' : List α List α × List α | .nil => (.nil, .nil) | .cons x .nil=> (.singleton x, .nil) | .cons x (.cons x' xs) => let (ys, zs) := split xs (.cons x ys, .cons x' zs)

14.15.2. Performance Notes🔗

The representation of lists is not overridden or modified by the compiler: they are linked lists, with a pointer indirection for each element. Calculating the length of a list requires a full traversal, and modifying an element in a list requires a traversal and reallocation of the prefix of the list that is prior to the element being modified. Due to Lean's reference-counting-based memory management, operations such as List.map that traverse a list, allocating a new List.cons constructor for each in the prior list, can re-use the original list's memory when there are no other references to it.

Because of the important role played by lists in specifications, most list functions are written as straightforwardly as possible using structural recursion. This makes it easier to write proofs by induction, but it also means that these operations consume stack space proportional to the length of the list. There are tail-recursive versions of many list functions that are equivalent to the non-tail-recursive versions, but more are difficult to use when reasoning. In compiled code, the tail-recursive versions are automatically used instead of the non-tail-recursive versions.

14.15.3. API Reference🔗

14.15.3.1. Predicates and Relations

🔗def
List.IsPrefix.{u} {α : Type u}
  (l₁ l₂ : List α) : Prop

IsPrefix l₁ l₂, or l₁ <+: l₂, means that l₁ is a prefix of l₂, that is, l₂ has the form l₁ ++ t for some t.

Conventions for notations in identifiers:

  • The recommended spelling of <+: in identifiers is prefix (not isPrefix).

syntaxList Prefix
term ::= ...
    | `IsPrefix l₁ l₂`, or `l₁ <+: l₂`, means that `l₁` is a prefix of `l₂`,
that is, `l₂` has the form `l₁ ++ t` for some `t`.


Conventions for notations in identifiers:

 * The recommended spelling of `<+:` in identifiers is `prefix` (not `isPrefix`).term <+: term

IsPrefix l₁ l₂, or l₁ <+: l₂, means that l₁ is a prefix of l₂, that is, l₂ has the form l₁ ++ t for some t.

Conventions for notations in identifiers:

  • The recommended spelling of <+: in identifiers is prefix (not isPrefix).

🔗def
List.IsSuffix.{u} {α : Type u}
  (l₁ l₂ : List α) : Prop

IsSuffix l₁ l₂, or l₁ <:+ l₂, means that l₁ is a suffix of l₂, that is, l₂ has the form t ++ l₁ for some t.

Conventions for notations in identifiers:

  • The recommended spelling of <:+ in identifiers is suffix (not isSuffix).

syntaxList Suffix
term ::= ...
    | `IsSuffix l₁ l₂`, or `l₁ <:+ l₂`, means that `l₁` is a suffix of `l₂`,
that is, `l₂` has the form `t ++ l₁` for some `t`.


Conventions for notations in identifiers:

 * The recommended spelling of `<:+` in identifiers is `suffix` (not `isSuffix`).term <:+ term

IsSuffix l₁ l₂, or l₁ <:+ l₂, means that l₁ is a suffix of l₂, that is, l₂ has the form t ++ l₁ for some t.

Conventions for notations in identifiers:

  • The recommended spelling of <:+ in identifiers is suffix (not isSuffix).

🔗def
List.IsInfix.{u} {α : Type u} (l₁ l₂ : List α) :
  Prop

IsInfix l₁ l₂, or l₁ <:+: l₂, means that l₁ is a contiguous substring of l₂, that is, l₂ has the form s ++ l₁ ++ t for some s, t.

Conventions for notations in identifiers:

  • The recommended spelling of <:+: in identifiers is infix (not isInfix).

syntaxList Infix
term ::= ...
    | `IsInfix l₁ l₂`, or `l₁ <:+: l₂`, means that `l₁` is a contiguous
substring of `l₂`, that is, `l₂` has the form `s ++ l₁ ++ t` for some `s, t`.


Conventions for notations in identifiers:

 * The recommended spelling of `<:+:` in identifiers is `infix` (not `isInfix`).term <:+: term

IsInfix l₁ l₂, or l₁ <:+: l₂, means that l₁ is a contiguous substring of l₂, that is, l₂ has the form s ++ l₁ ++ t for some s, t.

Conventions for notations in identifiers:

  • The recommended spelling of <:+: in identifiers is infix (not isInfix).

🔗inductive predicate
List.Perm.{u} {α : Type u} :
  List αList αProp

Perm l₁ l₂ or l₁ ~ l₂ asserts that l₁ and l₂ are permutations of each other. This is defined by induction using pairwise swaps.

Constructors

nil.{u} {α : Type u} : [].Perm []

[] ~ []

cons.{u} {α : Type u} (x : α) {l₁ l₂ : List α} :
  l₁.Perm l₂(x :: l₁).Perm (x :: l₂)

l₁ ~ l₂ x::l₁ ~ x::l₂

swap.{u} {α : Type u} (x y : α) (l : List α) :
  (y :: x :: l).Perm (x :: y :: l)

x::y::l ~ y::x::l

trans.{u} {α : Type u} {l₁ l₂ l₃ : List α} :
  l₁.Perm l₂l₂.Perm l₃l₁.Perm l₃

Perm is transitive.

syntaxList Permutation
term ::= ...
    | `Perm l₁ l₂` or `l₁ ~ l₂` asserts that `l₁` and `l₂` are permutations
of each other. This is defined by induction using pairwise swaps.
term ~ term

Perm l₁ l₂ or l₁ ~ l₂ asserts that l₁ and l₂ are permutations of each other. This is defined by induction using pairwise swaps.

This syntax is only available when the List namespace is opened.

🔗inductive predicate
List.Pairwise.{u} {α : Type u}
  (R : ααProp) : List αProp

Pairwise R l means that all the elements with earlier indexes are R-related to all the elements with later indexes.

Pairwise R [1, 2, 3] R 1 2 R 1 3 R 2 3

For example if R = (··) then it asserts l has no duplicates, and if R = (·<·) then it asserts that l is (strictly) sorted.

Constructors

nil.{u} {α : Type u} {R : ααProp} : List.Pairwise R []

All elements of the empty list are vacuously pairwise related.

cons.{u} {α : Type u} {R : ααProp} {a : α}
  {l : List α} :
  (∀ (a' : α), a'lR a a') →
    List.Pairwise R lList.Pairwise R (a :: l)

a :: l is Pairwise R if a R-relates to every element of l, and l is Pairwise R.

🔗def
List.Nodup.{u} {α : Type u} : List αProp

Nodup l means that l has no duplicates, that is, any element appears at most once in the List. It is defined as Pairwise ().

🔗inductive predicate
List.Lex.{u} {α : Type u} (r : ααProp) :
  List αList αProp

Lexicographic ordering for lists.

Constructors

nil.{u} {α : Type u} {r : ααProp} {a : α}
  {l : List α} : List.Lex r [] (a :: l)

[] is the smallest element in the order.

cons.{u} {α : Type u} {r : ααProp} {a : α}
  {l₁ l₂ : List α} (h : List.Lex r l₁ l₂) :
  List.Lex r (a :: l₁) (a :: l₂)

If a is indistinguishable from b and as < bs, then a::as < b::bs.

rel.{u} {α : Type u} {r : ααProp} {a₁ : α}
  {l₁ : List α} {a₂ : α} {l₂ : List α} (h : r a₁ a₂) :
  List.Lex r (a₁ :: l₁) (a₂ :: l₂)

If a < b then a::as < b::bs.

🔗inductive predicate
List.Mem.{u} {α : Type u} (a : α) :
  List αProp

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

Constructors

head.{u} {α : Type u} {a : α} (as : List α) :
  List.Mem a (a :: as)

The head of a list is a member: a a :: as.

tail.{u} {α : Type u} {a : α} (b : α) {as : List α} :
  List.Mem a asList.Mem a (b :: as)

A member of the tail of a list is a member of the list: a l a b :: l.

14.15.3.2. Constructing Lists

🔗def
List.singleton.{u} {α : Type u} (a : α) : List α

singleton x = [x].

🔗def
List.concat.{u} {α : Type u} :
  List ααList α

l.concat a appends a at the end of l, that is, l ++ [a].

🔗def
List.replicate.{u} {α : Type u} (n : Nat)
  (a : α) : List α

replicate n a is n copies of a:

  • replicate 5 a = [a, a, a, a, a]

🔗def
List.replicateTR.{u} {α : Type u} (n : Nat)
  (a : α) : List α

Tail-recursive version of List.replicate.

🔗def
List.ofFn.{u_1} {α : Type u_1} {n : Nat}
  (f : Fin nα) : List α

ofFn f with f : fin n α returns the list whose ith element is f i

ofFn f = [f 0, f 1, ... , f (n - 1)]
🔗def
List.append.{u} {α : Type u} (xs ys : List α) :
  List α

O(|xs|): append two lists. [1, 2, 3] ++ [4, 5] = [1, 2, 3, 4, 5]. It takes time proportional to the first list.

🔗def
List.appendTR.{u} {α : Type u}
  (as bs : List α) : List α

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
List.range (n : Nat) : List Nat

O(n). range n is the numbers from 0 to n exclusive, in increasing order.

  • range 5 = [0, 1, 2, 3, 4]

🔗def
List.range' (start len : Nat)
  (step : Nat := 1) : List Nat

range' start len step is the list of numbers [start, start+step, ..., start+(len-1)*step]. It is intended mainly for proving properties of range and iota.

🔗def
List.range'TR (s n : Nat) (step : Nat := 1) :
  List Nat

Optimized version of range'.

🔗def
List.finRange (n : Nat) : List (Fin n)

finRange n lists all elements of Fin n in order

14.15.3.3. Length

🔗def
List.length.{u_1} {α : Type u_1} : List αNat

The length of a list: [].length = 0 and (a :: l).length = l.length + 1.

This function is overridden in the compiler to lengthTR, which uses constant stack space, while leaving this function to use the "naive" recursion which is easier for reasoning.

🔗def
List.lengthTR.{u_1} {α : Type u_1}
  (as : List α) : Nat

A tail-recursive version of List.length, used to implement List.length without running out of stack space.

🔗def
List.isEmpty.{u} {α : Type u} : List αBool

O(1). isEmpty l is true if the list is empty.

14.15.3.4. Head and Tail

🔗def
List.head.{u} {α : Type u} (as : List α) :
  as[]α

Returns the first element of a non-empty list.

🔗def
List.head?.{u} {α : Type u} : List αOption α

Returns the first element in the list.

If the list is empty, this function returns none. Also see headD and head!.

🔗def
List.headD.{u} {α : Type u} (as : List α)
  (fallback : α) : α

Returns the first element in the list.

If the list is empty, this function returns fallback. Also see head? and head!.

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

Returns the first element in the list.

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

🔗def
List.tail.{u} {α : Type u} : List αList α

Get the tail of a nonempty list, or return [] for [].

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

Drops the first element of the list.

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

🔗def
List.tail?.{u} {α : Type u} :
  List αOption (List α)

Drops the first element of the list.

If the list is empty, this function returns none. Also see tailD and tail!.

🔗def
List.tailD.{u} {α : Type u}
  (l fallback : List α) : List α

Drops the first element of the list.

If the list is empty, this function returns fallback. Also see head? and head!.

14.15.3.5. Lookups

🔗def
List.get.{u} {α : Type u} (as : List α) :
  Fin as.lengthα

as.get i returns the i'th element of the list as. This version of the function uses i : Fin as.length to ensure that it will not index out of bounds.

🔗def
List.getD.{u_1} {α : Type u_1} (as : List α)
  (i : Nat) (fallback : α) : α

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
List.getLast.{u} {α : Type u} (as : List α) :
  as[]α

Returns the last element of a non-empty list.

🔗def
List.getLast?.{u} {α : Type u} :
  List αOption α

Returns the last element in the list.

If the list is empty, this function returns none. Also see getLastD and getLast!.

🔗def
List.getLastD.{u} {α : Type u} (as : List α)
  (fallback : α) : α

Returns the last element in the list.

If the list is empty, this function returns fallback. Also see getLast? and getLast!.

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

Returns the last element in the list.

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

🔗def
List.lookup.{u, v} {α : Type u} {β : Type v}
  [BEq α] : αList (α × β)Option β

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
List.max?.{u} {α : Type u} [Max α] :
  List αOption α

Returns the largest element of the list, if it is not empty.

🔗def
List.maxNatAbs (xs : List Int) : Nat

The maximum absolute value in a list of integers.

🔗def
List.min?.{u} {α : Type u} [Min α] :
  List αOption α

Returns the smallest element of the list, if it is not empty.

🔗def
List.minNatAbs (xs : List Int) : Nat

The minimum absolute value of a nonzero entry, or zero if all entries are zero.

We completely characterize the function via minNatAbs_eq_zero_iff and minNatAbs_eq_nonzero_iff below.

🔗def
List.nonzeroMinimum (xs : List Nat) : Nat

The minimum non-zero entry in a list of natural numbers, or zero if all entries are zero.

We completely characterize the function via nonzeroMinimum_eq_zero_iff and nonzeroMinimum_eq_nonzero_iff below.

14.15.3.5.1. Queries

🔗def
List.count.{u} {α : Type u} [BEq α] (a : α) :
  List αNat

count a l is the number of occurrences of a in l.

🔗def
List.countP.{u} {α : Type u} (p : αBool)
  (l : List α) : Nat

countP p l is the number of elements of l that satisfy p.

🔗def
List.idxOf.{u} {α : Type u} [BEq α] (a : α) :
  List αNat

Returns the index of the first element equal to a, or the length of the list otherwise.

🔗def
List.idxOf?.{u} {α : Type u} [BEq α] (a : α) :
  List αOption Nat

Return the index of the first occurrence of a in the list.

🔗def
List.finIdxOf?.{u} {α : Type u} [BEq α] (a : α)
  (l : List α) : Option (Fin l.length)

Return the index of the first occurrence of a, as a Fin l.length, or none if no such element is found.

🔗def
List.find?.{u} {α : Type u} (p : αBool) :
  List αOption α

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
List.findFinIdx?.{u} {α : Type u} (p : αBool)
  (l : List α) : Option (Fin l.length)

Return the index of the first occurrence of an element satisfying p, as a Fin l.length, or none if no such element is found.

🔗def
List.findIdx.{u} {α : Type u} (p : αBool)
  (l : List α) : Nat

Returns the index of the first element satisfying p, or the length of the list otherwise.

🔗def
List.findIdx?.{u} {α : Type u} (p : αBool)
  (l : List α) : Option Nat

Return the index of the first occurrence of an element satisfying p.

🔗def
List.findM?.{u} {m : TypeType u} [Monad m]
  {α : Type} (p : αm Bool) :
  List αm (Option α)
🔗def
List.findSome?.{u, v} {α : Type u} {β : Type v}
  (f : αOption β) : List αOption β

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
List.findSomeM?.{u, v, w} {m : Type uType v}
  [Monad m] {α : Type w} {β : Type u}
  (f : αm (Option β)) : List αm (Option β)

14.15.3.6. Conversions

🔗def
List.asString (s : List Char) : String
🔗def
List.toArray.{u_1} {α : Type u_1}
  (xs : List α) : Array α

Converts a List α into an Array α. (This is preferred over the synonym Array.mk.)

At runtime, this constructor is implemented by List.toArrayImpl and is O(n) in the length of the list.

🔗def
List.toArrayImpl.{u_1} {α : Type u_1}
  (xs : List α) : Array α

Convert a List α into an Array α. This is O(n) in the length of the list.

🔗def
List.toByteArray (bs : List UInt8) : ByteArray
🔗def
List.toFloatArray (ds : List Float) : FloatArray
🔗def
List.toPArray'.{u} {α : Type u} (xs : List α) :
  Lean.PersistentArray α
🔗def
List.toString.{u_1} {α : Type u_1}
  [ToString α] : List αString

14.15.3.7. Modification

🔗def
List.set.{u_1} {α : Type u_1} :
  List αNatαList α

l.set n a sets the value of list l at (zero-based) index n to a: [a, b, c, d].set 1 b' = [a, b', c, d]

🔗def
List.setTR.{u_1} {α : Type u_1} (l : List α)
  (n : Nat) (a : α) : List α

Tail recursive version of List.set.

🔗def
List.modify.{u} {α : Type u} (f : αα) :
  NatList αList α

Apply f to the nth element of the list, if it exists, replacing that element with the result.

🔗def
List.modifyHead.{u} {α : Type u} (f : αα) :
  List αList α

Apply f to the head of the list, if it exists.

🔗def
List.modifyTR.{u_1} {α : Type u_1} (f : αα)
  (n : Nat) (l : List α) : List α

Tail-recursive version of modify.

🔗def
List.modifyTailIdx.{u} {α : Type u}
  (f : List αList α) : NatList αList α

Apply a function to the nth tail of l. Returns the input without using f if the index is larger than the length of the List.

modifyTailIdx f 2 [a, b, c] = [a, b] ++ f [c]
🔗def
List.erase.{u_1} {α : Type u_1} [BEq α] :
  List ααList α

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]

🔗def
List.eraseDups.{u_1} {α : Type u_1} [BEq α]
  (as : List α) : List α

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
List.eraseIdx.{u} {α : Type u} :
  List αNatList α

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
List.eraseIdxTR.{u_1} {α : Type u_1}
  (l : List α) (n : Nat) : List α

Tail recursive version of List.eraseIdx.

🔗def
List.eraseP.{u} {α : Type u} (p : αBool) :
  List αList α

eraseP p l removes the first element of l satisfying the predicate p.

🔗def
List.erasePTR.{u_1} {α : Type u_1}
  (p : αBool) (l : List α) : List α

Tail-recursive version of eraseP.

🔗def
List.eraseReps.{u_1} {α : Type u_1} [BEq α] :
  List αList α

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
List.eraseTR.{u_1} {α : Type u_1} [BEq α]
  (l : List α) (a : α) : List α

Tail recursive version of List.erase.

🔗def
List.extract.{u} {α : Type u} (l : List α)
  (start : Nat := 0) (stop : Nat := l.length) :
  List α

extract l start stop returns the slice of l from indices start to stop (exclusive).

🔗def
List.removeAll.{u} {α : Type u} [BEq α]
  (xs ys : List α) : List α

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
List.replace.{u} {α : Type u} [BEq α] :
  List αααList α

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
List.replaceTR.{u_1} {α : Type u_1} [BEq α]
  (l : List α) (b c : α) : List α

Tail recursive version of List.replace.

🔗def
List.reverse.{u} {α : Type u} (as : List α) :
  List α

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
List.flatten.{u} {α : Type u} :
  List (List α) → List α

O(|flatten L|). flatten L concatenates all the lists in L into one list.

  • flatten [[a], [], [b, c], [d, e, f]] = [a, b, c, d, e, f]

🔗def
List.flattenTR.{u_1} {α : Type u_1}
  (l : List (List α)) : List α

Tail recursive version of List.flatten.

🔗def
List.rotateLeft.{u} {α : Type u} (xs : List α)
  (i : Nat := 1) : List α

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
List.rotateRight.{u} {α : Type u} (xs : List α)
  (i : Nat := 1) : List α

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
List.leftpad.{u} {α : Type u} (n : Nat) (a : α)
  (l : List α) : List α

Pads l : List α on the left with repeated occurrences of a : α until it is of length n. If l is initially larger than n, just return l.

🔗def
List.leftpadTR.{u} {α : Type u} (n : Nat)
  (a : α) (l : List α) : List α

Optimized version of leftpad.

🔗def
List.rightpad.{u} {α : Type u} (n : Nat) (a : α)
  (l : List α) : List α

Pads l : List α on the right with repeated occurrences of a : α until it is of length n. If l is initially larger than n, just return l.

14.15.3.7.1. Insertion

🔗def
List.insert.{u} {α : Type u} [BEq α] (a : α)
  (l : List α) : List α

Inserts an element into a list without duplication.

🔗def
List.insertIdx.{u} {α : Type u} (i : Nat)
  (a : α) : List αList α

insertIdx n a l inserts a into the list l after the first n elements of l

insertIdx 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
🔗def
List.insertIdxTR.{u_1} {α : Type u_1} (n : Nat)
  (a : α) (l : List α) : List α

Tail-recursive version of insertIdx.

🔗def
List.intercalate.{u} {α : Type u} (sep : List α)
  (xs : List (List α)) : List α

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
List.intercalateTR.{u_1} {α : Type u_1}
  (sep : List α) : List (List α) → List α

Tail recursive version of List.intercalate.

🔗def
List.intersperse.{u} {α : Type u} (sep : α) :
  List αList α

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
List.intersperseTR.{u} {α : Type u} (sep : α) :
  List αList α

Tail recursive version of List.intersperse.

14.15.3.8. Sorting

🔗def
List.mergeSort.{u_1} {α : Type u_1}
  (xs : List α)
  (le : ααBool := by
    exact fun a b => a ≤ b) :
  List α

Simplified implementation of stable merge sort.

This function is designed for reasoning about the algorithm, and is not efficient. (It particular it uses the non tail-recursive merge function, and so can not be run on large lists, but also makes unnecessary traversals of lists.) It is replaced at runtime in the compiler by mergeSortTR₂ using a @[csimp] lemma.

Because we want the sort to be stable, it is essential that we split the list in two contiguous sublists.

🔗def
List.merge.{u_1} {α : Type u_1} (xs ys : List α)
  (le : ααBool := by
    exact fun a b => a ≤ b) :
  List α

O(min |l| |r|). Merge two lists using le as a switch.

This version is not tail-recursive, but it is replaced at runtime by mergeTR using a @[csimp] lemma.

14.15.3.9. Iteration

🔗def
List.forA.{u, v, w} {m : Type uType v}
  [Applicative m] {α : Type w} (as : List α)
  (f : αm PUnit) : m PUnit

Applies the applicative action f on every element in the list, left-to-right.

NB: If m is also a Monad, then using forM can be more efficient.

See List.mapA for the variant that collects results. See List.forM for the variant that works with Monad.

🔗def
List.forM.{u, v, w} {m : Type uType v}
  [Monad m] {α : Type w} (as : List α)
  (f : αm PUnit) : m PUnit

Applies the monadic action f on every element in the list, left-to-right.

See List.mapM for the variant that collects results. See List.forA for the variant that works with Applicative.

🔗def
List.forIn'.{u, v, w} {α : Type u} {β : Type v}
  {m : Type vType w} [Monad m] (as : List α)
  (init : β)
  (f : (a : α) → aasβm (ForInStep β)) :
  m β
🔗def
List.firstM.{u, v, w} {m : Type uType v}
  [Alternative m] {α : Type w} {β : Type u}
  (f : αm β) : List αm β

Maps f over the list and collects the results with <|>.

firstM f [a, b, c] = f a <|> f b <|> f c <|> failure
🔗def
List.sum.{u_1} {α : Type u_1} [Add α] [Zero α] :
  List αα

Sum of a list.

List.sum [a, b, c] = a + (b + (c + 0))

14.15.3.9.1. Folds

Folds are operators that combine the elements of a list using a function. They come in two varieties, named after the nesting of the function calls:

Left folds

Left folds combine the elements from the head of the list towards the end. The head of the list is combined with the initial value, and the result of this operation is then combined with the next value, and so forth.

Right folds

Right folds combine the elements from the end of the list towards the start, as if each cons constructor were replaced by a call to the combining function and nil were replaced by the initial value.

Monadic folds, indicated with an -M suffix, allow the combining function to use effects in a monad, which may include stopping the fold early.

🔗def
List.foldl.{u, v} {α : Type u} {β : Type v}
  (f : αβα) (init : α) : List βα

Folds a function over a list from the left: foldl f z [a, b, c] = f (f (f z a) b) c

🔗def
List.foldlM.{u, v, w} {m : Type uType v}
  [Monad m] {s : Type u} {α : Type w}
  (f : sαm s) (init : s) : List αm s

Folds a monadic function over a list from left to right:

foldlM f x₀ [a, b, c] = do let x₁ f x₀ a let x₂ f x₁ b let x₃ f x₂ c pure x₃
🔗def
List.foldlRecOn.{u_1, u_2, u_3} {β : Type u_1}
  {α : Type u_2} {motive : βSort u_3}
  (l : List α) (op : βαβ) (b : β) :
  motive b →
    ((b : β) →
        motive b →
          (a : α) → almotive (op b a)) →
      motive (List.foldl op b l)

Prove a proposition about the result of List.foldl, by proving it for the initial data, and the implication that the operation applied to any element of the list preserves the property.

The motive can take values in Sort _, so this may be used to construct data, as well as to prove propositions.

🔗def
List.foldr.{u, v} {α : Type u} {β : Type v}
  (f : αββ) (init : β) : List αβ

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

🔗def
List.foldrM.{u, v, w} {m : Type uType v}
  [Monad m] {s : Type u} {α : Type w}
  (f : αsm s) (init : s) (l : List α) :
  m s

Folds a monadic function over a list from right to left:

foldrM f x₀ [a, b, c] = do let x₁ f c x₀ let x₂ f b x₁ let x₃ f a x₂ pure x₃
🔗def
List.foldrRecOn.{u_1, u_2, u_3} {β : Type u_1}
  {α : Type u_2} {motive : βSort u_3}
  (l : List α) (op : αββ) (b : β) :
  motive b →
    ((b : β) →
        motive b →
          (a : α) → almotive (op a b)) →
      motive (List.foldr op b l)

Prove a proposition about the result of List.foldr, by proving it for the initial data, and the implication that the operation applied to any element of the list preserves the property.

The motive can take values in Sort _, so this may be used to construct data, as well as to prove propositions.

🔗def
List.foldrTR.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} (f : αββ) (init : β)
  (l : List α) : β

Tail recursive version of List.foldr.

14.15.3.10. Transformation

🔗def
List.map.{u, v} {α : Type u} {β : Type v}
  (f : αβ) : List αList β

O(|l|). map f l applies f to each element of the list.

  • map f [a, b, c] = [f a, f b, f c]

🔗def
List.mapTR.{u, v} {α : Type u} {β : Type v}
  (f : αβ) (as : List α) : List β

Tail-recursive version of List.map.

🔗def
List.mapM.{u, v, w} {m : Type uType v}
  [Monad m] {α : Type w} {β : Type u}
  (f : αm β) (as : List α) : m (List β)

Applies the monadic action f on every element in the list, left-to-right, and returns the list of results.

See List.forM for the variant that discards the results. See List.mapA for the variant that works with Applicative.

🔗def
List.mapM'.{u_1, u_2, u_3}
  {m : Type u_1Type u_2} {α : Type u_3}
  {β : Type u_1} [Monad m] (f : αm β) :
  List αm (List β)

Alternate (non-tail-recursive) form of mapM for proofs.

Note that we can not have this as the main definition and replace it using a @[csimp] lemma, because they are only equal when m is a LawfulMonad.

🔗def
List.mapA.{u, v, w} {m : Type uType v}
  [Applicative m] {α : Type w} {β : Type u}
  (f : αm β) : List αm (List β)

Applies the applicative action f on every element in the list, left-to-right, and returns the list of results.

NB: If m is also a Monad, then using mapM can be more efficient.

See List.forA for the variant that discards the results. See List.mapM for the variant that works with Monad.

Warning: this function is not tail-recursive, meaning that it may fail with a stack overflow on long lists.

🔗def
List.mapFinIdx.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} (as : List α)
  (f : (i : Nat) → αi < as.lengthβ) :
  List β

Given a list as = [a₀, a₁, ...] and a function f : (i : Nat) α (h : i < as.length) β, returns the list [f 0 a₀ , f 1 a₁ , ...].

🔗def
List.mapFinIdxM.{u_1, u_2, u_3}
  {m : Type u_1Type u_2} {α : Type u_3}
  {β : Type u_1} [Monad m] (as : List α)
  (f : (i : Nat) → αi < as.lengthm β) :
  m (List β)

Given a list as = [a₀, a₁, ...] and a monadic function f : (i : Nat) α (h : i < as.length) m β, returns the list [f 0 a₀ , f 1 a₁ , ...].

🔗def
List.mapIdx.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} (f : Natαβ)
  (as : List α) : List β

Given a function f : Nat α β and as : List α, as = [a₀, a₁, ...], returns the list [f 0 a₀, f 1 a₁, ...].

🔗def
List.mapIdxM.{u_1, u_2, u_3}
  {m : Type u_1Type u_2} {α : Type u_3}
  {β : Type u_1} [Monad m] (f : Natαm β)
  (as : List α) : m (List β)

Given a monadic function f : Nat α m β and as : List α, as = [a₀, a₁, ...], returns the list [f 0 a₀, f 1 a₁, ...].

🔗def
List.mapMono.{u_1} {α : Type u_1} (as : List α)
  (f : αα) : List α
🔗def
List.mapMonoM.{u_1, u_2}
  {m : Type u_1Type u_2} {α : Type u_1}
  [Monad m] (as : List α) (f : αm α) :
  m (List α)

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

🔗def
List.flatMap.{u, v} {α : Type u} {β : Type v}
  (b : αList β) (as : List α) : List β

flatMap xs f 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]

🔗def
List.flatMapM.{u, v, w} {m : Type uType v}
  [Monad m] {α : Type w} {β : Type u}
  (f : αm (List β)) (as : List α) :
  m (List β)

Applies the monadic function f on every element x in the list, left-to-right, and returns the concatenation of the results.

🔗def
List.flatMapTR.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} (f : αList β)
  (as : List α) : List β

Tail recursive version of List.flatMap.

🔗def
List.unzip.{u, v} {α : Type u} {β : Type v} :
  List (α × β)List α × List β

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
List.unzipTR.{u, v} {α : Type u} {β : Type v}
  (l : List (α × β)) : List α × List β

Tail recursive version of List.unzip.

🔗def
List.zip.{u, v} {α : Type u} {β : Type v} :
  List αList βList (α × β)

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
List.zipIdx.{u} {α : Type u} :
  List α → (n : optParam Nat 0) → List (α × Nat)

O(|l|). zipIdx l zips a list with its indices, optionally starting from a given index.

  • zipIdx [a, b, c] = [(a, 0), (b, 1), (c, 2)]

  • zipIdx [a, b, c] 5 = [(a, 5), (b, 6), (c, 7)]

🔗def
List.zipIdxTR.{u_1} {α : Type u_1} (l : List α)
  (n : Nat := 0) : List (α × Nat)

Tail recursive version of List.zipIdx.

🔗def
List.zipIdxLE.{u_1} {α : Type u_1}
  (le : ααBool) (a b : α × Nat) : Bool

Given an ordering relation le : α α Bool, construct the lexicographic ordering on α × Nat. which first compares the first components using le, but if these are equivalent (in the sense le a.2 b.2 && le b.2 a.2) then compares the second components using .

This function is only used in stating the stability properties of mergeSort.

🔗def
List.zipWith.{u, v, w} {α : Type u} {β : Type v}
  {γ : Type w} (f : αβγ) (xs : List α)
  (ys : List β) : List γ

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₃]

🔗def
List.zipWithTR.{u_1, u_2, u_3} {α : Type u_1}
  {β : Type u_2} {γ : Type u_3} (f : αβγ)
  (as : List α) (bs : List β) : List γ

Tail recursive version of List.zipWith.

🔗def
List.zipWithAll.{u, v, w} {α : Type u}
  {β : Type v} {γ : Type w}
  (f : Option αOption βγ) :
  List αList βList γ

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.

14.15.3.11. Filtering

🔗def
List.filter.{u} {α : Type u} (p : αBool) :
  List αList α

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
List.filterTR.{u} {α : Type u} (p : αBool)
  (as : List α) : List α

Tail-recursive version of List.filter.

🔗def
List.filterM.{v} {m : TypeType v} [Monad m]
  {α : Type} (p : αm Bool) (as : List α) :
  m (List α)

Applies the monadic predicate p on every element in the list, left-to-right, and returns those elements x for which p x returns true.

🔗def
List.filterMap.{u, v} {α : Type u} {β : Type v}
  (f : αOption β) : List αList β

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]
🔗def
List.filterMapTR.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} (f : αOption β)
  (l : List α) : List β

Tail recursive version of filterMap.

🔗def
List.filterMapM.{u, v, w} {m : Type uType v}
  [Monad m] {α : Type w} {β : Type u}
  (f : αm (Option β)) (as : List α) :
  m (List β)

Applies the monadic function f on every element x in the list, left-to-right, and returns those results y for which f x returns some y.

🔗def
List.filterRevM.{v} {m : TypeType v}
  [Monad m] {α : Type} (p : αm Bool)
  (as : List α) : m (List α)

Applies the monadic predicate p on every element in the list, right-to-left, and returns those elements x for which p x returns true.

14.15.3.12. Partitioning

🔗def
List.take.{u} {α : Type u} :
  NatList αList α

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
List.takeTR.{u_1} {α : Type u_1} (n : Nat)
  (l : List α) : List α

Tail recursive version of List.take.

🔗def
List.takeWhile.{u} {α : Type u} (p : αBool)
  (xs : List α) : List α

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
List.takeWhileTR.{u_1} {α : Type u_1}
  (p : αBool) (l : List α) : List α

Tail recursive version of List.takeWhile.

🔗def
List.drop.{u} {α : Type u} :
  NatList αList α

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
List.dropLast.{u_1} {α : Type u_1} :
  List αList α

Removes the last element of the list.

  • dropLast [] = []

  • dropLast [a] = []

  • dropLast [a, b, c] = [a, b]

🔗def
List.dropLastTR.{u_1} {α : Type u_1}
  (l : List α) : List α

Tail recursive version of dropLast.

🔗def
List.dropWhile.{u} {α : Type u} (p : αBool) :
  List αList α

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
List.splitAt.{u} {α : Type u} (n : Nat)
  (l : List α) : List α × List α

Split a list at an index.

splitAt 2 [a, b, c] = ([a, b], [c])
🔗def
List.span.{u} {α : Type u} (p : αBool)
  (as : List α) : List α × List α

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])

🔗def
List.splitBy.{u} {α : Type u}
  (R : ααBool) : List αList (List α)

O(|l|). splitBy R l splits l into chains of elements such that adjacent elements are related by R.

  • splitBy (·==·) [1, 1, 2, 2, 2, 3, 2] = [[1, 1], [2, 2, 2], [3], [2]]

  • splitBy (·<·) [1, 2, 5, 4, 5, 1, 4] = [[1, 2, 5], [4, 5], [1, 4]]

🔗def
List.partition.{u} {α : Type u} (p : αBool)
  (as : List α) : List α × List α

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])
🔗def
List.partitionM.{u_1} {m : TypeType u_1}
  {α : Type} [Monad m] (p : αm Bool)
  (l : List α) : m (List α × List α)

Monadic generalization of List.partition.

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

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

partitionM posOrNeg [-1, 2, 3] = Except.ok ([2, 3], [-1])
partitionM posOrNeg [0, 2, 3] = Except.error "Zero is not positive or negative"
🔗def
List.partitionMap.{u_1, u_2, u_3} {α : Type u_1}
  {β : Type u_2} {γ : Type u_3} (f : αβγ)
  (l : List α) : List β × List γ

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

partitionMap (id : Nat Nat Nat Nat) [inl 0, inr 1, inl 2] = ([0, 2], [1])
🔗def
List.groupByKey.{u, v} {α : Type u} {β : Type v}
  [BEq α] [Hashable α] (key : βα)
  (xs : List β) : Std.HashMap α (List β)

Groups all elements x, y in xs with key x == key y into the same list (xs.groupByKey key).find! (key x). Groups preserve the relative order of elements in xs.

14.15.3.13. Element Predicates

🔗def
List.contains.{u} {α : Type u} [BEq α]
  (as : List α) (a : α) : Bool

O(|l|). l.contains a or elem a l is true if there is an element in l equal (according to ==) to a.

The preferred simp normal form is l.contains a, and when LawfulBEq α is available, l.contains a = true a l and l.contains a = false a l.

🔗def
List.elem.{u} {α : Type u} [BEq α] (a : α) :
  List αBool

O(|l|). l.contains a or elem a l is true if there is an element in l equal (according to ==) to a.

The preferred simp normal form is l.contains a, and when LawfulBEq α is available, l.contains a = true a l and l.contains a = false a l.

🔗def
List.all.{u} {α : Type u} :
  List α → (αBool) → Bool

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
List.allM.{u, v} {m : TypeType u} [Monad m]
  {α : Type v} (f : αm Bool) :
  List αm Bool
🔗def
List.any.{u} {α : Type u} :
  List α → (αBool) → Bool

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
List.anyM.{u, v} {m : TypeType u} [Monad m]
  {α : Type v} (f : αm Bool) :
  List αm Bool
🔗def
List.and (bs : List Bool) : Bool

O(|l|). Returns true if every element of l is the value true.

  • and [a, b, c] = a && b && c

🔗def
List.or (bs : List Bool) : Bool

O(|l|). Returns true if true is an element of the list of booleans l.

  • or [a, b, c] = a || b || c

14.15.3.14. Comparisons

🔗def
List.beq.{u} {α : Type u} [BEq α] :
  List αList αBool

The equality relation on lists asserts that they have the same length and they are pairwise BEq.

🔗def
List.isEqv.{u} {α : Type u} (as bs : List α)
  (eqv : ααBool) : Bool

O(min |as| |bs|). Returns true if as and bs have the same length, and they are pairwise related by eqv.

🔗def
List.isPerm.{u} {α : Type u} [BEq α] :
  List αList αBool

O(|l₁| * |l₂|). Computes whether l₁ is a permutation of l₂. See isPerm_iff for a characterization in terms of List.Perm.

🔗def
List.isPrefixOf.{u} {α : Type u} [BEq α] :
  List αList αBool

isPrefixOf l₁ l₂ returns true Iff l₁ is a prefix of l₂. That is, there exists a t such that l₂ == l₁ ++ t.

🔗def
List.isPrefixOf?.{u} {α : Type u} [BEq α] :
  List αList αOption (List α)

isPrefixOf? l₁ l₂ returns some t when l₂ == l₁ ++ t.

🔗def
List.isSublist.{u} {α : Type u} [BEq α] :
  List αList αBool

True if the first list is a potentially non-contiguous sub-sequence of the second list.

🔗def
List.isSuffixOf.{u} {α : Type u} [BEq α]
  (l₁ l₂ : List α) : Bool

isSuffixOf l₁ l₂ returns true Iff l₁ is a suffix of l₂. That is, there exists a t such that l₂ == t ++ l₁.

🔗def
List.isSuffixOf?.{u} {α : Type u} [BEq α]
  (l₁ l₂ : List α) : Option (List α)

isSuffixOf? l₁ l₂ returns some t when l₂ == t ++ l₁.

🔗def
List.le.{u} {α : Type u} [LT α]
  (as bs : List α) : Prop

The lexicographic order on lists.

🔗def
List.lt.{u} {α : Type u} [LT α] :
  List αList αProp

Lexicographic ordering for lists.

🔗def
List.lex.{u} {α : Type u} [BEq α]
  (l₁ l₂ : List α)
  (lt : ααBool := by exact (· < ·)) : Bool

Lexicographic comparator for lists.

  • lex lt [] (b :: bs) is true.

  • lex lt as [] is false.

  • lex lt (a :: as) (b :: bs) is true if lt a b or a == b and lex lt as bs is true.

🔗def
List.hasDecEq.{u} {α : Type u} [DecidableEq α]
  (a b : List α) : Decidable (a = b)

Implements decidable equality for List α, assuming α has decidable equality.

14.15.3.15. Termination Helpers

🔗def
List.attach.{u_1} {α : Type u_1} (l : List α) :
  List { x // xl }

O(1). "Attach" the proof that the elements of l are in l to produce a new list with the same elements but in the type {x // x l}.

🔗def
List.attachWith.{u_1} {α : Type u_1}
  (l : List α) (P : αProp)
  (H : ∀ (x : α), xlP x) :
  List { x // P x }

O(1). "Attach" a proof P x that holds for all the elements of l to produce a new list with the same elements but in the type {x // P x}.

🔗def
List.unattach.{u_1} {α : Type u_1}
  {p : αProp} (l : List { x // p x }) :
  List α

A synonym for l.map (·.val). Mostly this should not be needed by users. It is introduced as an intermediate step by lemmas such as map_subtype, and is ideally subsequently simplified away by unattach_attach.

If not, usually the right approach is simp [List.unattach, -List.map_subtype] to unfold.

🔗def
List.pmap.{u_1, u_2} {α : Type u_1}
  {β : Type u_2} {P : αProp}
  (f : (a : α) → P aβ) (l : List α)
  (H : ∀ (a : α), alP a) : List β

O(n). Partial map. If f : Π a, P a → β is a partial function defined on a : α satisfying P, then pmap f l h is essentially the same as map f l but is defined only when all members of l satisfy P, using the proof to apply f.

14.15.3.16. Proof Automation

🔗def
List.reduceOption.{u_1} {α : Type u_1} :
  List (Option α) → List α

Drop nones from a list, and replace each remaining some a with a.

🔗def
List.reduceReplicate : Lean.Meta.Simp.DSimproc

Simplification procedure for List.replicate applied to a Nat literal.