doc: review List docstrings for manual (#7452)
This PR makes the style of all `List` docstrings that appear in the language reference consistent. Relies on #7240 for links and example formatting. --------- Co-authored-by: Kim Morrison <kim@tqft.net>
This commit is contained in:
parent
06c57826ae
commit
25179352b4
20 changed files with 1616 additions and 460 deletions
|
|
@ -337,6 +337,9 @@ def prevn : Iterator → Nat → Iterator
|
|||
end Iterator
|
||||
end ByteArray
|
||||
|
||||
/--
|
||||
Converts a list of bytes into a `ByteArray`.
|
||||
-/
|
||||
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||
let rec loop
|
||||
| [], r => r
|
||||
|
|
|
|||
|
|
@ -167,6 +167,9 @@ def foldl {β : Type v} (f : β → Float → β) (init : β) (as : FloatArray)
|
|||
|
||||
end FloatArray
|
||||
|
||||
/--
|
||||
Converts a list of floats into a `FloatArray`.
|
||||
-/
|
||||
def List.toFloatArray (ds : List Float) : FloatArray :=
|
||||
let rec loop
|
||||
| [], r => r
|
||||
|
|
|
|||
|
|
@ -13,29 +13,44 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
|||
|
||||
namespace 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`. -/
|
||||
/--
|
||||
Maps a partially defined function (defined on those terms of `α` that satisfy a predicate `P`) over
|
||||
a list `l : List α`, given a proof that every element of `l` in fact satisfies `P`.
|
||||
|
||||
`O(|l|)`. `List.pmap`, named for “partial map,” is the equivalent of `List.map` for such partial
|
||||
functions.
|
||||
-/
|
||||
def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||
| [], _ => []
|
||||
| a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2
|
||||
|
||||
/--
|
||||
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||
Unsafe implementation of `attachWith` that takes advantage of the fact that the representation of
|
||||
`List {x // P x}` is the same as the input `List α`.
|
||||
(Someday, the compiler might do this optimization automatically, but until then...)
|
||||
-/
|
||||
@[inline] private unsafe def attachWithImpl
|
||||
(l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l
|
||||
|
||||
/-- `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}`. -/
|
||||
/--
|
||||
“Attaches” individual proofs to a list of values that satisfy a predicate `P`, returning a list of
|
||||
elements in the corresponding subtype `{ x // P x }`.
|
||||
|
||||
`O(1)`.
|
||||
-/
|
||||
@[implemented_by attachWithImpl] def attachWith
|
||||
(l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H
|
||||
|
||||
/-- `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}`. -/
|
||||
/--
|
||||
"Attaches" the proof that the elements of `l` are in fact elements of `l`, producing a new list with
|
||||
the same elements but in the subtype `{ x // x ∈ l }`.
|
||||
|
||||
`O(1)`.
|
||||
|
||||
This function is primarily used to allow definitions by [well-founded
|
||||
recursion](lean-manual://section/well-founded-recursion) that use higher-order functions (such as
|
||||
`List.map`) to prove that an value taken from a list is smaller than the list. This allows the
|
||||
well-founded recursion mechanism to prove that the function terminates.
|
||||
-/
|
||||
@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id
|
||||
|
||||
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
|
||||
|
|
@ -650,11 +665,19 @@ Further, we provide simp lemmas that push `unattach` inwards.
|
|||
-/
|
||||
|
||||
/--
|
||||
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`.
|
||||
Maps a list of terms in a subtype to the corresponding terms in the type by forgetting that they
|
||||
satisfy the predicate.
|
||||
|
||||
If not, usually the right approach is `simp [List.unattach, -List.map_subtype]` to unfold.
|
||||
This is the inverse of `List.attachWith` and 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`.
|
||||
|
||||
This function is usually inserted automatically by Lean as an intermediate step while proving
|
||||
termination. It is rarely used explicitly in code. It is introduced as an intermediate step during
|
||||
the elaboration of definitions by [well-founded
|
||||
recursion](lean-manual://section/well-founded-recursion). If this function is encountered in a proof
|
||||
state, the right approach is usually the tactic `simp [List.unattach, -List.map_subtype]`.
|
||||
-/
|
||||
def unattach {α : Type _} {p : α → Prop} (l : List { x // p x }) : List α := l.map (·.val)
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -79,10 +79,16 @@ theorem get!_cons_zero [Inhabited α] (l : List α) (a : α) : (a::l).get! 0 = a
|
|||
/-! ### getD -/
|
||||
|
||||
/--
|
||||
Returns the `i`-th element in the list (zero-based).
|
||||
Returns the element at the provided index, counting from `0`. Returns `fallback` if the index is out
|
||||
of bounds.
|
||||
|
||||
If the index is out of bounds (`i ≥ as.length`), this function returns `fallback`.
|
||||
See also `get?` and `get!`.
|
||||
To return an `Option` depending on whether the index is in bounds, use `as[i]?`. To panic if the
|
||||
index is out of bounds, use `as[i]!`.
|
||||
|
||||
Examples:
|
||||
* `["spring", "summer", "fall", "winter"].getD 2 "never" = "fall"`
|
||||
* `["spring", "summer", "fall", "winter"].getD 0 "never" = "spring"`
|
||||
* `["spring", "summer", "fall", "winter"].getD 4 "never" = "never"`
|
||||
-/
|
||||
def getD (as : List α) (i : Nat) (fallback : α) : α :=
|
||||
as[i]?.getD fallback
|
||||
|
|
@ -92,10 +98,16 @@ def getD (as : List α) (i : Nat) (fallback : α) : α :=
|
|||
/-! ### getLast! -/
|
||||
|
||||
/--
|
||||
Returns the last element in the list.
|
||||
Returns the last element in the list. Panics and returns `default` if the list is empty.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns `default`.
|
||||
See `getLast` and `getLastD` for safer alternatives.
|
||||
Safer alternatives include:
|
||||
* `getLast?`, which returns an `Option`,
|
||||
* `getLastD`, which takes a fallback value for empty lists, and
|
||||
* `getLast`, which requires a proof that the list is non-empty.
|
||||
|
||||
Examples:
|
||||
* `["circle", "rectangle"].getLast! = "rectangle"`
|
||||
* `["circle"].getLast! = "circle"`
|
||||
-/
|
||||
def getLast! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
|
|
@ -106,10 +118,12 @@ def getLast! [Inhabited α] : List α → α
|
|||
/-! ### head! -/
|
||||
|
||||
/--
|
||||
Returns the first element in the list.
|
||||
Returns the first element in the list. If the list is empty, panics and returns `default`.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns `default`.
|
||||
See `head` and `headD` for safer alternatives.
|
||||
Safer alternatives include:
|
||||
* `List.head`, which requires a proof that the list is non-empty,
|
||||
* `List.head?`, which returns an `Option`, and
|
||||
* `List.headD`, which returns an explicitly-provided fallback value on empty lists.
|
||||
-/
|
||||
def head! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
|
|
@ -118,10 +132,17 @@ def head! [Inhabited α] : List α → α
|
|||
/-! ### tail! -/
|
||||
|
||||
/--
|
||||
Drops the first element of the list.
|
||||
Drops the first element of a nonempty list, returning the tail. If the list is empty, this function
|
||||
panics when executed and returns the empty list.
|
||||
|
||||
If the list is empty, this function panics when executed, and returns the empty list.
|
||||
See `tail` and `tailD` for safer alternatives.
|
||||
Safer alternatives include
|
||||
* `tail`, which returns the empty list without panicking,
|
||||
* `tail?`, which returns an `Option`, and
|
||||
* `tailD`, which returns a fallback value when passed the empty list.
|
||||
|
||||
Examples:
|
||||
* `["apple", "banana", "grape"].tail! = ["banana", "grape"]`
|
||||
* `["banana", "grape"].tail! = ["grape"]`
|
||||
-/
|
||||
def tail! : List α → List α
|
||||
| [] => panic! "empty list"
|
||||
|
|
@ -132,17 +153,30 @@ def tail! : List α → List α
|
|||
/-! ### partitionM -/
|
||||
|
||||
/--
|
||||
Monadic generalization of `List.partition`.
|
||||
Returns a pair of lists that together contain all the elements of `as`. The first list contains
|
||||
those elements for which the monadic predicate `p` returns `true`, and the second contains those for
|
||||
which `p` returns `false`. The list's elements are examined in order, from left to right.
|
||||
|
||||
This uses `Array.toList` and which isn't imported by `Init.Data.List.Basic` or `Init.Data.List.Control`.
|
||||
```
|
||||
This is a monadic version of `List.partition`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
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"
|
||||
```
|
||||
```lean example
|
||||
#eval [-1, 2, 3].partitionM posOrNeg
|
||||
```
|
||||
```output
|
||||
Except.ok ([2, 3], [-1])
|
||||
```
|
||||
```lean example
|
||||
#eval [0, 2, 3].partitionM posOrNeg
|
||||
```
|
||||
```output
|
||||
Except.error "Zero is not positive or negative"
|
||||
```
|
||||
-/
|
||||
@[inline] def partitionM [Monad m] (p : α → m Bool) (l : List α) : m (List α × List α) :=
|
||||
|
|
@ -162,12 +196,12 @@ where
|
|||
/-! ### partitionMap -/
|
||||
|
||||
/--
|
||||
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])
|
||||
```
|
||||
Applies a function that returns a disjoint union to each element of a list, collecting the `Sum.inl`
|
||||
and `Sum.inr` results into separate lists.
|
||||
|
||||
Examples:
|
||||
* `[0, 1, 2, 3].partitionMap (fun x => if x % 2 = 0 then .inl x else .inr x) = ([0, 2], [1, 3])`
|
||||
* `[0, 1, 2, 3].partitionMap (fun x => if x = 0 then .inl x else .inr x) = ([0], [1, 2, 3])`
|
||||
-/
|
||||
@[inline] def partitionMap (f : α → β ⊕ γ) (l : List α) : List β × List γ := go l #[] #[] where
|
||||
/-- Auxiliary for `partitionMap`:
|
||||
|
|
@ -199,14 +233,24 @@ For verification purposes, `List.mapMono = List.map`.
|
|||
return b' :: bs'
|
||||
|
||||
/--
|
||||
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`.
|
||||
Applies a monadic function to each element of a list, returning the list of results. The function is
|
||||
monomorphic: it is required to return a value of the same type. The internal implementation uses
|
||||
pointer equality, and does not allocate a new list if the result of each function call is
|
||||
pointer-equal to its argument.
|
||||
-/
|
||||
@[implemented_by mapMonoMImp] def mapMonoM [Monad m] (as : List α) (f : α → m α) : m (List α) :=
|
||||
match as with
|
||||
| [] => return []
|
||||
| a :: as => return (← f a) :: (← mapMonoM as f)
|
||||
|
||||
/--
|
||||
Applies a function to each element of a list, returning the list of results. The function is
|
||||
monomorphic: it is required to return a value of the same type. The internal implementation uses
|
||||
pointer equality, and does not allocate a new list if the result of each function call is
|
||||
pointer-equal to its argument.
|
||||
|
||||
For verification purposes, `List.mapMono = List.map`.
|
||||
-/
|
||||
def mapMono (as : List α) (f : α → α) : List α :=
|
||||
Id.run <| as.mapMonoM f
|
||||
|
||||
|
|
|
|||
|
|
@ -49,8 +49,9 @@ Users that want to use `mapM` with `Applicative` should use `mapA` instead.
|
|||
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`.
|
||||
This implementation is tail recursive. `List.mapM'` is a a non-tail-recursive variant that may be
|
||||
more convenient to reason about. `List.forM` is the variant that discards the results and
|
||||
`List.mapA` is the variant that works with `Applicative`.
|
||||
-/
|
||||
@[inline]
|
||||
def mapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m β) (as : List α) : m (List β) :=
|
||||
|
|
@ -60,15 +61,15 @@ def mapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α
|
|||
loop as []
|
||||
|
||||
/--
|
||||
Applies the applicative action `f` on every element in the list, left-to-right, and returns the list of
|
||||
results.
|
||||
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.
|
||||
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`.
|
||||
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.
|
||||
This function is not tail-recursive, so it may fail with a stack overflow on long lists.
|
||||
-/
|
||||
@[specialize]
|
||||
def mapA {m : Type u → Type v} [Applicative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m (List β)
|
||||
|
|
@ -76,10 +77,10 @@ def mapA {m : Type u → Type v} [Applicative m] {α : Type w} {β : Type u} (f
|
|||
| a::as => List.cons <$> f a <*> mapA f as
|
||||
|
||||
/--
|
||||
Applies the monadic action `f` on every element in the list, left-to-right.
|
||||
Applies the monadic action `f` to every element in the list, in order.
|
||||
|
||||
See `List.mapM` for the variant that collects results.
|
||||
See `List.forA` for the variant that works with `Applicative`.
|
||||
`List.mapM` is a variant that collects results. `List.forA` is a variant that works on any
|
||||
`Applicative`.
|
||||
-/
|
||||
@[specialize]
|
||||
protected def forM {m : Type u → Type v} [Monad m] {α : Type w} (as : List α) (f : α → m PUnit) : m PUnit :=
|
||||
|
|
@ -88,12 +89,11 @@ protected def forM {m : Type u → Type v} [Monad m] {α : Type w} (as : List α
|
|||
| a :: as => do f a; List.forM as f
|
||||
|
||||
/--
|
||||
Applies the applicative action `f` on every element in the list, left-to-right.
|
||||
Applies the applicative action `f` to every element in the list, in order.
|
||||
|
||||
NB: If `m` is also a `Monad`, then using `forM` can be more efficient.
|
||||
If `m` is also a `Monad`, then using `List.forM` can be more efficient.
|
||||
|
||||
See `List.mapA` for the variant that collects results.
|
||||
See `List.forM` for the variant that works with `Monad`.
|
||||
`List.mapA` is a variant that collects results.
|
||||
-/
|
||||
@[specialize]
|
||||
def forA {m : Type u → Type v} [Applicative m] {α : Type w} (as : List α) (f : α → m PUnit) : m PUnit :=
|
||||
|
|
@ -110,8 +110,28 @@ def filterAuxM {m : Type → Type v} [Monad m] {α : Type} (f : α → m Bool) :
|
|||
filterAuxM f t (cond b (h :: acc) acc)
|
||||
|
||||
/--
|
||||
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`.
|
||||
Applies the monadic predicate `p` to every element in the list, in order from left to right, and
|
||||
returns the list of elements for which `p` returns `true`.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [1, 2, 5, 2, 7, 7].filterM fun x => do
|
||||
IO.println s!"Checking {x}"
|
||||
return x < 3
|
||||
```
|
||||
```output
|
||||
Checking 1
|
||||
Checking 2
|
||||
Checking 5
|
||||
Checking 2
|
||||
Checking 7
|
||||
Checking 7
|
||||
```
|
||||
```output
|
||||
[1, 2, 2]
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def filterM {m : Type → Type v} [Monad m] {α : Type} (p : α → m Bool) (as : List α) : m (List α) := do
|
||||
|
|
@ -119,16 +139,56 @@ def filterM {m : Type → Type v} [Monad m] {α : Type} (p : α → m Bool) (as
|
|||
pure as.reverse
|
||||
|
||||
/--
|
||||
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`.
|
||||
Applies the monadic predicate `p` on every element in the list in reverse order, from right to left,
|
||||
and returns those elements for which `p` returns `true`. The elements of the returned list are in
|
||||
the same order as in the input list.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [1, 2, 5, 2, 7, 7].filterRevM fun x => do
|
||||
IO.println s!"Checking {x}"
|
||||
return x < 3
|
||||
```
|
||||
```output
|
||||
Checking 7
|
||||
Checking 7
|
||||
Checking 2
|
||||
Checking 5
|
||||
Checking 2
|
||||
Checking 1
|
||||
```
|
||||
```output
|
||||
[1, 2, 2]
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def filterRevM {m : Type → Type v} [Monad m] {α : Type} (p : α → m Bool) (as : List α) : m (List α) :=
|
||||
filterAuxM p as.reverse []
|
||||
|
||||
/--
|
||||
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`.
|
||||
Applies a monadic function that returns an `Option` to each element of a list, collecting the
|
||||
non-`none` values.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [1, 2, 5, 2, 7, 7].filterMapM fun x => do
|
||||
IO.println s!"Examining {x}"
|
||||
if x > 2 then return some (2 * x)
|
||||
else return none
|
||||
```
|
||||
```output
|
||||
Examining 1
|
||||
Examining 2
|
||||
Examining 5
|
||||
Examining 2
|
||||
Examining 7
|
||||
Examining 7
|
||||
```
|
||||
```output
|
||||
[10, 14, 14]
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def filterMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (Option β)) (as : List α) : m (List β) :=
|
||||
|
|
@ -141,8 +201,8 @@ def filterMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
|
|||
loop as []
|
||||
|
||||
/--
|
||||
Applies the monadic function `f` on every element `x` in the list, left-to-right, and returns the
|
||||
concatenation of the results.
|
||||
Applies a monadic function that returns a list to each element of a list, from left to right, and
|
||||
concatenates the resulting lists.
|
||||
-/
|
||||
@[inline]
|
||||
def flatMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (List β)) (as : List α) : m (List β) :=
|
||||
|
|
@ -153,14 +213,20 @@ def flatMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f :
|
|||
loop as (bs' :: bs)
|
||||
loop as []
|
||||
|
||||
|
||||
/--
|
||||
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₃
|
||||
Folds a monadic function over a list from the left, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
example [Monad m] (f : α → β → m α) :
|
||||
List.foldlM (m := m) f x₀ [a, b, c] = (do
|
||||
let x₁ ← f x₀ a
|
||||
let x₂ ← f x₁ b
|
||||
let x₃ ← f x₂ c
|
||||
pure x₃)
|
||||
:= by rfl
|
||||
```
|
||||
-/
|
||||
@[specialize]
|
||||
|
|
@ -176,13 +242,18 @@ def foldlM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} : (f : s
|
|||
simp [List.foldlM]
|
||||
|
||||
/--
|
||||
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₃
|
||||
Folds a monadic function over a list from the right, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
example [Monad m] (f : α → β → m β) :
|
||||
List.foldrM (m := m) f x₀ [a, b, c] = (do
|
||||
let x₁ ← f c x₀
|
||||
let x₂ ← f b x₁
|
||||
let x₃ ← f a x₂
|
||||
pure x₃)
|
||||
:= by rfl
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
|
|
@ -192,32 +263,70 @@ def foldrM {m : Type u → Type v} [Monad m] {s : Type u} {α : Type w} (f : α
|
|||
@[simp] theorem foldrM_nil [Monad m] (f : α → β → m β) (b) : [].foldrM f b = pure b := rfl
|
||||
|
||||
/--
|
||||
Maps `f` over the list and collects the results with `<|>`.
|
||||
```
|
||||
firstM f [a, b, c] = f a <|> f b <|> f c <|> failure
|
||||
```
|
||||
Maps `f` over the list and collects the results with `<|>`. The result for the end of the list is
|
||||
`failure`.
|
||||
|
||||
Examples:
|
||||
* `[[], [1, 2], [], [2]].firstM List.head? = some 1`
|
||||
* `[[], [], []].firstM List.head? = none`
|
||||
* `[].firstM List.head? = none`
|
||||
-/
|
||||
@[specialize]
|
||||
def firstM {m : Type u → Type v} [Alternative m] {α : Type w} {β : Type u} (f : α → m β) : List α → m β
|
||||
| [] => failure
|
||||
| a::as => f a <|> firstM f as
|
||||
|
||||
/--
|
||||
Returns true if the monadic predicate `p` returns `true` for any element of `l`.
|
||||
|
||||
`O(|l|)`. Short-circuits upon encountering the first `true`. The elements in `l` are examined in
|
||||
order from left to right.
|
||||
-/
|
||||
@[specialize]
|
||||
def anyM {m : Type → Type u} [Monad m] {α : Type v} (f : α → m Bool) : List α → m Bool
|
||||
def anyM {m : Type → Type u} [Monad m] {α : Type v} (p : α → m Bool) : (l : List α) → m Bool
|
||||
| [] => pure false
|
||||
| a::as => do
|
||||
match (← f a) with
|
||||
match (← p a) with
|
||||
| true => pure true
|
||||
| false => anyM f as
|
||||
| false => anyM p as
|
||||
|
||||
/--
|
||||
Returns true if the monadic predicate `p` returns `true` for every element of `l`.
|
||||
|
||||
`O(|l|)`. Short-circuits upon encountering the first `false`. The elements in `l` are examined in
|
||||
order from left to right.
|
||||
-/
|
||||
@[specialize]
|
||||
def allM {m : Type → Type u} [Monad m] {α : Type v} (f : α → m Bool) : List α → m Bool
|
||||
def allM {m : Type → Type u} [Monad m] {α : Type v} (p : α → m Bool) : (l : List α) → m Bool
|
||||
| [] => pure true
|
||||
| a::as => do
|
||||
match (← f a) with
|
||||
| true => allM f as
|
||||
match (← p a) with
|
||||
| true => allM p as
|
||||
| false => pure false
|
||||
|
||||
/--
|
||||
Returns the first element of the list for which the monadic predicate `p` returns `true`, or `none`
|
||||
if no such element is found. Elements of the list are checked in order.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].findM? fun i => do
|
||||
if i < 5 then
|
||||
return true
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return false
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 1
|
||||
```
|
||||
-/
|
||||
@[specialize]
|
||||
def findM? {m : Type → Type u} [Monad m] {α : Type} (p : α → m Bool) : List α → m (Option α)
|
||||
| [] => pure none
|
||||
|
|
@ -241,6 +350,29 @@ theorem findM?_pure {m} [Monad m] [LawfulMonad m] (p : α → Bool) (as : List
|
|||
theorem findM?_id (p : α → Bool) (as : List α) : findM? (m := Id) p as = as.find? p :=
|
||||
findM?_pure _ _
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the monadic function `f` to each element of the
|
||||
list, in order. Returns `none` if `f` returns `none` for all elements.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].findSomeM? fun i => do
|
||||
if i < 5 then
|
||||
return some (i * 10)
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return none
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 10
|
||||
```
|
||||
-/
|
||||
@[specialize]
|
||||
def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (Option β)) : List α → m (Option β)
|
||||
| [] => pure none
|
||||
|
|
|
|||
|
|
@ -11,7 +11,13 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
|||
|
||||
namespace List
|
||||
|
||||
/-- `finRange n` lists all elements of `Fin n` in order -/
|
||||
/--
|
||||
Lists all elements of `Fin n` in order, starting at `0`.
|
||||
|
||||
Examples:
|
||||
* `List.finRange 0 = ([] : List Fin 0)`
|
||||
* `List.finRange 2 = ([0, 1] : List Fin 2)`
|
||||
-/
|
||||
def finRange (n : Nat) : List (Fin n) := ofFn fun i => i
|
||||
|
||||
@[simp] theorem length_finRange (n) : (List.finRange n).length = n := by
|
||||
|
|
|
|||
|
|
@ -49,7 +49,16 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### set -/
|
||||
|
||||
/-- Tail recursive version of `List.set`. -/
|
||||
/--
|
||||
Replaces the value at (zero-based) index `n` in `l` with `a`. If the index is out of bounds, then
|
||||
the list is returned unmodified.
|
||||
|
||||
This is a tail-recursive version of `List.set` that's used at runtime.
|
||||
|
||||
Examples:
|
||||
* `["water", "coffee", "soda", "juice"].set 1 "tea" = ["water", "tea", "soda", "juice"]`
|
||||
* `["water", "coffee", "soda", "juice"].set 4 "tea" = ["water", "coffee", "soda", "juice"]`
|
||||
-/
|
||||
@[inline] def setTR (l : List α) (n : Nat) (a : α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `setTR`: `setTR.go l a xs n acc = acc.toList ++ set xs a`,
|
||||
unless `n ≥ l.length` in which case it returns `l` -/
|
||||
|
|
@ -69,7 +78,22 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### filterMap -/
|
||||
|
||||
/-- Tail recursive version of `filterMap`. -/
|
||||
|
||||
/--
|
||||
Applies a function that returns an `Option` to each element of a list, collecting the non-`none`
|
||||
values.
|
||||
|
||||
`O(|l|)`. This is a tail-recursive version of `List.filterMap`, used at runtime.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [1, 2, 5, 2, 7, 7].filterMapTR fun x =>
|
||||
if x > 2 then some (2 * x) else none
|
||||
```
|
||||
```output
|
||||
[10, 14, 14]
|
||||
```
|
||||
-/
|
||||
@[inline] def filterMapTR (f : α → Option β) (l : List α) : List β := go l #[] where
|
||||
/-- Auxiliary for `filterMap`: `filterMap.go f l = acc.toList ++ filterMap f l` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
|
|
@ -90,7 +114,17 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### foldr -/
|
||||
|
||||
/-- Tail recursive version of `List.foldr`. -/
|
||||
/--
|
||||
Folds a function over a list from the right, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with the each element of the list in reverse order, using `f`.
|
||||
|
||||
`O(|l|)`. This is the tail-recursive replacement for `List.foldr` in runtime code.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].foldrTR f init = f a (f b (f c init))`
|
||||
* `[1, 2, 3].foldrTR (toString · ++ ·) "" = "123"`
|
||||
* `[1, 2, 3].foldrTR (s!"({·} {·})") "!" = "(1 (2 (3 !)))"`
|
||||
-/
|
||||
@[specialize] def foldrTR (f : α → β → β) (init : β) (l : List α) : β := l.toArray.foldr f init
|
||||
|
||||
@[csimp] theorem foldr_eq_foldrTR : @foldr = @foldrTR := by
|
||||
|
|
@ -98,7 +132,16 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### flatMap -/
|
||||
|
||||
/-- Tail recursive version of `List.flatMap`. -/
|
||||
/--
|
||||
Applies a function that returns a list to each element of a list, and concatenates the resulting
|
||||
lists.
|
||||
|
||||
This is the tail-recursive version of `List.flatMap` that's used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[2, 3, 2].flatMapTR List.range = [0, 1, 0, 1, 2, 0, 1]`
|
||||
* `["red", "blue"].flatMapTR String.toList = ['r', 'e', 'd', 'b', 'l', 'u', 'e']`
|
||||
-/
|
||||
@[inline] def flatMapTR (f : α → List β) (as : List α) : List β := go as #[] where
|
||||
/-- Auxiliary for `flatMap`: `flatMap.go f as = acc.toList ++ bind f as` -/
|
||||
@[specialize] go : List α → Array β → List β
|
||||
|
|
@ -114,7 +157,15 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### flatten -/
|
||||
|
||||
/-- Tail recursive version of `List.flatten`. -/
|
||||
/--
|
||||
Concatenates a list of lists into a single list, preserving the order of the elements.
|
||||
|
||||
`O(|flatten L|)`. This is a tail-recursive version of `List.flatten`, used in runtime code.
|
||||
|
||||
Examples:
|
||||
* `[["a"], ["b", "c"]].flattenTR = ["a", "b", "c"]`
|
||||
* `[["a"], [], ["b", "c"], ["d", "e", "f"]].flattenTR = ["a", "b", "c", "d", "e", "f"]`
|
||||
-/
|
||||
@[inline] def flattenTR (l : List (List α)) : List α := l.flatMapTR id
|
||||
|
||||
@[csimp] theorem flatten_eq_flattenTR : @flatten = @flattenTR := by
|
||||
|
|
@ -124,7 +175,16 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### take -/
|
||||
|
||||
/-- Tail recursive version of `List.take`. -/
|
||||
/--
|
||||
Extracts the first `n` elements of `xs`, or the whole list if `n` is greater than `xs.length`.
|
||||
|
||||
`O(min n |xs|)`. This is a tail-recursive version of `List.take`, used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c, d, e].takeTR 0 = []`
|
||||
* `[a, b, c, d, e].takeTR 3 = [a, b, c]`
|
||||
* `[a, b, c, d, e].takeTR 6 = [a, b, c, d, e]`
|
||||
-/
|
||||
@[inline] def takeTR (n : Nat) (l : List α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `take`: `take.go l xs n acc = acc.toList ++ take n xs`,
|
||||
unless `n ≥ xs.length` in which case it returns `l`. -/
|
||||
|
|
@ -146,7 +206,17 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### takeWhile -/
|
||||
|
||||
/-- Tail recursive version of `List.takeWhile`. -/
|
||||
|
||||
/--
|
||||
Returns the longest initial segment of `xs` for which `p` returns true.
|
||||
|
||||
`O(|xs|)`. This is a tail-recursive version of `List.take`, used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 4, 8].takeWhileTR (· > 5) = [7, 6]`
|
||||
* `[7, 6, 6, 5].takeWhileTR (· > 5) = [7, 6, 6]`
|
||||
* `[7, 6, 6, 8].takeWhileTR (· > 5) = [7, 6, 6, 8]`
|
||||
-/
|
||||
@[inline] def takeWhileTR (p : α → Bool) (l : List α) : List α := go l #[] where
|
||||
/-- Auxiliary for `takeWhile`: `takeWhile.go p l xs acc = acc.toList ++ takeWhile p xs`,
|
||||
unless no element satisfying `p` is found in `xs` in which case it returns `l`. -/
|
||||
|
|
@ -169,7 +239,16 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### dropLast -/
|
||||
|
||||
/-- Tail recursive version of `dropLast`. -/
|
||||
/--
|
||||
Removes the last element of the list, if one exists.
|
||||
|
||||
This is a tail-recursive version of `List.dropLast`, used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[].dropLastTR = []`
|
||||
* `["tea"].dropLastTR = []`
|
||||
* `["tea", "coffee", "juice"].dropLastTR = ["tea", "coffee"]`
|
||||
-/
|
||||
@[inline] def dropLastTR (l : List α) : List α := l.toArray.pop.toList
|
||||
|
||||
@[csimp] theorem dropLast_eq_dropLastTR : @dropLast = @dropLastTR := by
|
||||
|
|
@ -179,7 +258,16 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### replace -/
|
||||
|
||||
/-- Tail recursive version of `List.replace`. -/
|
||||
/--
|
||||
Replaces the first element of the list `l` that is equal to `a` with `b`. If no element is equal to
|
||||
`a`, then the list is returned unchanged.
|
||||
|
||||
`O(|l|)`. This is a tail-recursive version of `List.replace` that's used in runtime code.
|
||||
|
||||
Examples:
|
||||
* `[1, 4, 2, 3, 3, 7].replaceTR 3 6 = [1, 4, 2, 6, 3, 7]`
|
||||
* `[1, 4, 2, 3, 3, 7].replaceTR 5 6 = [1, 4, 2, 3, 3, 7]`
|
||||
-/
|
||||
@[inline] def replaceTR [BEq α] (l : List α) (b c : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `replace`: `replace.go l b c xs acc = acc.toList ++ replace xs b c`,
|
||||
unless `b` is not found in `xs` in which case it returns `l`. -/
|
||||
|
|
@ -202,7 +290,16 @@ The following operations are given `@[csimp]` replacements below:
|
|||
|
||||
/-! ### modify -/
|
||||
|
||||
/-- Tail-recursive version of `modify`. -/
|
||||
/--
|
||||
Replaces the element at the given index, if it exists, with the result of applying `f` to it.
|
||||
|
||||
This is a tail-recursive version of `List.modify`.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3].modifyTR (· * 10) 0 = [10, 2, 3]`
|
||||
* `[1, 2, 3].modifyTR (· * 10) 2 = [1, 2, 30]`
|
||||
* `[1, 2, 3].modifyTR (· * 10) 3 = [1, 2, 3]`
|
||||
-/
|
||||
def modifyTR (f : α → α) (n : Nat) (l : List α) : List α := go l n #[] where
|
||||
/-- Auxiliary for `modifyTR`: `modifyTR.go f l n acc = acc.toList ++ modify f n l`. -/
|
||||
go : List α → Nat → Array α → List α
|
||||
|
|
@ -220,8 +317,22 @@ theorem modifyTR_go_eq : ∀ l i, modifyTR.go f l i acc = acc.toList ++ modify f
|
|||
|
||||
/-! ### insertIdx -/
|
||||
|
||||
/-- Tail-recursive version of `insertIdx`. -/
|
||||
@[inline] def insertIdxTR (n : Nat) (a : α) (l : List α) : List α := go n l #[] where
|
||||
/--
|
||||
Inserts an element into a list at the specified index. If the index is greater than the length of
|
||||
the list, then the list is returned unmodified.
|
||||
|
||||
In other words, the new element is inserted into the list `l` after the first `i` elements of `l`.
|
||||
|
||||
This is a tail-recursive version of `List.insertIdx`, used at runtime.
|
||||
|
||||
Examples:
|
||||
* `["tues", "thur", "sat"].insertIdxTR 1 "wed" = ["tues", "wed", "thur", "sat"]`
|
||||
* `["tues", "thur", "sat"].insertIdxTR 2 "wed" = ["tues", "thur", "wed", "sat"]`
|
||||
* `["tues", "thur", "sat"].insertIdxTR 3 "wed" = ["tues", "thur", "sat", "wed"]`
|
||||
* `["tues", "thur", "sat"].insertIdxTR 4 "wed" = ["tues", "thur", "sat"]`
|
||||
|
||||
-/
|
||||
@[inline] def insertIdxTR (i : Nat) (a : α) (l : List α) : List α := go i l #[] where
|
||||
/-- Auxiliary for `insertIdxTR`: `insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l`. -/
|
||||
go : Nat → List α → Array α → List α
|
||||
| 0, l, acc => acc.toListAppend (a :: l)
|
||||
|
|
@ -237,7 +348,18 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
|
|||
|
||||
/-! ### erase -/
|
||||
|
||||
/-- Tail recursive version of `List.erase`. -/
|
||||
/--
|
||||
Removes the first occurrence of `a` from `l`. If `a` does not occur in `l`, the list is returned
|
||||
unmodified.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
This is a tail-recursive version of `List.erase`, used in runtime code.
|
||||
|
||||
Examples:
|
||||
* `[1, 5, 3, 2, 5].eraseTR 5 = [1, 3, 2, 5]`
|
||||
* `[1, 5, 3, 2, 5].eraseTR 6 = [1, 5, 3, 2, 5]`
|
||||
-/
|
||||
@[inline] def eraseTR [BEq α] (l : List α) (a : α) : List α := go l #[] where
|
||||
/-- Auxiliary for `eraseTR`: `eraseTR.go l a xs acc = acc.toList ++ erase xs a`,
|
||||
unless `a` is not present in which case it returns `l` -/
|
||||
|
|
@ -257,7 +379,17 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
|
|||
· rw [IH] <;> simp_all
|
||||
· simp
|
||||
|
||||
/-- Tail-recursive version of `eraseP`. -/
|
||||
/--
|
||||
Removes the first element of a list for which `p` returns `true`. If no element satisfies `p`, then
|
||||
the list is returned unchanged.
|
||||
|
||||
This is a tail-recursive version of `eraseP`, used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[2, 1, 2, 1, 3, 4].erasePTR (· < 2) = [2, 2, 1, 3, 4]`
|
||||
* `[2, 1, 2, 1, 3, 4].erasePTR (· > 2) = [2, 1, 2, 1, 4]`
|
||||
* `[2, 1, 2, 1, 3, 4].erasePTR (· > 8) = [2, 1, 2, 1, 3, 4]`
|
||||
-/
|
||||
@[inline] def erasePTR (p : α → Bool) (l : List α) : List α := go l #[] where
|
||||
/-- Auxiliary for `erasePTR`: `erasePTR.go p l xs acc = acc.toList ++ eraseP p xs`,
|
||||
unless `xs` does not contain any elements satisfying `p`, where it returns `l`. -/
|
||||
|
|
@ -277,7 +409,20 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
|
|||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
/-- Tail recursive version of `List.eraseIdx`. -/
|
||||
|
||||
/--
|
||||
Removes the element at the specified index. If the index is out of bounds, the list is returned
|
||||
unmodified.
|
||||
|
||||
`O(i)`.
|
||||
|
||||
This is a tail-recursive version of `List.eraseIdx`, used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[0, 1, 2, 3, 4].eraseIdxTR 0 = [1, 2, 3, 4]`
|
||||
* `[0, 1, 2, 3, 4].eraseIdxTR 1 = [0, 2, 3, 4]`
|
||||
* `[0, 1, 2, 3, 4].eraseIdxTR 5 = [0, 1, 2, 3, 4]`
|
||||
-/
|
||||
@[inline] def eraseIdxTR (l : List α) (n : Nat) : List α := go l n #[] where
|
||||
/-- Auxiliary for `eraseIdxTR`: `eraseIdxTR.go l n xs acc = acc.toList ++ eraseIdx xs a`,
|
||||
unless `a` is not present in which case it returns `l` -/
|
||||
|
|
@ -303,7 +448,18 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
|
|||
|
||||
/-! ### zipWith -/
|
||||
|
||||
/-- Tail recursive version of `List.zipWith`. -/
|
||||
/--
|
||||
Applies a function to the corresponding elements of two lists, stopping at the end of the shorter
|
||||
list.
|
||||
|
||||
`O(min |xs| |ys|)`. This is a tail-recursive version of `List.zipWith` that's used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[1, 2].zipWithTR (· + ·) [5, 6] = [6, 8]`
|
||||
* `[1, 2, 3].zipWithTR (· + ·) [5, 6, 10] = [6, 8, 13]`
|
||||
* `[].zipWithTR (· + ·) [5, 6] = []`
|
||||
* `[x₁, x₂, x₃].zipWithTR f [y₁, y₂, y₃, y₄] = [f x₁ y₁, f x₂ y₂, f x₃ y₃]`
|
||||
-/
|
||||
@[inline] def zipWithTR (f : α → β → γ) (as : List α) (bs : List β) : List γ := go as bs #[] where
|
||||
/-- Auxiliary for `zipWith`: `zipWith.go f as bs acc = acc.toList ++ zipWith f as bs` -/
|
||||
go : List α → List β → Array γ → List γ
|
||||
|
|
@ -321,7 +477,16 @@ theorem insertIdxTR_go_eq : ∀ i l, insertIdxTR.go a i l acc = acc.toList ++ in
|
|||
|
||||
/-! ### zipIdx -/
|
||||
|
||||
/-- Tail recursive version of `List.zipIdx`. -/
|
||||
|
||||
/--
|
||||
Pairs each element of a list with its index, optionally starting from an index other than `0`.
|
||||
|
||||
`O(|l|)`. This is a tail-recursive version of `List.zipIdx` that's used at runtime.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].zipIdxTR = [(a, 0), (b, 1), (c, 2)]`
|
||||
* `[a, b, c].zipIdxTR 5 = [(a, 5), (b, 6), (c, 7)]`
|
||||
-/
|
||||
def zipIdxTR (l : List α) (n : Nat := 0) : List (α × Nat) :=
|
||||
let as := l.toArray
|
||||
(as.foldr (fun a (n, acc) => (n-1, (a, n-1) :: acc)) (n + as.size, [])).2
|
||||
|
|
@ -363,8 +528,18 @@ theorem enumFrom_eq_enumFromTR : @enumFrom = @enumFromTR := by
|
|||
/-! ### intercalate -/
|
||||
|
||||
set_option linter.listVariables false in
|
||||
/-- Tail recursive version of `List.intercalate`. -/
|
||||
def intercalateTR (sep : List α) : List (List α) → List α
|
||||
/--
|
||||
Alternates the lists in `xs` with the separator `sep`.
|
||||
|
||||
This is a tail-recursive version of `List.intercalate` used at runtime.
|
||||
|
||||
Examples:
|
||||
* `List.intercalateTR sep [] = []`
|
||||
* `List.intercalateTR sep [a] = a`
|
||||
* `List.intercalateTR sep [a, b] = a ++ sep ++ b`
|
||||
* `List.intercalateTR sep [a, b, c] = a ++ sep ++ b ++ sep ++ c`
|
||||
-/
|
||||
def intercalateTR (sep : List α) : (xs : List (List α)) → List α
|
||||
| [] => []
|
||||
| [x] => x
|
||||
| x::xs => go sep.toArray x xs #[]
|
||||
|
|
|
|||
|
|
@ -2697,12 +2697,20 @@ theorem foldr_hom (f : β₁ → β₂) (g₁ : α → β₁ → β₁) (g₂ :
|
|||
induction l <;> simp [*, H]
|
||||
|
||||
/--
|
||||
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.
|
||||
A reasoning principle for proving propositions about the result of `List.foldl` by establishing an
|
||||
invariant that is true for the initial data and preserved by the operation being folded.
|
||||
|
||||
The motive can take values in `Sort _`, so this may be used to construct data,
|
||||
as well as to prove propositions.
|
||||
Because the motive can return a type in any sort, this function may be used to construct data as
|
||||
well as to prove propositions.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
example {xs : List Nat} : xs.foldl (· + ·) 1 > 0 := by
|
||||
apply List.foldlRecOn
|
||||
. show 0 < 1; trivial
|
||||
. show ∀ (b : Nat), 0 < b → ∀ (a : Nat), a ∈ xs → 0 < b + a
|
||||
intros; omega
|
||||
```
|
||||
-/
|
||||
def foldlRecOn {motive : β → Sort _} : ∀ (l : List α) (op : β → α → β) (b : β) (_ : motive b)
|
||||
(_ : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ l), motive (op b a)), motive (List.foldl op b l)
|
||||
|
|
@ -2723,12 +2731,20 @@ def foldlRecOn {motive : β → Sort _} : ∀ (l : List α) (op : β → α →
|
|||
rfl
|
||||
|
||||
/--
|
||||
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.
|
||||
A reasoning principle for proving propositions about the result of `List.foldr` by establishing an
|
||||
invariant that is true for the initial data and preserved by the operation being folded.
|
||||
|
||||
The motive can take values in `Sort _`, so this may be used to construct data,
|
||||
as well as to prove propositions.
|
||||
Because the motive can return a type in any sort, this function may be used to construct data as
|
||||
well as to prove propositions.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
example {xs : List Nat} : xs.foldr (· + ·) 1 > 0 := by
|
||||
apply List.foldrRecOn
|
||||
. show 0 < 1; trivial
|
||||
. show ∀ (b : Nat), 0 < b → ∀ (a : Nat), a ∈ xs → 0 < a + b
|
||||
intros; omega
|
||||
```
|
||||
-/
|
||||
def foldrRecOn {motive : β → Sort _} : ∀ (l : List α) (op : α → β → β) (b : β) (_ : motive b)
|
||||
(_ : ∀ (b : β) (_ : motive b) (a : α) (_ : a ∈ l), motive (op a b)), motive (List.foldr op b l)
|
||||
|
|
|
|||
|
|
@ -19,8 +19,11 @@ namespace List
|
|||
/-! ## Operations using indexes -/
|
||||
|
||||
/--
|
||||
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₁ ⋯, ...]`.
|
||||
Applies a function to each element of the list along with the index at which that element is found,
|
||||
returning the list of results. In addition to the index, the function is also provided with a proof
|
||||
that the index is valid.
|
||||
|
||||
`List.mapIdx` is a variant that does not provide the function with evidence that the index is valid.
|
||||
-/
|
||||
@[inline] def mapFinIdx (as : List α) (f : (i : Nat) → α → (h : i < as.length) → β) : List β :=
|
||||
go as #[] (by simp)
|
||||
|
|
@ -33,8 +36,11 @@ where
|
|||
go as (acc.push (f acc.size a (by simp at h; omega))) (by simp at h ⊢; omega)
|
||||
|
||||
/--
|
||||
Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁, ...]`, returns the list
|
||||
`[f 0 a₀, f 1 a₁, ...]`.
|
||||
Applies a function to each element of the list along with the index at which that element is found,
|
||||
returning the list of results.
|
||||
|
||||
`List.mapFinIdx` is a variant that additionally provides the function with a proof that the index
|
||||
is valid.
|
||||
-/
|
||||
@[inline] def mapIdx (f : Nat → α → β) (as : List α) : List β := go as #[] where
|
||||
/-- Auxiliary for `mapIdx`:
|
||||
|
|
@ -44,8 +50,12 @@ Given a function `f : Nat → α → β` and `as : List α`, `as = [a₀, a₁,
|
|||
| a :: as, acc => go as (acc.push (f acc.size a))
|
||||
|
||||
/--
|
||||
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₁ ⋯, ...]`.
|
||||
Applies a monadic function to each element of the list along with the index at which that element is
|
||||
found, returning the list of results. In addition to the index, the function is also provided with a
|
||||
proof that the index is valid.
|
||||
|
||||
`List.mapIdxM` is a variant that does not provide the function with evidence that the index is
|
||||
valid.
|
||||
-/
|
||||
@[inline] def mapFinIdxM [Monad m] (as : List α) (f : (i : Nat) → α → (h : i < as.length) → m β) : m (List β) :=
|
||||
go as #[] (by simp)
|
||||
|
|
@ -58,8 +68,11 @@ where
|
|||
go as (acc.push (← f acc.size a (by simp at h; omega))) (by simp at h ⊢; omega)
|
||||
|
||||
/--
|
||||
Given a monadic function `f : Nat → α → m β` and `as : List α`, `as = [a₀, a₁, ...]`,
|
||||
returns the list `[f 0 a₀, f 1 a₁, ...]`.
|
||||
Applies a monadic function to each element of the list along with the index at which that element is
|
||||
found, returning the list of results.
|
||||
|
||||
`List.mapFinIdxM` is a variant that additionally provides the function with a proof that the index
|
||||
is valid.
|
||||
-/
|
||||
@[inline] def mapIdxM [Monad m] (f : Nat → α → m β) (as : List α) : m (List β) := go as #[] where
|
||||
/-- Auxiliary for `mapIdxM`:
|
||||
|
|
|
|||
|
|
@ -31,10 +31,13 @@ attribute [simp] mapA forA filterAuxM firstM anyM allM findM? findSomeM?
|
|||
|
||||
/-! ### mapM -/
|
||||
|
||||
/-- Alternate (non-tail-recursive) form of mapM for proofs.
|
||||
/--
|
||||
Applies the monadic action `f` on every element in the list, left-to-right, and returns the list of
|
||||
results.
|
||||
|
||||
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`.
|
||||
This is a non-tail-recursive variant of `List.mapM` that's easier to reason about. It cannot be used
|
||||
as the main definition and replaced by the tail-recursive version because they can only be proved
|
||||
equal when `m` is a `LawfulMonad`.
|
||||
-/
|
||||
def mapM' [Monad m] (f : α → m β) : List α → m (List β)
|
||||
| [] => pure []
|
||||
|
|
|
|||
|
|
@ -17,10 +17,11 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
|||
namespace 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)]
|
||||
```
|
||||
Creates a list by applying `f` to each potential index in order, starting at `0`.
|
||||
|
||||
Examples:
|
||||
* `List.ofFn (n := 3) toString = ["0", "1", "2"]`
|
||||
* `List.ofFn (fun i => #["red", "green", "blue"].get i.val i.isLt) = ["red", "green", "blue"]`
|
||||
-/
|
||||
def ofFn {n} (f : Fin n → α) : List α := Fin.foldr n (f · :: ·) []
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,14 @@ set_option linter.indexVariables true -- Enforce naming conventions for index va
|
|||
namespace List
|
||||
|
||||
/--
|
||||
`O(min |l| |r|)`. Merge two lists using `le` as a switch.
|
||||
Merges two lists, using `le` to select the first element of the resulting list if both are
|
||||
non-empty.
|
||||
|
||||
This version is not tail-recursive,
|
||||
but it is replaced at runtime by `mergeTR` using a `@[csimp]` lemma.
|
||||
If both input lists are sorted according to `le`, then the resulting list is also sorted according
|
||||
to `le`. `O(min |l| |r|)`.
|
||||
|
||||
This implementation is not tail-recursive, but it is replaced at runtime by a proven-equivalent
|
||||
tail-recursive merge.
|
||||
-/
|
||||
def merge (xs ys : List α) (le : α → α → Bool := by exact fun a b => a ≤ b) : List α :=
|
||||
match xs, ys with
|
||||
|
|
@ -54,16 +58,16 @@ def MergeSort.Internal.splitInTwo (l : { l : List α // l.length = n }) :
|
|||
open MergeSort.Internal in
|
||||
set_option linter.unusedVariables false in
|
||||
/--
|
||||
Simplified implementation of stable merge sort.
|
||||
A 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.
|
||||
This function is a simplified implementation that's designed to be easy to reason about, rather than
|
||||
for efficiency. In particular, it uses the non-tail-recursive `List.merge` function and traverses
|
||||
lists unnecessarily.
|
||||
|
||||
Because we want the sort to be stable,
|
||||
it is essential that we split the list in two contiguous sublists.
|
||||
It is replaced at runtime by an efficient implementation that has been proven to be equivalent.
|
||||
-/
|
||||
-- Because we want the sort to be stable, it is essential that we split the list in two contiguous
|
||||
-- sublists.
|
||||
def mergeSort : ∀ (xs : List α) (le : α → α → Bool := by exact fun a b => a ≤ b), List α
|
||||
| [], _ => []
|
||||
| [a], _ => [a]
|
||||
|
|
|
|||
|
|
@ -18,7 +18,13 @@ def List.toArrayAux : List α → Array α → Array α
|
|||
| nil, xs => xs
|
||||
| cons a as, xs => toArrayAux as (xs.push a)
|
||||
|
||||
/-- Convert a `List α` into an `Array α`. This is O(n) in the length of the list. -/
|
||||
/--
|
||||
Converts a `List α` into an `Array α` by repeatedly pushing elements from the list onto an empty
|
||||
array. `O(|xs|)`.
|
||||
|
||||
Use `List.toArray` instead of calling this function directly. At runtime, this operation implements
|
||||
both `List.toArray` and `Array.mk`.
|
||||
-/
|
||||
-- This function is exported to C, where it is called by `Array.mk`
|
||||
-- (the constructor) to implement this functionality.
|
||||
@[inline, match_pattern, pp_nodot, export lean_list_to_array]
|
||||
|
|
|
|||
|
|
@ -9,6 +9,14 @@ import Init.Data.Char.Basic
|
|||
|
||||
universe u
|
||||
|
||||
/--
|
||||
Creates a string that contains the characters in a list, in order.
|
||||
|
||||
Examples:
|
||||
* `['L', '∃', '∀', 'N'].asString = "L∃∀N"`
|
||||
* `[].asString = ""`
|
||||
* `['a', 'a', 'a'].asString = "aaa"`
|
||||
-/
|
||||
def List.asString (s : List Char) : String :=
|
||||
⟨s⟩
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,20 @@ instance {p : Prop} : ToString (Decidable p) := ⟨fun h =>
|
|||
| Decidable.isTrue _ => "true"
|
||||
| Decidable.isFalse _ => "false"⟩
|
||||
|
||||
/--
|
||||
Converts a list into a string, using `ToString.toString` to convert its elements.
|
||||
|
||||
The resulting string resembles list literal syntax, with the elements separated by `", "` and
|
||||
enclosed in square brackets.
|
||||
|
||||
The resulting string may not be valid Lean syntax, because there's no such expectation for
|
||||
`ToString` instances.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3].toString = "[1, 2, 3]"`
|
||||
* `["cat", "dog"].toString = "[cat, dog]"`
|
||||
* `["cat", "dog", ""].toString = "[cat, dog, ]"`
|
||||
-/
|
||||
protected def List.toString [ToString α] : List α → String
|
||||
| [] => "[]"
|
||||
| [x] => "[" ++ toString x ++ "]"
|
||||
|
|
|
|||
|
|
@ -2407,21 +2407,24 @@ Examples:
|
|||
| none => none
|
||||
|
||||
/--
|
||||
`List α` is the type of ordered lists with elements of type `α`.
|
||||
It is implemented as a linked list.
|
||||
Linked lists: ordered lists, in which each element has a reference to the next element.
|
||||
|
||||
Most operations on linked lists take time proportional to the length of the list, because each
|
||||
element must be traversed to find the next element.
|
||||
|
||||
`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.
|
||||
* `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.
|
||||
-/
|
||||
inductive List (α : Type u) where
|
||||
/-- `[]` is the empty list. -/
|
||||
/-- The empty list, usually written `[]`. -/
|
||||
| nil : 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. -/
|
||||
/--
|
||||
The list whose first element is `head`, where `tail` is the rest of the list.
|
||||
Usually written `head :: tail`.
|
||||
-/
|
||||
| cons (head : α) (tail : List α) : List α
|
||||
|
||||
instance {α} : Inhabited (List α) where
|
||||
|
|
@ -2443,11 +2446,13 @@ protected def List.hasDecEq {α : Type u} [DecidableEq α] : (a b : List α) →
|
|||
instance {α : Type u} [DecidableEq α] : DecidableEq (List α) := List.hasDecEq
|
||||
|
||||
/--
|
||||
The length of a list: `[].length = 0` and `(a :: l).length = l.length + 1`.
|
||||
The length of a list.
|
||||
|
||||
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.
|
||||
This function is overridden in the compiler to `lengthTR`, which uses constant stack space.
|
||||
|
||||
Examples:
|
||||
* `([] : List String).length = 0`
|
||||
* `["green", "brown"].length = 2`
|
||||
-/
|
||||
def List.length : List α → Nat
|
||||
| nil => 0
|
||||
|
|
@ -2459,40 +2464,69 @@ def List.lengthTRAux : List α → Nat → Nat
|
|||
| cons _ as, n => lengthTRAux as (Nat.succ n)
|
||||
|
||||
/--
|
||||
A tail-recursive version of `List.length`, used to implement `List.length`
|
||||
without running out of stack space.
|
||||
The length of a list.
|
||||
|
||||
This is a tail-recursive version of `List.length`, used to implement `List.length` without running
|
||||
out of stack space.
|
||||
|
||||
Examples:
|
||||
* `([] : List String).lengthTR = 0`
|
||||
* `["green", "brown"].lengthTR = 2`
|
||||
-/
|
||||
def List.lengthTR (as : List α) : Nat :=
|
||||
lengthTRAux as 0
|
||||
|
||||
/--
|
||||
`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.
|
||||
Returns the element at the provided index, counting from `0`.
|
||||
|
||||
In other words, for `i : Fin as.length`, `as.get i` returns the `i`'th element of the list `as`.
|
||||
Because the index is a `Fin` bounded by the list's length, the index will never be out of bounds.
|
||||
|
||||
Examples:
|
||||
* `["spring", "summer", "fall", "winter"].get (2 : Fin 4) = "fall"`
|
||||
* `["spring", "summer", "fall", "winter"].get (0 : Fin 4) = "spring"`
|
||||
-/
|
||||
def List.get {α : Type u} : (as : List α) → Fin as.length → α
|
||||
| cons a _, ⟨0, _⟩ => a
|
||||
| cons _ as, ⟨Nat.succ i, h⟩ => get as ⟨i, Nat.le_of_succ_le_succ h⟩
|
||||
|
||||
/--
|
||||
`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]`
|
||||
Replaces the value at (zero-based) index `n` in `l` with `a`. If the index is out of bounds, then
|
||||
the list is returned unmodified.
|
||||
|
||||
Examples:
|
||||
* `["water", "coffee", "soda", "juice"].set 1 "tea" = ["water", "tea", "soda", "juice"]`
|
||||
* `["water", "coffee", "soda", "juice"].set 4 "tea" = ["water", "coffee", "soda", "juice"]`
|
||||
-/
|
||||
def List.set : List α → Nat → α → List α
|
||||
def List.set : (l : List α) → (n : Nat) → (a : α) → List α
|
||||
| cons _ as, 0, b => cons b as
|
||||
| cons a as, Nat.succ n, b => cons a (set as n b)
|
||||
| nil, _, _ => nil
|
||||
|
||||
/--
|
||||
Folds a function over a list from the left:
|
||||
`foldl f z [a, b, c] = f (f (f z a) b) c`
|
||||
Folds a function over a list from the left, accumulating a value starting with `init`. The
|
||||
accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
Examples:
|
||||
* `[a, b, c].foldl f z = f (f (f z a) b) c`
|
||||
* `[1, 2, 3].foldl (· ++ toString ·) "" = "123"`
|
||||
* `[1, 2, 3].foldl (s!"({·} {·})") "" = "((( 1) 2) 3)"`
|
||||
-/
|
||||
@[specialize]
|
||||
def List.foldl {α : Type u} {β : Type v} (f : α → β → α) : (init : α) → List β → α
|
||||
| a, nil => a
|
||||
| a, cons b l => foldl f (f a b) l
|
||||
|
||||
/-- `l.concat a` appends `a` at the *end* of `l`, that is, `l ++ [a]`. -/
|
||||
/--
|
||||
Adds an element to the *end* of a list.
|
||||
|
||||
The added element is the last element of the resulting list.
|
||||
|
||||
Examples:
|
||||
* `List.concat ["red", "yellow"] "green" = ["red", "yellow", "green"]`
|
||||
* `List.concat [1, 2, 3] 4 = [1, 2, 3, 4]`
|
||||
* `List.concat [] () = [()]`
|
||||
-/
|
||||
def List.concat {α : Type u} : List α → α → List α
|
||||
| nil, b => cons b nil
|
||||
| cons a as, b => cons a (concat as b)
|
||||
|
|
@ -2718,10 +2752,14 @@ attribute [extern "lean_array_to_list"] Array.toList
|
|||
attribute [extern "lean_array_mk"] Array.mk
|
||||
|
||||
/--
|
||||
Converts a `List α` into an `Array α`. (This is preferred over the synonym `Array.mk`.)
|
||||
Converts a `List α` into an `Array α`. `O(|xs|)`.
|
||||
|
||||
At runtime, this constructor is implemented by `List.toArrayImpl` and is O(n) in the length of the
|
||||
list.
|
||||
At runtime, this operation is implemented by `List.toArrayImpl` and takes time linear in the length
|
||||
of the list. `List.toArray` should be used instead of `Array.mk`.
|
||||
|
||||
Examples:
|
||||
* `[1, 2, 3].toArray = #[1, 2, 3]`
|
||||
* `["monday", "wednesday", friday"].toArray = #["monday", "wednesday", friday"].`
|
||||
-/
|
||||
@[match_pattern]
|
||||
abbrev List.toArray (xs : List α) : Array α := .mk xs
|
||||
|
|
|
|||
|
|
@ -381,6 +381,9 @@ end Lean
|
|||
|
||||
open Lean (PersistentArray)
|
||||
|
||||
/--
|
||||
Converts a list to a persistent array.
|
||||
-/
|
||||
def List.toPArray' {α : Type u} (xs : List α) : PersistentArray α :=
|
||||
let rec loop : List α → PersistentArray α → PersistentArray α
|
||||
| [], t => t
|
||||
|
|
|
|||
|
|
@ -312,8 +312,16 @@ def Array.groupByKey [BEq α] [Hashable α] (key : β → α) (xs : Array β)
|
|||
return groups
|
||||
|
||||
/--
|
||||
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`.
|
||||
Groups the elements of a list `xs` according to the function `key`, returning a hash map in which
|
||||
each group is associated with its key. Groups preserve the relative order of elements in `xs`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [0, 1, 2, 3, 4, 5, 6].groupByKey (· % 2)
|
||||
```
|
||||
```output
|
||||
Std.HashMap.ofList [(0, [0, 2, 4, 6]), (1, [1, 3, 5])]
|
||||
```
|
||||
-/
|
||||
def List.groupByKey [BEq α] [Hashable α] (key : β → α) (xs : List β) :
|
||||
Std.HashMap α (List β) :=
|
||||
|
|
|
|||
|
|
@ -612,7 +612,7 @@
|
|||
"end": {"line": 290, "character": 16}},
|
||||
"contents":
|
||||
{"value":
|
||||
"```lean\nList.nil.{u} {α : Type u} : List α\n```\n***\n`[]` is the empty list. \n\nConventions for notations in identifiers:\n\n * The recommended spelling of `[]` in identifiers is `nil`.\n***\n*import Init.Prelude*",
|
||||
"```lean\nList.nil.{u} {α : Type u} : List α\n```\n***\nThe empty list, usually written `[]`. \n\nConventions for notations in identifiers:\n\n * The recommended spelling of `[]` in identifiers is `nil`.\n***\n*import Init.Prelude*",
|
||||
"kind": "markdown"}}
|
||||
{"textDocument": {"uri": "file:///hover.lean"},
|
||||
"position": {"line": 292, "character": 13}}
|
||||
|
|
@ -621,7 +621,7 @@
|
|||
"end": {"line": 292, "character": 15}},
|
||||
"contents":
|
||||
{"value":
|
||||
"```lean\nList.cons.{u} {α : Type u} (head : α) (tail : List α) : List α\n```\n***\nIf `a : α` and `l : List α`, then `cons a l`, or `a :: l`, is the\nlist whose first element is `a` and with `l` as the rest of the list. \n\nConventions for notations in identifiers:\n\n * The recommended spelling of `::` in identifiers is `cons`.\n\n * The recommended spelling of `[a]` in identifiers is `singleton`.\n***\n*import Init.Prelude*",
|
||||
"```lean\nList.cons.{u} {α : Type u} (head : α) (tail : List α) : List α\n```\n***\nThe list whose first element is `head`, where `tail` is the rest of the list.\nUsually written `head :: tail`.\n\n\nConventions for notations in identifiers:\n\n * The recommended spelling of `::` in identifiers is `cons`.\n\n * The recommended spelling of `[a]` in identifiers is `singleton`.\n***\n*import Init.Prelude*",
|
||||
"kind": "markdown"}}
|
||||
{"textDocument": {"uri": "file:///hover.lean"},
|
||||
"position": {"line": 294, "character": 18}}
|
||||
|
|
@ -630,7 +630,7 @@
|
|||
"end": {"line": 294, "character": 20}},
|
||||
"contents":
|
||||
{"value":
|
||||
"```lean\nList.map.{u, v} {α : Type u} {β : Type v} (f : α → β) : List α → List β\n```\n***\n`O(|l|)`. `map f l` applies `f` to each element of the list.\n* `map f [a, b, c] = [f a, f b, f c]`\n\n***\n*import Init.Data.List.Basic*",
|
||||
"```lean\nList.map.{u, v} {α : Type u} {β : Type v} (f : α → β) (l : List α) : List β\n```\n***\nApplies a function to each element of the list, returning the resulting list of values.\n\n`O(|l|)`.\n\nExamples:\n* `[a, b, c].map f = [f a, f b, f c]`\n* `[].map Nat.succ = []`\n* `[\"one\", \"two\", \"three\"].map (·.length) = [3, 3, 5]`\n* `[\"one\", \"two\", \"three\"].map (·.reverse) = [\"eno\", \"owt\", \"eerht\"]`\n\n***\n*import Init.Data.List.Basic*",
|
||||
"kind": "markdown"}}
|
||||
{"textDocument": {"uri": "file:///hover.lean"},
|
||||
"position": {"line": 297, "character": 26}}
|
||||
|
|
@ -639,7 +639,7 @@
|
|||
"end": {"line": 297, "character": 29}},
|
||||
"contents":
|
||||
{"value":
|
||||
"```lean\nList.zip.{u, v} {α : Type u} {β : Type v} : List α → List β → List (α × β)\n```\n***\n`O(min |xs| |ys|)`. Combines the two lists into a list of pairs, with one element from each list.\nThe longer list is truncated to match the shorter list.\n* `zip [x₁, x₂, x₃] [y₁, y₂, y₃, y₄] = [(x₁, y₁), (x₂, y₂), (x₃, y₃)]`\n\n***\n*import Init.Data.List.Basic*",
|
||||
"```lean\nList.zip.{u, v} {α : Type u} {β : Type v} : List α → List β → List (α × β)\n```\n***\nCombines two lists into a list of pairs in which the first and second components are the\ncorresponding elements of each list. The resulting list is the length of the shorter of the inputs\nlists.\n\n`O(min |xs| |ys|)`.\n\nExamples:\n* `[\"Mon\", \"Tue\", \"Wed\"].zip [1, 2, 3] = [(\"Mon\", 1), (\"Tue\", 2), (\"Wed\", 3)]`\n* `[\"Mon\", \"Tue\", \"Wed\"].zip [1, 2] = [(\"Mon\", 1), (\"Tue\", 2)]`\n* `[x₁, x₂, x₃].zip [y₁, y₂, y₃, y₄] = [(x₁, y₁), (x₂, y₂), (x₃, y₃)]`\n\n***\n*import Init.Data.List.Basic*",
|
||||
"kind": "markdown"}}
|
||||
{"textDocument": {"uri": "file:///hover.lean"},
|
||||
"position": {"line": 297, "character": 19}}
|
||||
|
|
@ -648,5 +648,5 @@
|
|||
"end": {"line": 297, "character": 22}},
|
||||
"contents":
|
||||
{"value":
|
||||
"```lean\nList.zip.{u, v} {α : Type u} {β : Type v} : List α → List β → List (α × β)\n```\n***\n`O(min |xs| |ys|)`. Combines the two lists into a list of pairs, with one element from each list.\nThe longer list is truncated to match the shorter list.\n* `zip [x₁, x₂, x₃] [y₁, y₂, y₃, y₄] = [(x₁, y₁), (x₂, y₂), (x₃, y₃)]`\n\n***\n*import Init.Data.List.Basic*",
|
||||
"```lean\nList.zip.{u, v} {α : Type u} {β : Type v} : List α → List β → List (α × β)\n```\n***\nCombines two lists into a list of pairs in which the first and second components are the\ncorresponding elements of each list. The resulting list is the length of the shorter of the inputs\nlists.\n\n`O(min |xs| |ys|)`.\n\nExamples:\n* `[\"Mon\", \"Tue\", \"Wed\"].zip [1, 2, 3] = [(\"Mon\", 1), (\"Tue\", 2), (\"Wed\", 3)]`\n* `[\"Mon\", \"Tue\", \"Wed\"].zip [1, 2] = [(\"Mon\", 1), (\"Tue\", 2)]`\n* `[x₁, x₂, x₃].zip [y₁, y₂, y₃, y₄] = [(x₁, y₁), (x₂, y₂), (x₃, y₃)]`\n\n***\n*import Init.Data.List.Basic*",
|
||||
"kind": "markdown"}}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue