Skip to content

Commit 2a1d083

Browse files
committed
feat: add lemmas about List.scanr (#26838)
I add basic lemmas to reason about List.scanr, and slightly clean-up the file and add some basic lemmas to keep the API unified with the one for List.scanl. Original PR: #25188 Co-authored-by: Vlad Tsyrklevich <vlad902@gmail.com>
1 parent bd6f86a commit 2a1d083

File tree

1 file changed

+87
-19
lines changed

1 file changed

+87
-19
lines changed

Mathlib/Data/List/Scan.lean

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,50 @@ import Mathlib.Order.Basic
88
import Mathlib.Data.Nat.Basic
99
import Mathlib.Data.Option.Basic
1010

11-
/-! ### List.scanl and List.scanr -/
11+
/-!
12+
# List scan
13+
14+
Prove basic results about `List.scanl` and `List.scanr`.
15+
-/
1216

1317
open Nat
1418

1519
namespace List
1620

1721
variable {α β : Type*} {f : β → α → β} {b : β} {a : α} {l : List α}
1822

19-
theorem length_scanl : ∀ a l, length (scanl f a l) = l.length + 1
20-
| _, [] => rfl
21-
| a, x :: l => by
22-
rw [scanl, length_cons, length_cons, ← succ_eq_add_one, congr_arg succ]
23-
exact length_scanl _ _
23+
/-! ### List.scanl -/
24+
25+
@[simp]
26+
theorem length_scanl (b : β) (l : List α) : length (scanl f b l) = l.length + 1 := by
27+
induction l generalizing b <;> simp_all
2428

2529
@[simp]
26-
theorem scanl_nil (b : β) : scanl f b nil = [b] :=
30+
theorem scanl_nil (b : β) : scanl f b [] = [b] :=
2731
rfl
2832

33+
@[simp]
34+
theorem scanl_ne_nil : scanl f b l ≠ [] := by
35+
cases l <;> simp
36+
37+
@[simp]
38+
theorem scanl_iff_nil (c : β) : scanl f b l = [c] ↔ c = b ∧ l = [] := by
39+
constructor <;> cases l <;> simp_all
40+
2941
@[simp]
3042
theorem scanl_cons : scanl f b (a :: l) = [b] ++ scanl f (f b a) l := by
3143
simp only [scanl, singleton_append]
3244

33-
@[simp]
3445
theorem getElem?_scanl_zero : (scanl f b l)[0]? = some b := by
35-
cases l
36-
· simp
37-
· simp
46+
cases l <;> simp
47+
48+
@[simp]
49+
theorem getElem_scanl_zero : (scanl f b l)[0] = b := by
50+
cases l <;> simp
3851

3952
@[simp]
40-
theorem getElem_scanl_zero {h : 0 < (scanl f b l).length} : (scanl f b l)[0] = b := by
41-
cases l
42-
· simp
43-
· simp
53+
theorem head_scanl (h : scanl f b l ≠ []) : (scanl f b l).head h = b := by
54+
cases l <;> simp
4455

4556
theorem getElem?_succ_scanl {i : ℕ} : (scanl f b l)[i + 1]? =
4657
(scanl f b l)[i]?.bind fun x => l[i]?.map fun y => f x y := by
@@ -74,17 +85,74 @@ theorem getElem_succ_scanl {i : ℕ} (h : i + 1 < (scanl f b l).length) :
7485
· simp only [length, Nat.zero_add 1, succ_add_sub_one, hi]; rfl
7586
· simp only [length_singleton]; omega
7687

77-
-- scanr
88+
/-! ### List.scanr -/
89+
90+
variable {f : α → β → β}
91+
7892
@[simp]
79-
theorem scanr_nil (f : α → β → β) (b : β) : scanr f b [] = [b] :=
93+
theorem scanr_nil (b : β) : scanr f b [] = [b] :=
8094
rfl
8195

8296
@[simp]
83-
theorem scanr_cons (f : α → β → β) (b : β) (a : α) (l : List α) :
84-
scanr f b (a :: l) = foldr f b (a :: l) :: scanr f b l := by
97+
theorem scanr_ne_nil : scanr f b l ≠ [] := by
98+
simp [scanr]
99+
100+
@[simp]
101+
theorem scanr_cons : scanr f b (a :: l) = foldr f b (a :: l) :: scanr f b l := by
85102
simp only [scanr, foldr, cons.injEq, and_true]
86103
induction l generalizing a with
87104
| nil => rfl
88105
| cons hd tl ih => simp only [foldr, ih]
89106

107+
@[simp]
108+
theorem scanr_iff_nil (c : β) : scanr f b l = [c] ↔ c = b ∧ l = [] := by
109+
constructor <;> cases l <;> simp_all
110+
111+
@[simp]
112+
theorem length_scanr (b : β) (l : List α) : length (scanr f b l) = l.length + 1 := by
113+
induction l <;> simp_all
114+
115+
theorem scanr_append (l₁ l₂ : List α) :
116+
scanr f b (l₁ ++ l₂) = (scanr f (foldr f b l₂) l₁) ++ (scanr f b l₂).tail := by
117+
induction l₁ <;> induction l₂ <;> simp [*]
118+
119+
@[simp]
120+
theorem head_scanr (h : scanr f b l ≠ []) : (scanr f b l).head h = foldr f b l := by
121+
cases l <;> simp
122+
123+
theorem tail_scanr (h : 0 < l.length) : (scanr f b l).tail = scanr f b l.tail := by
124+
induction l <;> simp_all
125+
126+
theorem drop_scanr {i : ℕ} (h : i ≤ l.length) : (scanr f b l).drop i = scanr f b (l.drop i) := by
127+
induction i with
128+
| zero => simp
129+
| succ i ih =>
130+
rw [← drop_drop]
131+
simp [ih (by omega), tail_scanr (l := l.drop i) (by rw [length_drop]; omega)]
132+
133+
@[simp]
134+
theorem getElem_scanr_zero : (scanr f b l)[0] = foldr f b l := by
135+
cases l <;> simp
136+
137+
theorem getElem?_scanr_zero : (scanr f b l)[0]? = foldr f b l := by
138+
simp
139+
140+
theorem getElem_scanr {i : ℕ} (h : i < (scanr f b l).length) :
141+
(scanr f b l)[i] = foldr f b (l.drop i) := by
142+
induction l generalizing i with
143+
| nil => simp
144+
| cons head tail ih =>
145+
obtain rfl | h' := eq_or_ne i 0
146+
· simp
147+
· obtain ⟨m, rfl⟩ := Nat.exists_eq_succ_of_ne_zero h'
148+
simp [@ih m (by simp_all [length_scanr])]
149+
150+
theorem getElem?_scanr {i : ℕ} (h : i < l.length + 1) :
151+
(scanr f b l)[i]? = if i < l.length + 1 then some (foldr f b (l.drop i)) else none := by
152+
split <;> simp_all [getElem_scanr]
153+
154+
theorem getElem?_scanr_of_lt {i : ℕ} (h : i < l.length + 1) :
155+
(scanr f b l)[i]? = some (foldr f b (l.drop i)) := by
156+
simpa [getElem?_scanr h]
157+
90158
end List

0 commit comments

Comments
 (0)