feat: lemmas about List.map (#4521)
This commit is contained in:
parent
f32780d863
commit
301a89aba4
6 changed files with 319 additions and 28 deletions
|
|
@ -1191,6 +1191,8 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
|
|||
(f : α₁ → α₂) (g : β₁ → β₂) : α₁ × β₁ → α₂ × β₂
|
||||
| (a, b) => (f a, g b)
|
||||
|
||||
@[simp] theorem Prod.map_apply : Prod.map f g (x, y) = (f x, g y) := rfl
|
||||
|
||||
/-! # Dependent products -/
|
||||
|
||||
theorem ex_of_PSigma {α : Type u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x)
|
||||
|
|
|
|||
|
|
@ -880,6 +880,8 @@ def rotateLeft (xs : List α) (n : Nat := 1) : List α :=
|
|||
let e := xs.drop n
|
||||
e ++ b
|
||||
|
||||
@[simp] theorem rotateLeft_nil : ([] : List α).rotateLeft n = [] := rfl
|
||||
|
||||
/-! ### rotateRight -/
|
||||
|
||||
/--
|
||||
|
|
@ -899,6 +901,8 @@ def rotateRight (xs : List α) (n : Nat := 1) : List α :=
|
|||
let e := xs.drop n
|
||||
e ++ b
|
||||
|
||||
@[simp] theorem rotateRight_nil : ([] : List α).rotateRight n = [] := rfl
|
||||
|
||||
/-! ## Manipulating elements -/
|
||||
|
||||
/-! ### replace -/
|
||||
|
|
|
|||
|
|
@ -33,6 +33,23 @@ For each `List` operation, we would like theorems describing the following, when
|
|||
|
||||
Of course for any individual operation, not all of these will be relevant or helpful, so some judgement is required.
|
||||
|
||||
General principles for `simp` normal forms for `List` operations:
|
||||
* Conversion operations (e.g. `toArray`, or `length`) should be moved inwards aggressively,
|
||||
to make the conversion effective.
|
||||
* Similarly, operation which work on elements should be moved inwards in preference to
|
||||
"structural" operations on the list, e.g. we prefer to simplify
|
||||
`List.map f (L ++ M) ~> (List.map f L) ++ (List.map f M)`,
|
||||
`List.map f L.reverse ~> (List.map f L).reverse`, and
|
||||
`List.map f (L.take n) ~> (List.map f L).take n`.
|
||||
* Arithmetic operations are "light", so e.g. we prefer to simplify `drop i (drop j L)` to `drop (i + j) L`,
|
||||
rather than the other way round.
|
||||
* Function compositions are "light", so we prefer to simplify `(L.map f).map g` to `L.map (g ∘ f)`.
|
||||
* We try to avoid non-linear left hand sides (i.e. with subexpressions appearing multiple times),
|
||||
but this is only a weak preference.
|
||||
* Generally, we prefer that the right hand side does not introduce duplication,
|
||||
however generally duplication of higher order arguments (functions, predicates, etc) is allowed,
|
||||
as we expect to be able to compute these once they reach ground terms.
|
||||
|
||||
-/
|
||||
namespace List
|
||||
|
||||
|
|
@ -590,6 +607,20 @@ theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α
|
|||
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
/-! ### getD -/
|
||||
|
||||
@[simp] theorem getD_eq_getElem? (l) (n) (a : α) : getD l n a = (l[n]?).getD a := by
|
||||
|
|
@ -682,6 +713,15 @@ theorem head?_eq_head : ∀ l h, @head? α l = some (head l h)
|
|||
|
||||
/-! ### map -/
|
||||
|
||||
@[simp] theorem map_id (l : List α) : map id l = l := by induction l <;> simp_all
|
||||
|
||||
@[simp] theorem map_id' (l : List α) : map (fun a => a) l = l := by induction l <;> simp_all
|
||||
|
||||
theorem map_id'' {f : α → α} (h : ∀ x, f x = x) (l : List α) : map f l = l := by
|
||||
simp [show f = id from funext h]
|
||||
|
||||
theorem map_singleton (f : α → β) (a : α) : map f [a] = [f a] := rfl
|
||||
|
||||
@[simp] theorem length_map (as : List α) (f : α → β) : (as.map f).length = as.length := by
|
||||
induction as with
|
||||
| nil => simp [List.map]
|
||||
|
|
@ -707,33 +747,105 @@ theorem get_map (f : α → β) {l n} :
|
|||
get (map f l) n = f (get l ⟨n, length_map l f ▸ n.2⟩) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem map_append (f : α → β) : ∀ l₁ l₂, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
|
||||
intro l₁; induction l₁ <;> intros <;> simp_all
|
||||
|
||||
@[simp] theorem map_id (l : List α) : map id l = l := by induction l <;> simp_all
|
||||
|
||||
@[simp] theorem map_id' (l : List α) : map (fun a => a) l = l := by induction l <;> simp_all
|
||||
|
||||
@[simp] theorem mem_map {f : α → β} : ∀ {l : List α}, b ∈ l.map f ↔ ∃ a, a ∈ l ∧ f a = b
|
||||
| [] => by simp
|
||||
| _ :: l => by simp [mem_map (l := l), eq_comm (a := b)]
|
||||
|
||||
theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h
|
||||
|
||||
theorem mem_map_of_mem (f : α → β) (h : a ∈ l) : f a ∈ map f l := mem_map.2 ⟨_, h, rfl⟩
|
||||
|
||||
@[simp] theorem map_inj_left {f g : α → β} : map f l = map g l ↔ ∀ a ∈ l, f a = g a := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem map_congr_left (h : ∀ a ∈ l, f a = g a) : map f l = map g l :=
|
||||
map_inj_left.2 h
|
||||
|
||||
theorem map_inj : map f = map g ↔ f = g := by
|
||||
constructor
|
||||
· intro h; ext a; replace h := congrFun h [a]; simpa using h
|
||||
· intro h; subst h; rfl
|
||||
|
||||
@[simp] theorem map_eq_nil {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
|
||||
constructor <;> exact fun _ => match l with | [] => rfl
|
||||
|
||||
theorem eq_nil_of_map_eq_nil {f : α → β} {l : List α} (h : map f l = []) : l = [] :=
|
||||
map_eq_nil.mp h
|
||||
|
||||
theorem map_eq_cons {f : α → β} {l : List α} :
|
||||
map f l = b :: l₂ ↔ l.head?.map f = some b ∧ l.tail?.map (map f) = some l₂ := by
|
||||
induction l <;> simp_all
|
||||
|
||||
theorem map_eq_cons' {f : α → β} {l : List α} :
|
||||
map f l = b :: l₂ ↔ ∃ a l₁, l = a :: l₁ ∧ f a = b ∧ map f l₁ = l₂ := by
|
||||
cases l
|
||||
case nil => simp
|
||||
case cons a l₁ =>
|
||||
simp only [map_cons, cons.injEq]
|
||||
constructor
|
||||
· rintro ⟨rfl, rfl⟩
|
||||
exact ⟨a, l₁, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
|
||||
· rintro ⟨a, l₁, ⟨rfl, rfl⟩, ⟨rfl, rfl⟩⟩
|
||||
constructor <;> rfl
|
||||
|
||||
theorem map_eq_foldr (f : α → β) (l : List α) : map f l = foldr (fun a bs => f a :: bs) [] l := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[simp] theorem set_map {f : α → β} {l : List α} {n : Nat} {a : α} :
|
||||
(map f l).set n (f a) = map f (l.set n a) := by
|
||||
induction l generalizing n with
|
||||
| nil => simp
|
||||
| cons b l ih => cases n <;> simp_all
|
||||
|
||||
@[simp] theorem head_map (f : α → β) (l : List α) (w) :
|
||||
head (map f l) w = f (head l (by simpa using w)) := by
|
||||
cases l
|
||||
· simp at w
|
||||
· simp_all
|
||||
|
||||
@[simp] theorem head?_map (f : α → β) (l : List α) : head? (map f l) = (head? l).map f := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem headD_map (f : α → β) (l : List α) (a : α) : headD (map f l) (f a) = f (headD l a) := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem tail?_map (f : α → β) (l : List α) : tail? (map f l) = (tail? l).map (map f) := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem tailD_map (f : α → β) (l : List α) (l' : List α) :
|
||||
tailD (map f l) (map f l') = map f (tailD l l') := by
|
||||
cases l <;> rfl
|
||||
|
||||
@[simp] theorem getLast_map (f : α → β) (l : List α) (h) :
|
||||
getLast (map f l) h = f (getLast l (by simpa using h)) := by
|
||||
cases l
|
||||
· simp at h
|
||||
· simp only [← getElem_cons_length _ _ _ rfl]
|
||||
simp only [map_cons]
|
||||
simp only [← getElem_cons_length _ _ _ rfl]
|
||||
simp only [← map_cons, getElem_map]
|
||||
simp
|
||||
|
||||
@[simp] theorem getLast?_map (f : α → β) (l : List α) : getLast? (map f l) = (getLast? l).map f := by
|
||||
cases l
|
||||
· simp
|
||||
· rw [getLast?_eq_getLast, getLast?_eq_getLast, getLast_map] <;> simp
|
||||
|
||||
@[simp] theorem getLastD_map (f : α → β) (l : List α) (a : α) : getLastD (map f l) (f a) = f (getLastD l a) := by
|
||||
cases l
|
||||
· simp
|
||||
· rw [getLastD_eq_getLast?, getLastD_eq_getLast?, getLast?_map] <;> simp
|
||||
|
||||
@[simp] theorem map_append (f : α → β) : ∀ l₁ l₂, map f (l₁ ++ l₂) = map f l₁ ++ map f l₂ := by
|
||||
intro l₁; induction l₁ <;> intros <;> simp_all
|
||||
|
||||
@[simp] theorem map_map (g : β → γ) (f : α → β) (l : List α) :
|
||||
map g (map f l) = map (g ∘ f) l := by induction l <;> simp_all
|
||||
|
||||
theorem map_singleton (f : α → β) (a : α) : map f [a] = [f a] := rfl
|
||||
|
||||
theorem exists_of_mem_map (h : b ∈ map f l) : ∃ a, a ∈ l ∧ f a = b := mem_map.1 h
|
||||
|
||||
theorem forall_mem_map_iff {f : α → β} {l : List α} {P : β → Prop} :
|
||||
(∀ (i) (_ : i ∈ l.map f), P i) ↔ ∀ (j) (_ : j ∈ l), P (f j) := by
|
||||
simp
|
||||
|
||||
@[simp] theorem map_eq_nil {f : α → β} {l : List α} : map f l = [] ↔ l = [] := by
|
||||
constructor <;> exact fun _ => match l with | [] => rfl
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@[simp] theorem filter_cons_of_pos {p : α → Bool} {a : α} (l) (pa : p a) :
|
||||
|
|
@ -797,18 +909,28 @@ theorem filter_map (f : β → α) (l : List β) : filter p (map f l) = map f (f
|
|||
|
||||
@[deprecated filter_map (since := "2024-06-15")] abbrev map_filter := @filter_map
|
||||
|
||||
theorem map_filter_eq_foldr (f : α → β) (p : α → Bool) (as : List α) :
|
||||
map f (filter p as) = foldr (fun a bs => bif p a then f a :: bs else bs) [] as := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons head _ ih =>
|
||||
simp only [foldr]
|
||||
cases hp : p head <;> simp [filter, *]
|
||||
|
||||
@[simp] theorem filter_append {p : α → Bool} :
|
||||
∀ (l₁ l₂ : List α), filter p (l₁ ++ l₂) = filter p l₁ ++ filter p l₂
|
||||
| [], l₂ => rfl
|
||||
| a :: l₁, l₂ => by simp [filter]; split <;> simp [filter_append l₁]
|
||||
|
||||
theorem filter_congr' {p q : α → Bool} :
|
||||
theorem filter_congr {p q : α → Bool} :
|
||||
∀ {l : List α}, (∀ x ∈ l, p x ↔ q x) → filter p l = filter q l
|
||||
| [], _ => rfl
|
||||
| a :: l, h => by
|
||||
rw [forall_mem_cons] at h; by_cases pa : p a
|
||||
· simp [pa, h.1.1 pa, filter_congr' h.2]
|
||||
· simp [pa, mt h.1.2 pa, filter_congr' h.2]
|
||||
· simp [pa, h.1.1 pa, filter_congr h.2]
|
||||
· simp [pa, mt h.1.2 pa, filter_congr h.2]
|
||||
|
||||
@[deprecated filter_congr (since := "2024-06-20")] abbrev filter_congr' := @filter_congr
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
|
|
@ -1096,6 +1218,11 @@ theorem concat_append (a : α) (l₁ l₂ : List α) : concat l₁ a ++ l₂ = l
|
|||
|
||||
theorem append_concat (a : α) (l₁ l₂ : List α) : l₁ ++ concat l₂ a = concat (l₁ ++ l₂) a := by simp
|
||||
|
||||
theorem map_concat (f : α → β) (a : α) (l : List α) : map f (concat l a) = concat (map f l) (f a) := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih => simp [ih]
|
||||
|
||||
theorem eq_nil_or_concat : ∀ l : List α, l = [] ∨ ∃ L b, l = concat L b
|
||||
| [] => .inl rfl
|
||||
| a::l => match l, eq_nil_or_concat l with
|
||||
|
|
@ -1112,6 +1239,9 @@ theorem exists_of_mem_join : a ∈ join L → ∃ l, l ∈ L ∧ a ∈ l := mem_
|
|||
|
||||
theorem mem_join_of_mem (lL : l ∈ L) (al : a ∈ l) : a ∈ join L := mem_join.2 ⟨l, lL, al⟩
|
||||
|
||||
@[simp] theorem map_join (f : α → β) (L : List (List α)) : map f (join L) = join (map (map f) L) := by
|
||||
induction L <;> simp_all
|
||||
|
||||
/-! ### bind -/
|
||||
|
||||
@[simp] theorem append_bind xs ys (f : α → List β) :
|
||||
|
|
@ -1130,10 +1260,27 @@ theorem exists_of_mem_bind {b : β} {l : List α} {f : α → List β} :
|
|||
theorem mem_bind_of_mem {b : β} {l : List α} {f : α → List β} {a} (al : a ∈ l) (h : b ∈ f a) :
|
||||
b ∈ List.bind l f := mem_bind.2 ⟨a, al, h⟩
|
||||
|
||||
theorem bind_map (f : β → γ) (g : α → List β) :
|
||||
∀ l : List α, map f (l.bind g) = l.bind fun a => (g a).map f
|
||||
theorem bind_singleton (f : α → List β) (x : α) : [x].bind f = f x :=
|
||||
append_nil (f x)
|
||||
|
||||
@[simp] theorem bind_singleton' (l : List α) : (l.bind fun x => [x]) = l := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
theorem bind_assoc {α β} (l : List α) (f : α → List β) (g : β → List γ) :
|
||||
(l.bind f).bind g = l.bind fun x => (f x).bind g := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
theorem map_bind (f : β → γ) (g : α → List β) :
|
||||
∀ l : List α, (l.bind g).map f = l.bind fun a => (g a).map f
|
||||
| [] => rfl
|
||||
| a::l => by simp only [bind_cons, map_append, bind_map _ _ l]
|
||||
| a::l => by simp only [bind_cons, map_append, map_bind _ _ l]
|
||||
|
||||
theorem bind_map {f : α → β} {g : β → List γ} (l : List α) : (map f l).bind g = l.bind (fun a => g (f a)) := by
|
||||
induction l <;> simp [bind_cons, append_bind, *]
|
||||
|
||||
theorem map_eq_bind {α β} (f : α → β) (l : List α) : map f l = l.bind fun x => [f x] := by
|
||||
simp only [← map_singleton]
|
||||
rw [← bind_singleton' l, map_bind, bind_singleton']
|
||||
|
||||
/-! ### replicate -/
|
||||
|
||||
|
|
@ -1202,6 +1349,17 @@ theorem eq_replicate {a : α} {n} {l : List α} :
|
|||
⟨fun h => h ▸ ⟨length_replicate .., fun _ => eq_of_mem_replicate⟩,
|
||||
fun ⟨e, al⟩ => e ▸ eq_replicate_of_mem al⟩
|
||||
|
||||
theorem map_eq_replicate_iff {l : List α} {f : α → β} {b : β} :
|
||||
l.map f = replicate l.length b ↔ ∀ x ∈ l, f x = b := by
|
||||
simp [eq_replicate]
|
||||
|
||||
@[simp] theorem map_const (l : List α) (b : β) : map (Function.const α b) l = replicate l.length b :=
|
||||
map_eq_replicate_iff.mpr fun _ _ => rfl
|
||||
|
||||
-- This can not be a `@[simp]` lemma because it would fire on every `List.map`.
|
||||
theorem map_const' (l : List α) (b : β) : map (fun _ => b) l = replicate l.length b :=
|
||||
map_const l b
|
||||
|
||||
@[simp] theorem append_replicate_replicate : replicate n a ++ replicate m a = replicate (n + m) a := by
|
||||
rw [eq_replicate]
|
||||
constructor
|
||||
|
|
@ -1319,9 +1477,13 @@ theorem reverseAux_reverseAux_nil (as bs : List α) : reverseAux (reverseAux as
|
|||
@[simp] theorem reverse_append (as bs : List α) : (as ++ bs).reverse = bs.reverse ++ as.reverse := by
|
||||
induction as <;> simp_all
|
||||
|
||||
theorem reverse_map (f : α → β) (l : List α) : (l.map f).reverse = l.reverse.map f := by
|
||||
@[simp] theorem map_reverse (f : α → β) (l : List α) : l.reverse.map f = (l.map f).reverse := by
|
||||
induction l <;> simp [*]
|
||||
|
||||
@[deprecated map_reverse (since := "2024-06-20")]
|
||||
theorem reverse_map (f : α → β) (l : List α) : (l.map f).reverse = l.reverse.map f := by
|
||||
simp
|
||||
|
||||
@[simp] theorem reverse_eq_nil_iff {xs : List α} : xs.reverse = [] ↔ xs = [] := by
|
||||
match xs with
|
||||
| [] => simp
|
||||
|
|
@ -1354,13 +1516,11 @@ theorem reverseAux_eq (as bs : List α) : reverseAux as bs = reverse as ++ bs :=
|
|||
|
||||
/-! ## List membership -/
|
||||
|
||||
/-! ### elem -/
|
||||
/-! ### elem / contains -/
|
||||
|
||||
@[simp] theorem elem_cons_self [BEq α] [LawfulBEq α] {a : α} : (a::as).elem a = true := by
|
||||
simp [elem_cons]
|
||||
|
||||
/-! ### contains -/
|
||||
|
||||
@[simp] theorem contains_cons [BEq α] :
|
||||
(a :: as : List α).contains x = (x == a || as.contains x) := by
|
||||
simp only [contains, elem]
|
||||
|
|
@ -1421,7 +1581,7 @@ theorem take_left : ∀ l₁ l₂ : List α, take (length l₁) (l₁ ++ l₂) =
|
|||
theorem take_left' {l₁ l₂ : List α} {n} (h : length l₁ = n) : take n (l₁ ++ l₂) = l₁ := by
|
||||
rw [← h]; apply take_left
|
||||
|
||||
theorem map_take (f : α → β) :
|
||||
@[simp] theorem map_take (f : α → β) :
|
||||
∀ (L : List α) (i : Nat), (L.take i).map f = (L.map f).take i
|
||||
| [], i => by simp
|
||||
| _, 0 => by simp
|
||||
|
|
@ -1510,7 +1670,7 @@ theorem take_drop : ∀ (m n : Nat) (l : List α), take n (drop m l) = drop m (t
|
|||
| _, _, [] => by simp
|
||||
| _+1, _, _ :: _ => by simpa [Nat.succ_add, take_succ_cons, drop_succ_cons] using take_drop ..
|
||||
|
||||
theorem map_drop (f : α → β) :
|
||||
@[simp] theorem map_drop (f : α → β) :
|
||||
∀ (L : List α) (i : Nat), (L.drop i).map f = (L.map f).drop i
|
||||
| [], i => by simp
|
||||
| L, 0 => by simp
|
||||
|
|
@ -1564,6 +1724,22 @@ theorem dropWhile_cons :
|
|||
(x :: xs : List α).dropWhile p = if p x then xs.dropWhile p else x :: xs := by
|
||||
split <;> simp_all [dropWhile]
|
||||
|
||||
theorem takeWhile_map (f : α → β) (p : β → Bool) (l : List α) :
|
||||
(l.map f).takeWhile p = (l.takeWhile (p ∘ f)).map f := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [map_cons, takeWhile_cons]
|
||||
split <;> simp_all
|
||||
|
||||
theorem dropWhile_map (f : α → β) (p : β → Bool) (l : List α) :
|
||||
(l.map f).dropWhile p = (l.dropWhile (p ∘ f)).map f := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih =>
|
||||
simp only [map_cons, dropWhile_cons]
|
||||
split <;> simp_all
|
||||
|
||||
@[simp] theorem takeWhile_append_dropWhile (p : α → Bool) :
|
||||
∀ (l : List α), takeWhile p l ++ dropWhile p l = l
|
||||
| [] => rfl
|
||||
|
|
@ -1648,6 +1824,11 @@ theorem dropLast_append_cons : dropLast (l₁ ++ b::l₂) = l₁ ++ dropLast (b:
|
|||
|
||||
@[simp 1100] theorem dropLast_concat : dropLast (l₁ ++ [b]) = l₁ := by simp
|
||||
|
||||
@[simp] theorem map_dropLast (f : α → β) (l : List α) : l.dropLast.map f = (l.map f).dropLast := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
| cons x xs ih => cases xs <;> simp [ih]
|
||||
|
||||
@[simp] theorem dropLast_replicate (n) (a : α) : dropLast (replicate n a) = replicate (n - 1) a := by
|
||||
match n with
|
||||
| 0 => simp
|
||||
|
|
@ -1700,11 +1881,17 @@ end isSuffixOf
|
|||
@[simp] theorem rotateLeft_zero (l : List α) : rotateLeft l 0 = l := by
|
||||
simp [rotateLeft]
|
||||
|
||||
-- TODO Batteries defines its own `getElem?_rotate`, which we need to adapt.
|
||||
-- TODO Prove `map_rotateLeft`, using `ext` and `getElem?_rotateLeft`.
|
||||
|
||||
/-! ### rotateRight -/
|
||||
|
||||
@[simp] theorem rotateRight_zero (l : List α) : rotateRight l 0 = l := by
|
||||
simp [rotateRight]
|
||||
|
||||
-- TODO Batteries defines its own `getElem?_rotate`, which we need to adapt.
|
||||
-- TODO Prove `map_rotateRight`, using `ext` and `getElem?_rotateRight`.
|
||||
|
||||
/-! ## Manipulating elements -/
|
||||
|
||||
/-! ### replace -/
|
||||
|
|
@ -1827,6 +2014,13 @@ theorem find?_some : ∀ {l}, find? p l = some a → p a
|
|||
· exact H ▸ .head _
|
||||
· exact .tail _ (mem_of_find?_eq_some H)
|
||||
|
||||
@[simp] theorem find?_map (f : β → α) (l : List β) : find? p (l.map f) = (l.find? (p ∘ f)).map f := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [map_cons, find?]
|
||||
by_cases h : p (f x) <;> simp [h, ih]
|
||||
|
||||
theorem find?_replicate : find? p (replicate n a) = if n = 0 then none else if p a then some a else none := by
|
||||
cases n
|
||||
· simp
|
||||
|
|
@ -1859,6 +2053,13 @@ theorem exists_of_findSome?_eq_some {l : List α} {f : α → Option β} (w : l.
|
|||
simp_all only [findSome?_cons, mem_cons, exists_eq_or_imp]
|
||||
split at w <;> simp_all
|
||||
|
||||
@[simp] theorem findSome?_map (f : β → γ) (l : List β) : findSome? p (l.map f) = l.findSome? (p ∘ f) := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
simp only [map_cons, findSome?]
|
||||
split <;> simp_all
|
||||
|
||||
theorem findSome?_replicate : findSome? f (replicate n a) = if n = 0 then none else f a := by
|
||||
induction n with
|
||||
| zero => simp
|
||||
|
|
@ -1941,6 +2142,12 @@ theorem any_eq_not_all_not (l : List α) (p : α → Bool) : l.any p = !l.all (!
|
|||
theorem all_eq_not_any_not (l : List α) (p : α → Bool) : l.all p = !l.any (!p .) := by
|
||||
simp only [not_any_eq_all_not, Bool.not_not]
|
||||
|
||||
theorem any_map (f : α → β) (l : List α) (p : β → Bool) : (l.map f).any p = l.any (p ∘ f) := by
|
||||
induction l with simp | cons _ _ ih => rw [ih]
|
||||
|
||||
theorem all_map (f : α → β) (l : List α) (p : β → Bool) : (l.map f).all p = l.all (p ∘ f) := by
|
||||
induction l with simp | cons _ _ ih => rw [ih]
|
||||
|
||||
/-! ## Zippers -/
|
||||
|
||||
/-! ### zip -/
|
||||
|
|
@ -2127,6 +2334,25 @@ theorem get?_zipWithAll {f : Option α → Option β → γ} :
|
|||
set_option linter.deprecated false in
|
||||
@[deprecated getElem?_zipWithAll (since := "2024-06-07")] abbrev zipWithAll_get? := @get?_zipWithAll
|
||||
|
||||
theorem zipWithAll_map {μ} (f : Option γ → Option δ → μ) (g : α → γ) (h : β → δ) (l₁ : List α) (l₂ : List β) :
|
||||
zipWithAll f (l₁.map g) (l₂.map h) = zipWithAll (fun a b => f (g <$> a) (h <$> b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
theorem zipWithAll_map_left (l₁ : List α) (l₂ : List β) (f : α → α') (g : Option α' → Option β → γ) :
|
||||
zipWithAll g (l₁.map f) l₂ = zipWithAll (fun a b => g (f <$> a) b) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
theorem zipWithAll_map_right (l₁ : List α) (l₂ : List β) (f : β → β') (g : Option α → Option β' → γ) :
|
||||
zipWithAll g l₁ (l₂.map f) = zipWithAll (fun a b => g a (f <$> b)) l₁ l₂ := by
|
||||
induction l₁ generalizing l₂ <;> cases l₂ <;> simp_all
|
||||
|
||||
theorem map_zipWithAll {δ : Type _} (f : α → β) (g : Option γ → Option δ → α) (l : List γ) (l' : List δ) :
|
||||
map f (zipWithAll g l l') = zipWithAll (fun x y => f (g x y)) l l' := by
|
||||
induction l generalizing l' with
|
||||
| nil => simp
|
||||
| cons hd tl hl =>
|
||||
cases l' <;> simp_all
|
||||
|
||||
@[simp] theorem zipWithAll_replicate {a : α} {b : β} {n : Nat} :
|
||||
zipWithAll f (replicate n a) (replicate n b) = replicate n (f a b) := by
|
||||
induction n with
|
||||
|
|
@ -2149,6 +2375,10 @@ set_option linter.deprecated false in
|
|||
| _, [] => rfl
|
||||
| _, _ :: _ => congrArg Nat.succ enumFrom_length
|
||||
|
||||
theorem map_enumFrom (f : α → β) (n : Nat) (l : List α) :
|
||||
map (Prod.map id f) (enumFrom n l) = enumFrom n (map f l) := by
|
||||
induction l generalizing n <;> simp_all
|
||||
|
||||
/-! ### enum -/
|
||||
|
||||
@[simp] theorem enum_length : (enum l).length = l.length :=
|
||||
|
|
@ -2156,6 +2386,9 @@ set_option linter.deprecated false in
|
|||
|
||||
theorem enum_cons : (a::as).enum = (0, a) :: as.enumFrom 1 := rfl
|
||||
|
||||
theorem map_enum (f : α → β) (l : List α) : map (Prod.map id f) (enum l) = enum (map f l) :=
|
||||
map_enumFrom f 0 l
|
||||
|
||||
/-! ## Minima and maxima -/
|
||||
|
||||
/-! ### minimum? -/
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ theorem take_reverse {α} {xs : List α} (n : Nat) (h : n ≤ xs.length) :
|
|||
have : (n + 1) % m < m := Nat.mod_lt _ (by omega)
|
||||
omega
|
||||
|
||||
/-! ### rotateLeft -/
|
||||
/-! ### rotateRight -/
|
||||
|
||||
@[simp] theorem rotateRight_replicate (n) (a : α) : rotateRight (replicate m a) n = replicate m a := by
|
||||
cases n with
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ theorem mul_neg_left (xs ys : IntList) : (-xs) * ys = -(xs * ys) := by
|
|||
attribute [local simp] add_def neg_def sub_def in
|
||||
theorem sub_eq_add_neg (xs ys : IntList) : xs - ys = xs + (-ys) := by
|
||||
induction xs generalizing ys with
|
||||
| nil => simp; rfl
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
cases ys with
|
||||
| nil => simp
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@ variable {α : Type _}
|
|||
variable {x y z : α}
|
||||
variable (l l₁ l₂ l₃ : List α)
|
||||
|
||||
variable {β : Type _}
|
||||
variable {f g : α → β}
|
||||
|
||||
variable {γ : Type _}
|
||||
variable {f' : β → γ}
|
||||
|
||||
variable (m n : Nat)
|
||||
|
||||
/-! ## Preliminaries -/
|
||||
|
|
@ -52,6 +58,52 @@ variable (m n : Nat)
|
|||
|
||||
/-! ### map -/
|
||||
|
||||
#check_simp l.map id ~> l
|
||||
#check_simp l.map (fun x => x) ~> l
|
||||
#check_simp [].map f ~> []
|
||||
#check_simp [x].map f ~> [f x]
|
||||
|
||||
#check_simp map f l = map g l ~> ∀ a ∈ l, f a = g a
|
||||
variable (l : List Nat) in
|
||||
#check_simp map (· + 1) l = map (·.succ) l ~> True
|
||||
variable (l : List Nat) in
|
||||
#check_simp map (0 * ·) l ~> map (fun _ => 0) l
|
||||
variable (l : List String) in
|
||||
#check_simp map (fun s => s ++ s) ("a" :: l) ~> "aa" :: map (fun s => s ++ s) l
|
||||
|
||||
#check_simp l.map f = [] ~> l = []
|
||||
|
||||
variable (w : l ≠ []) in
|
||||
#check_simp head (l.map f) (by simpa) ~> f (head l (by simpa))
|
||||
variable (l : List String) in
|
||||
#check_simp head (("a" :: l).map fun s => s ++ s) (by simp) ~> "aa"
|
||||
|
||||
variable (w : l ≠ []) in
|
||||
#check_simp getLast (l.map f) (by simpa) ~> f (getLast l (by simpa))
|
||||
|
||||
#check_simp (l₁ ++ l₂).map f ~> l₁.map f ++ l₂.map f
|
||||
#check_simp (l.map f).map f' ~> l.map (f' ∘ f)
|
||||
#check_simp (concat l x).map f ~> map f l ++ [f x]
|
||||
|
||||
variable (L : List (List α)) in
|
||||
#check_simp L.join.map f ~> (L.map (map f)).join
|
||||
#check_simp [l₁, l₂].join.map f ~> map f l₁ ++ map f l₂
|
||||
|
||||
#check_simp l.map (Function.const α "1") ~> replicate l.length "1"
|
||||
#check_simp [x, y].map (Function.const α "1") ~> ["1", "1"]
|
||||
|
||||
#check_simp l.reverse.map f ~> (l.map f).reverse
|
||||
|
||||
#check_simp (l.take 3).map f ~> (l.map f).take 3
|
||||
#check_simp (l.drop 3).map f ~> (l.map f).drop 3
|
||||
|
||||
#check_simp l.dropLast.map f ~> (l.map f).dropLast
|
||||
|
||||
variable (p : β → Bool) in
|
||||
#check_simp (l.map f).find? p ~> (l.find? (p ∘ f)).map f
|
||||
variable (p : β → Option γ) in
|
||||
#check_simp (l.map f).findSome? p ~> l.findSome? (p ∘ f)
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue