Definitions on lists #
THIS FILE IS SYNCHRONIZED WITH MATHLIB4. Any changes to this file require a corresponding PR to mathlib4.
This file contains various definitions on lists. It does not contain
proofs about these definitions, those are contained in other files in data/list
Equations
- list.has_sdiff = {sdiff := list.diff (λ (a b : α), _inst_1 a b)}
Create a list of n
copies of a
. Same as function.swap list.repeat
.
Equations
- list.replicate n.succ a = a :: list.replicate n a
- list.replicate 0 _x = list.nil
Split a list at an index.
split_at 2 [a, b, c] = ([a, b], [c])
Equations
- list.split_at n.succ (x :: xs) = list.split_at._match_1 x (list.split_at n xs)
- list.split_at n.succ list.nil = (list.nil α, list.nil α)
- list.split_at 0 a = (list.nil α, a)
- list.split_at._match_1 x (l, r) = (x :: l, r)
An auxiliary function for split_on_p
.
Equations
- list.split_on_p_aux P (h :: t) f = ite (P h) (f list.nil :: list.split_on_p_aux P t id) (list.split_on_p_aux P t (λ (l : list α), f (h :: l)))
- list.split_on_p_aux P list.nil f = [f list.nil]
Split a list at every element satisfying a predicate.
Equations
- list.split_on_p P l = list.split_on_p_aux P l id
Split a list at every occurrence of an element.
[1,1,2,3,2,4,4].split_on 2 = [[1,1],[3],[4,4]]
Equations
- list.split_on a as = list.split_on_p (λ (_x : α), _x = a) as
head' xs
returns the first element of xs
if xs
is non-empty;
it returns none
otherwise
Equations
- (a :: l).head' = option.some a
- list.nil.head' = option.none
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.
modify_nth_tail f 2 [a, b, c] = [a, b] ++ f [c]
Equations
- list.modify_nth_tail f (n + 1) (a :: l) = a :: list.modify_nth_tail f n l
- list.modify_nth_tail f (n + 1) list.nil = list.nil
- list.modify_nth_tail f 0 l = f l
Apply f
to the head of the list, if it exists.
Equations
- list.modify_head f (a :: l) = f a :: l
- list.modify_head f list.nil = list.nil
Apply f
to the nth element of the list, if it exists.
Equations
Apply f
to the last element of l
, if it exists.
Equations
- list.modify_last f (x :: hd :: tl) = x :: list.modify_last f (hd :: tl)
- list.modify_last f [x] = [f x]
- list.modify_last f list.nil = list.nil
insert_nth n a l
inserts a
into the list l
after the first n
elements of l
insert_nth 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
Equations
- list.insert_nth n a = list.modify_nth_tail (list.cons a) n
Take n
elements from a list l
. If l
has less than n
elements, append n - length l
elements default
.
Equations
- list.take' (n + 1) l = l.head :: list.take' n l.tail
- list.take' 0 l = list.nil
Get the longest initial segment of the list whose members all satisfy p
.
take_while (λ x, x < 3) [0, 2, 5, 1] = [0, 2]
Equations
- list.take_while p (a :: l) = ite (p a) (a :: list.take_while p l) list.nil
- list.take_while p list.nil = list.nil
Fold a function f
over the list from the left, returning the list
of partial results.
scanl (+) 0 [1, 2, 3] = [0, 1, 3, 6]
Equations
- list.scanl f a (b :: l) = a :: list.scanl f (f a b) l
- list.scanl f a list.nil = [a]
Auxiliary definition used to define scanr
. If scanr_aux f b l = (b', l')
then scanr f b l = b' :: l'
Equations
- list.scanr_aux f b (a :: l) = list.scanr_aux._match_1 f a (list.scanr_aux f b l)
- list.scanr_aux f b list.nil = (b, list.nil β)
- list.scanr_aux._match_1 f a (b', l') = (f a b', b' :: l')
Fold a function f
over the list from the right, returning the list
of partial results.
scanr (+) 0 [1, 2, 3] = [6, 5, 3, 0]
Equations
- list.scanr f b l = list.scanr._match_1 (list.scanr_aux f b l)
- list.scanr._match_1 (b', l') = b' :: l'
The alternating sum of a list.
Equations
- (g :: h :: t).alternating_sum = g + -h + t.alternating_sum
- [g].alternating_sum = g
- list.nil.alternating_sum = 0
The alternating product of a list.
Equations
- (g :: h :: t).alternating_prod = g * h⁻¹ * t.alternating_prod
- [g].alternating_prod = g
- list.nil.alternating_prod = 1
Given a function f : α → β ⊕ γ
, partition_map f l
maps the list by f
whilst partitioning the result it into a pair of lists, list β × list γ
,
partitioning the sum.inl _
into the left list, and the sum.inr _
into the right list.
partition_map (id : ℕ ⊕ ℕ → ℕ ⊕ ℕ) [inl 0, inr 1, inl 2] = ([0,2], [1])
Equations
- list.partition_map f (x :: xs) = list.partition_map._match_1 (list.partition_map f xs) (list.partition_map f xs) (f x)
- list.partition_map f list.nil = (list.nil β, list.nil γ)
- list.partition_map._match_1 _f_1 _f_2 (sum.inr r) = prod.map id (list.cons r) _f_1
- list.partition_map._match_1 _f_1 _f_2 (sum.inl l) = prod.map (list.cons l) id _f_2
mfind tac l
returns the first element of l
on which tac
succeeds, and
fails otherwise.
Equations
- list.mfind tac = list.mfirst (λ (a : α), tac a $> a)
mbfind' p l
returns the first element a
of l
for which p a
returns
true. mbfind'
short-circuits, so p
is not necessarily run on every a
in
l
. This is a monadic version of list.find
.
Equations
- list.mbfind' p (x :: xs) = p x >>= λ (_p : ulift bool), list.mbfind'._match_1 x (list.mbfind' p xs) _p
- list.mbfind' p list.nil = has_pure.pure option.none
- list.mbfind'._match_1 x _f_1 {down := px} = ite ↥px (has_pure.pure (option.some x)) _f_1
A variant of mbfind'
with more restrictive universe levels.
Equations
- list.mbfind p xs = list.mbfind' (functor.map ulift.up ∘ p) xs
many p as
returns true iff p
returns true for any element of l
.
many
short-circuits, so if p
returns true for any element of l
, later
elements are not checked. This is a monadic version of list.any
.
mall p as
returns true iff p
returns true for all elements of l
.
mall
short-circuits, so if p
returns false for any element of l
, later
elements are not checked. This is a monadic version of list.all
.
mbor xs
runs the actions in xs
, returning true if any of them returns
true. mbor
short-circuits, so if an action returns true, later actions are
not run. This is a monadic version of list.bor
.
mband xs
runs the actions in xs
, returning true if all of them return
true. mband
short-circuits, so if an action returns false, later actions are
not run. This is a monadic version of list.band
.
Equations
Fold a list from left to right as with foldl
, but the combining function
also receives each element's index.
Equations
- list.foldl_with_index f a l = list.foldl_with_index_aux f 0 a l
Fold a list from right to left as with foldr
, but the combining function
also receives each element's index.
Equations
- list.foldr_with_index f b l = list.foldr_with_index_aux f 0 b l
find_indexes p l
is the list of indexes of elements of l
that satisfy p
.
Equations
- list.find_indexes p l = list.foldr_with_index (λ (i : ℕ) (a : α) (is : list ℕ), ite (p a) (i :: is) is) list.nil l
Returns the elements of l
that satisfy p
together with their indexes in
l
. The returned list is ordered by index.
Equations
- list.indexes_values p l = list.foldr_with_index (λ (i : ℕ) (a : α) (l : list (ℕ × α)), ite (p a) ((i, a) :: l) l) list.nil l
indexes_of a l
is the list of all indexes of a
in l
. For example:
indexes_of a [a, b, a, a] = [0, 2, 3]
Equations
- list.indexes_of a = list.find_indexes (eq a)
Monadic variant of foldl_with_index
.
Equations
- list.mfoldl_with_index f b as = list.foldl_with_index (λ (i : ℕ) (ma : m β) (b : α), ma >>= λ (a : β), f i a b) (has_pure.pure b) as
Monadic variant of foldr_with_index
.
Equations
- list.mfoldr_with_index f b as = list.foldr_with_index (λ (i : ℕ) (a : α) (mb : m β), mb >>= λ (b : β), f i a b) (has_pure.pure b) as
Auxiliary definition for mmap_with_index
.
Equations
- list.mmap_with_index_aux f i (a :: as) = list.cons <$> f i a <*> list.mmap_with_index_aux f (i + 1) as
- list.mmap_with_index_aux f _x list.nil = has_pure.pure list.nil
Applicative variant of map_with_index
.
Equations
- list.mmap_with_index f as = list.mmap_with_index_aux f 0 as
Auxiliary definition for mmap_with_index'
.
Equations
- list.mmap_with_index'_aux f i (a :: as) = f i a *> list.mmap_with_index'_aux f (i + 1) as
- list.mmap_with_index'_aux f _x list.nil = has_pure.pure punit.star
A variant of mmap_with_index
specialised to applicative actions which
return unit
.
Equations
- list.mmap_with_index' f as = list.mmap_with_index'_aux f 0 as
lookmap
is a combination of lookup
and filter_map
.
lookmap f l
will apply f : α → option α
to each element of the list,
replacing a → b
at the first value a
in the list such that f a = some b
.
Equations
- list.lookmap f (a :: l) = list.lookmap._match_1 a l (list.lookmap f l) (f a)
- list.lookmap f list.nil = list.nil
- list.lookmap._match_1 a l _f_1 (option.some b) = b :: l
- list.lookmap._match_1 a l _f_1 option.none = a :: _f_1
countp p l
is the number of elements of l
that satisfy p
.
Equations
- list.countp p (x :: xs) = ite (p x) (list.countp p xs).succ (list.countp p xs)
- list.countp p list.nil = 0
count a l
is the number of occurrences of a
in l
.
Equations
- list.count a = list.countp (eq a)
is_prefix l₁ l₂
, or l₁ <+: l₂
, means that l₁
is a prefix of l₂
,
that is, l₂
has the form l₁ ++ t
for some t
.
Instances for list.is_prefix
is_suffix l₁ l₂
, or l₁ <:+ l₂
, means that l₁
is a suffix of l₂
,
that is, l₂
has the form t ++ l₁
for some t
.
Instances for list.is_suffix
is_infix 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
.
Instances for list.is_infix
sublists' l
is the list of all (non-contiguous) sublists of l
.
It differs from sublists
only in the order of appearance of the sublists;
sublists'
uses the first element of the list as the MSB,
sublists
uses the first element of the list as the LSB.
sublists' [1, 2, 3] = [[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
Equations
sublists l
is the list of all (non-contiguous) sublists of l
; cf. sublists'
for a different ordering.
sublists [1, 2, 3] = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
- nil : ∀ {α : Type u_1} {β : Type u_2} {R : α → β → Prop}, list.forall₂ R list.nil list.nil
- cons : ∀ {α : Type u_1} {β : Type u_2} {R : α → β → Prop} {a : α} {b : β} {l₁ : list α} {l₂ : list β}, R a b → list.forall₂ R l₁ l₂ → list.forall₂ R (a :: l₁) (b :: l₂)
forall₂ R l₁ l₂
means that l₁
and l₂
have the same length,
and whenever a
is the nth element of l₁
, and b
is the nth element of l₂
,
then R a b
is satisfied.
l.all₂ p
is equivalent to ∀ a ∈ l, p a
, but unfolds directly to a conjunction, i.e.
list.all₂ p [0, 1, 2] = p 0 ∧ p 1 ∧ p 2
.
Equations
Instances for list.all₂
Auxiliary definition used to define transpose
.
transpose_aux l L
takes each element of l
and appends it to the start of
each element of L
.
transpose_aux [a, b, c] [l₁, l₂, l₃] = [a::l₁, b::l₂, c::l₃]
Equations
- (a :: i).transpose_aux (l :: ls) = (a :: l) :: i.transpose_aux ls
- (a :: i).transpose_aux list.nil = [a] :: i.transpose_aux list.nil
- list.nil.transpose_aux ls = ls
List of all sections through a list of lists. A section
of [L₁, L₂, ..., Lₙ]
is a list whose first element comes from
L₁
, whose second element comes from L₂
, and so on.
An auxiliary function for defining permutations
. permutations_aux2 t ts r ys f
is equal to
(ys ++ ts, (insert_left ys t ts).map f ++ r)
, where insert_left ys t ts
(not explicitly
defined) is the list of lists of the form insert_nth n t (ys ++ ts)
for 0 ≤ n < length ys
.
permutations_aux2 10 [4, 5, 6] [] [1, 2, 3] id =
([1, 2, 3, 4, 5, 6],
[[10, 1, 2, 3, 4, 5, 6],
[1, 10, 2, 3, 4, 5, 6],
[1, 2, 10, 3, 4, 5, 6]])
Equations
- list.permutations_aux2 t ts r (y :: ys) f = list.permutations_aux2._match_1 t y f (list.permutations_aux2 t ts r ys (λ (x : list α), f (y :: x)))
- list.permutations_aux2 t ts r list.nil f = (ts, r)
- list.permutations_aux2._match_1 t y f (us, zs) = (y :: us, f (t :: y :: us) :: zs)
A recursor for pairs of lists. To have C l₁ l₂
for all l₁
, l₂
, it suffices to have it for
l₂ = []
and to be able to pour the elements of l₁
into l₂
.
Equations
- list.permutations_aux.rec H0 H1 (t :: ts) is = H1 t ts is (list.permutations_aux.rec H0 H1 ts (t :: is)) (list.permutations_aux.rec H0 H1 is list.nil)
- list.permutations_aux.rec H0 H1 list.nil is = H0 is
An auxiliary function for defining permutations
. permutations_aux ts is
is the set of all
permutations of is ++ ts
that do not fix ts
.
Equations
- list.permutations_aux = list.permutations_aux.rec (λ (is : list α), list.nil) (λ (t : α) (ts is : list α) (IH1 : (λ (_x _x : list α), list (list α)) ts (t :: is)) (IH2 : (λ (_x _x : list α), list (list α)) is list.nil), list.foldr (λ (y : list α) (r : (λ (_x _x : list α), list (list α)) (t :: ts) is), (list.permutations_aux2 t ts r y id).snd) IH1 (is :: IH2))
List of all permutations of l
.
permutations [1, 2, 3] =
[[1, 2, 3], [2, 1, 3], [3, 2, 1],
[2, 3, 1], [3, 1, 2], [1, 3, 2]]
Equations
- l.permutations = l :: l.permutations_aux list.nil
permutations'_aux t ts
inserts t
into every position in ts
, including the last.
This function is intended for use in specifications, so it is simpler than permutations_aux2
,
which plays roughly the same role in permutations
.
Note that (permutations_aux2 t [] [] ts id).2
is similar to this function, but skips the last
position:
permutations'_aux 10 [1, 2, 3] =
[[10, 1, 2, 3], [1, 10, 2, 3], [1, 2, 10, 3], [1, 2, 3, 10]]
(permutations_aux2 10 [] [] [1, 2, 3] id).2 =
[[10, 1, 2, 3], [1, 10, 2, 3], [1, 2, 10, 3]]
Equations
- list.permutations'_aux t (y :: ys) = (t :: y :: ys) :: list.map (list.cons y) (list.permutations'_aux t ys)
- list.permutations'_aux t list.nil = [[t]]
List of all permutations of l
. This version of permutations
is less efficient but has
simpler definitional equations. The permutations are in a different order,
but are equal up to permutation, as shown by list.permutations_perm_permutations'
.
permutations [1, 2, 3] =
[[1, 2, 3], [2, 1, 3], [2, 3, 1],
[1, 3, 2], [3, 1, 2], [3, 2, 1]]
Equations
- (t :: ts).permutations' = ts.permutations'.bind (list.permutations'_aux t)
- list.nil.permutations' = [list.nil]
erasep p l
removes the first element of l
satisfying the predicate p
.
Equations
- list.erasep p (a :: l) = ite (p a) l (a :: list.erasep p l)
- list.erasep p list.nil = list.nil
extractp p l
returns a pair of an element a
of l
satisfying the predicate
p
, and l
, with a
removed. If there is no such element a
it returns (none, l)
.
Equations
- list.extractp p (a :: l) = ite (p a) (option.some a, l) (list.extractp._match_1 a (list.extractp p l))
- list.extractp p list.nil = (option.none α, list.nil α)
- list.extractp._match_1 a (a', l') = (a', a :: l')
Auxliary definition used to define of_fn
.
of_fn_aux f m h l
returns the first m
elements of of_fn f
appended to l
Equations
- list.of_fn_aux f m.succ h l = list.of_fn_aux f m _ (f ⟨m, h⟩ :: l)
- list.of_fn_aux f 0 h l = l
of_fn f
with f : fin n → α
returns the list whose ith element is f i
of_fun f = [f 0, f 1, ... , f(n - 1)]
Equations
- list.of_fn f = list.of_fn_aux f n list.of_fn._proof_1 list.nil
of_fn_nth_val f i
returns some (f i)
if i < n
and none
otherwise.
Equations
- list.of_fn_nth_val f i = dite (i < n) (λ (h : i < n), option.some (f ⟨i, h⟩)) (λ (h : ¬i < n), option.none)
- nil : ∀ {α : Type u_1} {R : α → α → Prop}, list.pairwise R list.nil
- cons : ∀ {α : Type u_1} {R : α → α → Prop} {a : α} {l : list α}, (∀ (a' : α), a' ∈ l → R a a') → list.pairwise R l → list.pairwise R (a :: l)
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.
Instances for list.pairwise
Equations
- l.decidable_pairwise = list.rec (decidable.is_true list.pairwise.nil) (λ (hd : α) (tl : list α) (ih : decidable (list.pairwise R tl)), decidable_of_iff' ((∀ (a' : α), a' ∈ tl → R hd a') ∧ list.pairwise R tl) list.pairwise_cons) l
pw_filter R l
is a maximal sublist of l
which is pairwise R
.
pw_filter (≠)
is the erase duplicates function (cf. dedup
), and pw_filter (<)
finds
a maximal increasing subsequence in l
. For example,
pw_filter (<) [0, 1, 5, 2, 6, 3, 4] = [0, 1, 2, 3, 4]
Equations
- list.pw_filter R (x :: xs) = let IH : list α := list.pw_filter R xs in ite (∀ (y : α), y ∈ IH → R x y) (x :: IH) IH
- list.pw_filter R list.nil = list.nil
- nil : ∀ {α : Type u_1} {R : α → α → Prop} {a : α}, list.chain R a list.nil
- cons : ∀ {α : Type u_1} {R : α → α → Prop} {a b : α} {l : list α}, R a b → list.chain R b l → list.chain R a (b :: l)
chain R a l
means that R
holds between adjacent elements of a::l
.
chain R a [b, c, d] ↔ R a b ∧ R b c ∧ R c d
Instances for list.chain
chain' R l
means that R
holds between adjacent elements of l
.
chain' R [a, b, c, d] ↔ R a b ∧ R b c ∧ R c d
Equations
- list.chain' R (a :: l) = list.chain R a l
- list.chain' R list.nil = true
Instances for list.chain'
Equations
- list.decidable_chain a l = list.rec (λ (a : α), _.mpr decidable.true) (λ (l_hd : α) (l_tl : list α) (l_ih : Π (a : α), decidable (list.chain R a l_tl)) (a : α), _.mpr and.decidable) l a
Equations
- l.decidable_chain' = l.cases_on (id decidable.true) (λ (l_hd : α) (l_tl : list α), id (list.decidable_chain l_hd l_tl))
nodup l
means that l
has no duplicates, that is, any element appears at most
once in the list. It is defined as pairwise (≠)
.
Equations
Instances for list.nodup
Equations
Greedily create a sublist of a :: l
such that, for every two adjacent elements a, b
,
R a b
holds. Mostly used with ≠; for example, destutter' (≠) 1 [2, 2, 1, 1] = [1, 2, 1]
,
destutter' (≠) 1, [2, 3, 3] = [1, 2, 3]
, destutter' (<) 1 [2, 5, 2, 3, 4, 9] = [1, 2, 5, 9]
.
Equations
- list.destutter' R a (h :: l) = ite (R a h) (a :: list.destutter' R h l) (list.destutter' R a l)
- list.destutter' R a list.nil = [a]
Greedily create a sublist of l
such that, for every two adjacent elements a, b ∈ l
,
R a b
holds. Mostly used with ≠; for example, destutter (≠) [1, 2, 2, 1, 1] = [1, 2, 1]
,
destutter (≠) [1, 2, 3, 3] = [1, 2, 3]
, destutter (<) [1, 2, 5, 2, 3, 4, 9] = [1, 2, 5, 9]
.
Equations
- list.destutter R (h :: l) = list.destutter' R h l
- list.destutter R list.nil = list.nil
range' s n
is the list of numbers [s, s+1, ..., s+n-1]
.
It is intended mainly for proving properties of range
and iota
.
Equations
- list.range' s (n + 1) = s :: list.range' (s + 1) n
- list.range' s 0 = list.nil
Drop none
s from a list, and replace each remaining some a
with a
.
Equations
ilast' x xs
returns the last element of xs
if xs
is non-empty;
it returns x
otherwise
Equations
- list.ilast' a (b :: l) = list.ilast' b l
- list.ilast' a list.nil = a
Given a decidable predicate p
and a proof of existence of a ∈ l
such that p a
,
choose the first element with this property. This version returns both a
and proofs
of a ∈ l
and p a
.
Equations
- list.choose_x p (l :: ls) hp = dite (p l) (λ (pl : p l), ⟨l, _⟩) (λ (pl : ¬p l), list.choose_x._match_2 p l ls (list.choose_x p ls _))
- list.choose_x p list.nil hp = _.elim
- list.choose_x._match_2 p l ls ⟨a, _⟩ = ⟨a, _⟩
Given a decidable predicate p
and a proof of existence of a ∈ l
such that p a
,
choose the first element with this property. This version returns a : α
, and properties
are given by choose_mem
and choose_property
.
Equations
- list.choose p l hp = ↑(list.choose_x p l hp)
Filters and maps elements of a list
Equations
- list.mmap_filter f (h :: t) = f h >>= λ (b : option β), list.mmap_filter f t >>= λ (t' : list β), return (list.mmap_filter._match_1 t' b)
- list.mmap_filter f list.nil = return list.nil
- list.mmap_filter._match_1 t' (option.some x) = x :: t'
- list.mmap_filter._match_1 t' option.none = t'
mmap_upper_triangle f l
calls f
on all elements in the upper triangular part of l × l
.
That is, for each e ∈ l
, it will run f e e
and then f e e'
for each e'
that appears after e
in l
.
Example: suppose l = [1, 2, 3]
. mmap_upper_triangle f l
will produce the list
[f 1 1, f 1 2, f 1 3, f 2 2, f 2 3, f 3 3]
.
mmap'_diag f l
calls f
on all elements in the upper triangular part of l × l
.
That is, for each e ∈ l
, it will run f e e
and then f e e'
for each e'
that appears after e
in l
.
Example: suppose l = [1, 2, 3]
. mmap'_diag f l
will evaluate, in this order,
f 1 1
, f 1 2
, f 1 3
, f 2 2
, f 2 3
, f 3 3
.
Equations
- list.mmap'_diag f (h :: t) = f h h >> list.mmap' (f h) t >> list.mmap'_diag f t
- list.mmap'_diag f list.nil = return unit.star()
Equations
- list.traverse f (x :: xs) = list.cons <$> f x <*> list.traverse f xs
- list.traverse f list.nil = has_pure.pure list.nil
get_rest l l₁
returns some l₂
if l = l₁ ++ l₂
.
If l₁
is not a prefix of l
, returns none
list.slice n m xs
removes a slice of length m
at index n
in list xs
.
Equations
- list.slice n.succ m (x :: xs) = x :: list.slice n m xs
- list.slice n.succ m list.nil = list.nil
- list.slice 0 n xs = list.drop n xs
Left-biased version of list.map₂
. map₂_left' f as bs
applies f
to each
pair of elements aᵢ ∈ as
and bᵢ ∈ bs
. If bs
is shorter than as
, f
is
applied to none
for the remaining aᵢ
. Returns the results of the f
applications and the remaining bs
.
map₂_left' prod.mk [1, 2] ['a'] = ([(1, some 'a'), (2, none)], [])
map₂_left' prod.mk [1] ['a', 'b'] = ([(1, some 'a')], ['b'])
```
Equations
- list.map₂_left' f (a :: as) (b :: bs) = let rec : list γ × list β := list.map₂_left' f as bs in (f a (option.some b) :: rec.fst, rec.snd)
- list.map₂_left' f (a :: as) list.nil = (list.map (λ (a : α), f a option.none) (a :: as), list.nil β)
- list.map₂_left' f list.nil bs = (list.nil γ, bs)
Right-biased version of list.map₂
. map₂_right' f as bs
applies f
to each
pair of elements aᵢ ∈ as
and bᵢ ∈ bs
. If as
is shorter than bs
, f
is
applied to none
for the remaining bᵢ
. Returns the results of the f
applications and the remaining as
.
map₂_right' prod.mk [1] ['a', 'b'] = ([(some 1, 'a'), (none, 'b')], [])
map₂_right' prod.mk [1, 2] ['a'] = ([(some 1, 'a')], [2])
```
Equations
- list.map₂_right' f as bs = list.map₂_left' (flip f) bs as
Left-biased version of list.zip
. zip_left' as bs
returns the list of
pairs (aᵢ, bᵢ)
for aᵢ ∈ as
and bᵢ ∈ bs
. If bs
is shorter than as
, the
remaining aᵢ
are paired with none
. Also returns the remaining bs
.
zip_left' [1, 2] ['a'] = ([(1, some 'a'), (2, none)], [])
zip_left' [1] ['a', 'b'] = ([(1, some 'a')], ['b'])
zip_left' = map₂_left' prod.mk
```
Equations
Right-biased version of list.zip
. zip_right' as bs
returns the list of
pairs (aᵢ, bᵢ)
for aᵢ ∈ as
and bᵢ ∈ bs
. If as
is shorter than bs
, the
remaining bᵢ
are paired with none
. Also returns the remaining as
.
zip_right' [1] ['a', 'b'] = ([(some 1, 'a'), (none, 'b')], [])
zip_right' [1, 2] ['a'] = ([(some 1, 'a')], [2])
zip_right' = map₂_right' prod.mk
```
Equations
Left-biased version of list.map₂
. map₂_left f as bs
applies f
to each pair
aᵢ ∈ as
and bᵢ ∈ bs
. If bs
is shorter than as
, f
is applied to none
for the remaining aᵢ
.
map₂_left prod.mk [1, 2] ['a'] = [(1, some 'a'), (2, none)]
map₂_left prod.mk [1] ['a', 'b'] = [(1, some 'a')]
map₂_left f as bs = (map₂_left' f as bs).fst
```
Equations
- list.map₂_left f (a :: as) (b :: bs) = f a (option.some b) :: list.map₂_left f as bs
- list.map₂_left f (a :: as) list.nil = list.map (λ (a : α), f a option.none) (a :: as)
- list.map₂_left f list.nil _x = list.nil
Right-biased version of list.map₂
. map₂_right f as bs
applies f
to each
pair aᵢ ∈ as
and bᵢ ∈ bs
. If as
is shorter than bs
, f
is applied to
none
for the remaining bᵢ
.
map₂_right prod.mk [1, 2] ['a'] = [(some 1, 'a')]
map₂_right prod.mk [1] ['a', 'b'] = [(some 1, 'a'), (none, 'b')]
map₂_right f as bs = (map₂_right' f as bs).fst
```
Equations
- list.map₂_right f as bs = list.map₂_left (flip f) bs as
Left-biased version of list.zip
. zip_left as bs
returns the list of pairs
(aᵢ, bᵢ)
for aᵢ ∈ as
and bᵢ ∈ bs
. If bs
is shorter than as
, the
remaining aᵢ
are paired with none
.
zip_left [1, 2] ['a'] = [(1, some 'a'), (2, none)]
zip_left [1] ['a', 'b'] = [(1, some 'a')]
zip_left = map₂_left prod.mk
```
Equations
Right-biased version of list.zip
. zip_right as bs
returns the list of pairs
(aᵢ, bᵢ)
for aᵢ ∈ as
and bᵢ ∈ bs
. If as
is shorter than bs
, the
remaining bᵢ
are paired with none
.
zip_right [1, 2] ['a'] = [(some 1, 'a')]
zip_right [1] ['a', 'b'] = [(some 1, 'a'), (none, 'b')]
zip_right = map₂_right prod.mk
```
Equations
If all elements of xs
are some xᵢ
, all_some xs
returns the xᵢ
. Otherwise
it returns none
.
all_some [some 1, some 2] = some [1, 2]
all_some [some 1, none ] = none
Equations
- (option.some a :: as).all_some = list.cons a <$> as.all_some
- (option.none :: as).all_some = option.none
- list.nil.all_some = option.some list.nil
fill_nones xs ys
replaces the none
s in xs
with elements of ys
. If there
are not enough ys
to replace all the none
s, the remaining none
s are
dropped from xs
.
fill_nones [none, some 1, none, none] [2, 3] = [2, 1, 3]
Equations
- (option.some a :: as).fill_nones as' = a :: as.fill_nones as'
- (option.none :: as).fill_nones (a :: as') = a :: as.fill_nones as'
- (option.none :: as).fill_nones list.nil = as.reduce_option
- list.nil.fill_nones _x = list.nil
take_list as ns
extracts successive sublists from as
. For ns = n₁ ... nₘ
,
it first takes the n₁
initial elements from as
, then the next n₂
ones,
etc. It returns the sublists of as
-- one for each nᵢ
-- and the remaining
elements of as
. If as
does not have at least as many elements as the sum of
the nᵢ
, the corresponding sublists will have less than nᵢ
elements.
take_list ['a', 'b', 'c', 'd', 'e'] [2, 1, 1] = ([['a', 'b'], ['c'], ['d']], ['e'])
take_list ['a', 'b'] [3, 1] = ([['a', 'b'], []], [])
Equations
to_rbmap as
is the map that associates each index i
of as
with the
corresponding element of as
.
to_rbmap ['a', 'b', 'c'] = rbmap_of [(0, 'a'), (1, 'b'), (2, 'c')]
Auxliary definition used to define to_chunks
.
to_chunks_aux n xs i
returns (xs.take i, (xs.drop i).to_chunks (n+1))
,
that is, the first i
elements of xs
, and the remaining elements chunked into
sublists of length n+1
.
Equations
- list.to_chunks_aux n (x :: xs) (i + 1) = list.to_chunks_aux._match_2 x (list.to_chunks_aux n xs i)
- list.to_chunks_aux n (x :: xs) 0 = list.to_chunks_aux._match_1 x (list.to_chunks_aux n xs n)
- list.to_chunks_aux n list.nil i = (list.nil α, list.nil (list α))
- list.to_chunks_aux._match_2 x (l, L) = (x :: l, L)
- list.to_chunks_aux._match_1 x (l, L) = (list.nil α, (x :: l) :: L)
xs.to_chunks n
splits the list into sublists of size at most n
,
such that (xs.to_chunks n).join = xs
.
[1, 2, 3, 4, 5, 6, 7, 8].to_chunks 10 = [[1, 2, 3, 4, 5, 6, 7, 8]]
[1, 2, 3, 4, 5, 6, 7, 8].to_chunks 3 = [[1, 2, 3], [4, 5, 6], [7, 8]]
[1, 2, 3, 4, 5, 6, 7, 8].to_chunks 2 = [[1, 2], [3, 4], [5, 6], [7, 8]]
[1, 2, 3, 4, 5, 6, 7, 8].to_chunks 0 = [[1, 2, 3, 4, 5, 6, 7, 8]]
Equations
- list.to_chunks (n + 1) (x :: xs) = list.to_chunks._match_1 x (list.to_chunks_aux n xs n)
- list.to_chunks n.succ list.nil = list.nil
- list.to_chunks 0 (hd :: tl) = [hd :: tl]
- list.to_chunks 0 list.nil = list.nil
- list.to_chunks._match_1 x (l, L) = (x :: l) :: L
We add some n-ary versions of list.zip_with
for functions with more than two arguments.
These can also be written in terms of list.zip
or list.zip_with
.
For example, zip_with3 f xs ys zs
could also be written as
zip_with id (zip_with f xs ys) zs
or as
(zip xs $ zip ys zs).map $ λ ⟨x, y, z⟩, f x y z
.
Ternary version of list.zip_with
.
Equations
- list.zip_with3 f (x :: xs) (y :: ys) (z :: zs) = f x y z :: list.zip_with3 f xs ys zs
- list.zip_with3 f (hd :: tl) (hd_1 :: tl_1) list.nil = list.nil
- list.zip_with3 f (hd :: tl) list.nil _x = list.nil
- list.zip_with3 f list.nil _x _x_1 = list.nil
Quaternary version of list.zip_with
.
Equations
- list.zip_with4 f (x :: xs) (y :: ys) (z :: zs) (u :: us) = f x y z u :: list.zip_with4 f xs ys zs us
- list.zip_with4 f (hd :: tl) (hd_1 :: tl_1) (hd_2 :: tl_2) list.nil = list.nil
- list.zip_with4 f (hd :: tl) (hd_1 :: tl_1) list.nil _x = list.nil
- list.zip_with4 f (hd :: tl) list.nil _x _x_1 = list.nil
- list.zip_with4 f list.nil _x _x_1 _x_2 = list.nil
Quinary version of list.zip_with
.
Equations
- list.zip_with5 f (x :: xs) (y :: ys) (z :: zs) (u :: us) (v :: vs) = f x y z u v :: list.zip_with5 f xs ys zs us vs
- list.zip_with5 f (hd :: tl) (hd_1 :: tl_1) (hd_2 :: tl_2) (hd_3 :: tl_3) list.nil = list.nil
- list.zip_with5 f (hd :: tl) (hd_1 :: tl_1) (hd_2 :: tl_2) list.nil _x = list.nil
- list.zip_with5 f (hd :: tl) (hd_1 :: tl_1) list.nil _x _x_1 = list.nil
- list.zip_with5 f (hd :: tl) list.nil _x _x_1 _x_2 = list.nil
- list.zip_with5 f list.nil _x _x_1 _x_2 _x_3 = list.nil
Given a starting list old
, a list of booleans and a replacement list new
,
read the items in old
in succession and either replace them with the next element of new
or
not, according as to whether the corresponding boolean is tt
or ff
.
Equations
- (n :: ns).replace_if (tf :: bs) (c :: cs) = ite ↥tf (c :: ns.replace_if bs cs) (n :: ns.replace_if bs (c :: cs))
- (hd :: tl).replace_if (hd_1 :: tl_1) list.nil = hd :: tl
- (hd :: tl).replace_if list.nil (hd_1 :: tl_1) = hd :: tl
- (hd :: tl).replace_if list.nil list.nil = hd :: tl
- list.nil.replace_if (hd :: tl) (hd_1 :: tl_1) = list.nil
- list.nil.replace_if (hd :: tl) list.nil = list.nil
- list.nil.replace_if list.nil (hd :: tl) = list.nil
- list.nil.replace_if list.nil list.nil = list.nil
An auxiliary function for list.map_with_prefix_suffix
.
Equations
- list.map_with_prefix_suffix_aux f prev (h :: t) = f prev h t :: list.map_with_prefix_suffix_aux f (prev.concat h) t
- list.map_with_prefix_suffix_aux f prev list.nil = list.nil
list.map_with_prefix_suffix f l
maps f
across a list l
.
For each a ∈ l
with l = pref ++ [a] ++ suff
, a
is mapped to f pref a suff
.
Example: if f : list ℕ → ℕ → list ℕ → β
,
list.map_with_prefix_suffix f [1, 2, 3]
will produce the list
[f [] 1 [2, 3], f [1] 2 [3], f [1, 2] 3 []]
.
Equations
list.map_with_complement f l
is a variant of list.map_with_prefix_suffix
that maps f
across a list l
.
For each a ∈ l
with l = pref ++ [a] ++ suff
, a
is mapped to f a (pref ++ suff)
,
i.e., the list input to f
is l
with a
removed.
Example: if f : ℕ → list ℕ → β
, list.map_with_complement f [1, 2, 3]
will produce the list
[f 1 [2, 3], f 2 [1, 3], f 3 [1, 2]]
.
Equations
- list.map_with_complement f = list.map_with_prefix_suffix (λ (pref : list α) (a : α) (suff : list α), f a (pref ++ suff))