Skip to content

Commit 48ca97e

Browse files
authored
feat: add List/Array/Vector.ofFnM (#8389)
This PR adds the `List/Array/Vector.ofFnM`, the monadic analogues of `ofFn`, along with basic theory. At the same time we pave some potholes in nearby API.
1 parent c8290bd commit 48ca97e

File tree

15 files changed

+458
-25
lines changed

15 files changed

+458
-25
lines changed

src/Init/Data/Array/Basic.lean

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
112112
rw [Array.mem_def, ← getElem_toList]
113113
apply List.getElem_mem
114114

115+
@[simp, grind] theorem mkEmpty_eq_empty {n : Nat} : (mkEmpty n : Array α) = #[] := rfl
116+
115117
end Array
116118

117119
namespace List
@@ -334,6 +336,8 @@ def ofFn {n} (f : Fin n → α) : Array α := go 0 (emptyWithCapacity n) where
334336
if h : i < n then go (i+1) (acc.push (f ⟨i, h⟩)) else acc
335337
decreasing_by simp_wf; decreasing_trivial_pre_omega
336338
339+
-- See also `Array.ofFnM` defined in `Init.Data.Array.OfFn`.
340+
337341
/--
338342
Constructs an array that contains all the numbers from `0` to `n`, exclusive.
339343

src/Init/Data/Array/Lemmas.lean

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,12 @@ theorem back?_pop {xs : Array α} :
247247

248248
/-! ### push -/
249249

250+
@[simp] theorem push_empty : #[].push x = #[x] := rfl
251+
252+
@[simp] theorem toList_push {xs : Array α} {x : α} : (xs.push x).toList = xs.toList ++ [x] := by
253+
rcases xs with ⟨xs⟩
254+
simp
255+
250256
@[simp] theorem push_ne_empty {a : α} {xs : Array α} : xs.push a ≠ #[] := by
251257
cases xs
252258
simp
@@ -3266,6 +3272,22 @@ rather than `(arr.push a).size` as the argument.
32663272
(xs.push a).foldrM f init start = f a init >>= xs.foldrM f := by
32673273
simp [← foldrM_push, h]
32683274

3275+
@[simp, grind] theorem _root_.List.foldrM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
3276+
l.foldrM (fun x xs => xs.push <$> f x) xs = do return xs ++ (← l.reverse.mapM f).toArray := by
3277+
induction l with
3278+
| nil => simp
3279+
| cons a l ih =>
3280+
simp [ih]
3281+
congr 1
3282+
funext l'
3283+
congr 1
3284+
funext x
3285+
simp
3286+
3287+
@[simp, grind] theorem _root_.List.foldlM_push_eq_append [Monad m] [LawfulMonad m] {l : List α} {f : α → m β} {xs : Array β} :
3288+
l.foldlM (fun xs x => xs.push <$> f x) xs = do return xs ++ (← l.mapM f).toArray := by
3289+
induction l generalizing xs <;> simp [*]
3290+
32693291
/-! ### foldl / foldr -/
32703292

32713293
@[grind] theorem foldl_empty {f : β → α → β} {init : β} : (#[].foldl f init) = init := rfl
@@ -3362,6 +3384,24 @@ rather than `(arr.push a).size` as the argument.
33623384
rcases as with ⟨as⟩
33633385
simp
33643386

3387+
@[simp, grind] theorem _root_.List.foldr_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
3388+
l.foldr (fun x xs => xs.push (f x)) xs = xs ++ (l.reverse.map f).toArray := by
3389+
induction l <;> simp [*]
3390+
3391+
/-- Variant of `List.foldr_push_eq_append` specialized to `f = id`. -/
3392+
@[simp, grind] theorem _root_.List.foldr_push_eq_append' {l : List α} {xs : Array α} :
3393+
l.foldr (fun x xs => xs.push x) xs = xs ++ l.reverse.toArray := by
3394+
induction l <;> simp [*]
3395+
3396+
@[simp, grind] theorem _root_.List.foldl_push_eq_append {l : List α} {f : α → β} {xs : Array β} :
3397+
l.foldl (fun xs x => xs.push (f x)) xs = xs ++ (l.map f).toArray := by
3398+
induction l generalizing xs <;> simp [*]
3399+
3400+
/-- Variant of `List.foldl_push_eq_append` specialized to `f = id`. -/
3401+
@[simp, grind] theorem _root_.List.foldl_push_eq_append' {l : List α} {xs : Array α} :
3402+
l.foldl (fun xs x => xs.push x) xs = xs ++ l.toArray := by
3403+
induction l <;> simp [*]
3404+
33653405
@[simp, grind] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
33663406
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
33673407
rcases xs with ⟨xs⟩

src/Init/Data/Array/Monadic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ open Nat
3434
@[simp] theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
3535
mapM_pure
3636

37+
@[simp] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Array α} :
38+
(xs.map f).mapM g = xs.mapM (g ∘ f) := by
39+
rcases xs with ⟨xs⟩
40+
simp
41+
3742
@[simp] theorem mapM_append [Monad m] [LawfulMonad m] {f : α → m β} {xs ys : Array α} :
3843
(xs ++ ys).mapM f = (return (← xs.mapM f) ++ (← ys.mapM f)) := by
3944
rcases xs with ⟨xs⟩

src/Init/Data/Array/OfFn.lean

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ prelude
99
import all Init.Data.Array.Basic
1010
import Init.Data.Array.Lemmas
1111
import Init.Data.List.OfFn
12+
import Init.Data.List.FinRange
1213

1314
/-!
1415
# Theorems about `Array.ofFn`
@@ -17,8 +18,42 @@ import Init.Data.List.OfFn
1718
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
1819
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
1920

21+
namespace List
22+
23+
/-! ### ofFnM
24+
25+
We prove some theorems about `List.ofFnM` here, as they rely on `Array` lemmas.
26+
-/
27+
28+
theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
29+
ofFnM f = (do
30+
let a ← f 0
31+
let as ← ofFnM fun i => f i.succ
32+
pure (a :: as)) := by
33+
simp [ofFnM, Fin.foldlM_eq_finRange_foldlM, List.foldlM_push_eq_append, List.finRange_succ, Function.comp_def]
34+
35+
theorem ofFnM_succ_last {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
36+
ofFnM f = (do
37+
let as ← ofFnM fun i => f i.castSucc
38+
let a ← f (Fin.last n)
39+
pure (as ++ [a])) := by
40+
simp [ofFnM, Fin.foldlM_succ_last]
41+
42+
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
43+
ofFnM f = (do
44+
let as ← ofFnM fun i : Fin n => f (i.castLE (Nat.le_add_right n k))
45+
let bs ← ofFnM fun i : Fin k => f (i.natAdd n)
46+
pure (as ++ bs)) := by
47+
induction k with
48+
| zero => simp
49+
| succ k ih => simp [ofFnM_succ_last, ih]
50+
51+
end List
52+
2053
namespace Array
2154

55+
/-! ### ofFn -/
56+
2257
@[simp] theorem ofFn_zero {f : Fin 0 → α} : ofFn f = #[] := by
2358
simp [ofFn, ofFn.go]
2459

@@ -32,12 +67,23 @@ theorem ofFn_succ {f : Fin (n+1) → α} :
3267
intro h₃
3368
simp only [show i = n by omega]
3469

70+
theorem ofFn_add {n m} {f : Fin (n + m) → α} :
71+
ofFn f = (ofFn (fun i => f (i.castLE (Nat.le_add_right n m)))) ++ (ofFn (fun i => f (i.natAdd n))) := by
72+
induction m with
73+
| zero => simp
74+
| succ m ih => simp [ofFn_succ, ih]
75+
3576
@[simp] theorem _root_.List.toArray_ofFn {f : Fin n → α} : (List.ofFn f).toArray = Array.ofFn f := by
3677
ext <;> simp
3778

3879
@[simp] theorem toList_ofFn {f : Fin n → α} : (Array.ofFn f).toList = List.ofFn f := by
3980
apply List.ext_getElem <;> simp
4081

82+
theorem ofFn_succ' {f : Fin (n+1) → α} :
83+
ofFn f = #[f 0] ++ ofFn (fun i => f i.succ) := by
84+
apply Array.toList_inj.mp
85+
simp [List.ofFn_succ]
86+
4187
@[simp]
4288
theorem ofFn_eq_empty_iff {f : Fin n → α} : ofFn f = #[] ↔ n = 0 := by
4389
rw [← Array.toList_inj]
@@ -52,4 +98,52 @@ theorem mem_ofFn {n} {f : Fin n → α} {a : α} : a ∈ ofFn f ↔ ∃ i, f i =
5298
· rintro ⟨i, rfl⟩
5399
apply mem_of_getElem (i := i) <;> simp
54100

101+
/-! ### ofFnM -/
102+
103+
/-- Construct (in a monadic context) an array by applying a monadic function to each index. -/
104+
def ofFnM {n} [Monad m] (f : Fin n → m α) : m (Array α) :=
105+
Fin.foldlM n (fun xs i => xs.push <$> f i) (Array.mkEmpty n)
106+
107+
@[simp]
108+
theorem ofFnM_zero [Monad m] {f : Fin 0 → m α} : ofFnM f = pure #[] := by
109+
simp [ofFnM]
110+
111+
theorem ofFnM_succ' {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
112+
ofFnM f = (do
113+
let a ← f 0
114+
let as ← ofFnM fun i => f i.succ
115+
pure (#[a] ++ as)) := by
116+
simp [ofFnM, Fin.foldlM_eq_finRange_foldlM, List.foldlM_push_eq_append, List.finRange_succ, Function.comp_def]
117+
118+
theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
119+
ofFnM f = (do
120+
let as ← ofFnM fun i => f i.castSucc
121+
let a ← f (Fin.last n)
122+
pure (as.push a)) := by
123+
simp [ofFnM, Fin.foldlM_succ_last]
124+
125+
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
126+
ofFnM f = (do
127+
let as ← ofFnM fun i : Fin n => f (i.castLE (Nat.le_add_right n k))
128+
let bs ← ofFnM fun i : Fin k => f (i.natAdd n)
129+
pure (as ++ bs)) := by
130+
induction k with
131+
| zero => simp
132+
| succ k ih =>
133+
simp only [ofFnM_succ, Nat.add_eq, ih, Fin.castSucc_castLE, Fin.castSucc_natAdd, bind_pure_comp,
134+
bind_assoc, bind_map_left, Fin.natAdd_last, map_bind, Functor.map_map]
135+
congr 1
136+
funext xs
137+
congr 1
138+
funext ys
139+
congr 1
140+
funext x
141+
simp
142+
143+
@[simp] theorem toList_ofFnM [Monad m] [LawfulMonad m] {f : Fin n → m α} :
144+
toList <$> ofFnM f = List.ofFnM f := by
145+
induction n with
146+
| zero => simp
147+
| succ n ih => simp [ofFnM_succ, List.ofFnM_succ_last, ← ih]
148+
55149
end Array

src/Init/Data/Fin/Fold.lean

Lines changed: 100 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ Fin.foldrM n f xₙ = do
100100

101101
/-! ### foldlM -/
102102

103+
@[congr] theorem foldlM_congr [Monad m] {n k : Nat} (w : n = k) (f : α → Fin n → m α) :
104+
foldlM n f = foldlM k (fun x i => f x (i.cast w.symm)) := by
105+
subst w
106+
rfl
107+
103108
theorem foldlM_loop_lt [Monad m] (f : α → Fin n → m α) (x) (h : i < n) :
104109
foldlM.loop n f x i = f x ⟨i, h⟩ >>= (foldlM.loop n f . (i+1)) := by
105110
rw [foldlM.loop, dif_pos h]
@@ -120,14 +125,49 @@ theorem foldlM_loop [Monad m] (f : α → Fin (n+1) → m α) (x) (h : i < n+1)
120125
rw [foldlM_loop_eq, foldlM_loop_eq]
121126
termination_by n - i
122127

123-
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) (x) : foldlM 0 f x = pure x :=
124-
foldlM_loop_eq ..
128+
@[simp] theorem foldlM_zero [Monad m] (f : α → Fin 0 → m α) : foldlM 0 f = pure := by
129+
funext x
130+
exact foldlM_loop_eq ..
131+
132+
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) :
133+
foldlM (n+1) f = fun x => f x 0 >>= foldlM n (fun x j => f x j.succ) := by
134+
funext x
135+
exact foldlM_loop ..
125136

126-
theorem foldlM_succ [Monad m] (f : α → Fin (n+1) → m α) (x) :
127-
foldlM (n+1) f x = f x 0 >>= foldlM n (fun x j => f x j.succ) := foldlM_loop ..
137+
/-- Variant of `foldlM_succ` that splits off `Fin.last n` rather than `0`. -/
138+
theorem foldlM_succ_last [Monad m] [LawfulMonad m] (f : α → Fin (n+1) → m α) :
139+
foldlM (n+1) f = fun x => foldlM n (fun x j => f x j.castSucc) x >>= (f · (Fin.last n)) := by
140+
funext x
141+
induction n generalizing x with
142+
| zero =>
143+
simp [foldlM_succ]
144+
| succ n ih =>
145+
rw [foldlM_succ]
146+
conv => rhs; rw [foldlM_succ]
147+
simp only [castSucc_zero, castSucc_succ, bind_assoc]
148+
congr 1
149+
funext x
150+
rw [ih]
151+
simp
152+
153+
theorem foldlM_add [Monad m] [LawfulMonad m] (f : α → Fin (n + k) → m α) :
154+
foldlM (n + k) f =
155+
fun x => foldlM n (fun x i => f x (i.castLE (Nat.le_add_right n k))) x >>= foldlM k (fun x i => f x (i.natAdd n)) := by
156+
induction k with
157+
| zero =>
158+
funext x
159+
simp
160+
| succ k ih =>
161+
funext x
162+
simp [foldlM_succ_last, ← Nat.add_assoc, ih]
128163

129164
/-! ### foldrM -/
130165

166+
@[congr] theorem foldrM_congr [Monad m] {n k : Nat} (w : n = k) (f : Fin n → α → m α) :
167+
foldrM n f = foldrM k (fun i => f (i.cast w.symm)) := by
168+
subst w
169+
rfl
170+
131171
theorem foldrM_loop_zero [Monad m] (f : Fin n → α → m α) (x) :
132172
foldrM.loop n f ⟨0, Nat.zero_le _⟩ x = pure x := by
133173
rw [foldrM.loop]
@@ -145,19 +185,46 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
145185
conv => rhs; rw [←bind_pure (f 0 x)]
146186
congr
147187
funext
148-
try simp only [foldrM.loop] -- the try makes this proof work with and without opaque wf rec
149188
| succ i ih =>
150189
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
151190
congr; funext; exact ih ..
152191

153-
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) (x) : foldrM 0 f x = pure x :=
154-
foldrM_loop_zero ..
192+
@[simp] theorem foldrM_zero [Monad m] (f : Fin 0 → α → m α) : foldrM 0 f = pure := by
193+
funext x
194+
exact foldrM_loop_zero ..
155195

156-
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x) :
157-
foldrM (n+1) f x = foldrM n (fun i => f i.succ) x >>= f 0 := foldrM_loop ..
196+
theorem foldrM_succ [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) :
197+
foldrM (n+1) f = fun x => foldrM n (fun i => f i.succ) x >>= f 0 := by
198+
funext x
199+
exact foldrM_loop ..
200+
201+
theorem foldrM_succ_last [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) :
202+
foldrM (n+1) f = fun x => f (Fin.last n) x >>= foldrM n (fun i => f i.castSucc) := by
203+
funext x
204+
induction n generalizing x with
205+
| zero => simp [foldrM_succ]
206+
| succ n ih =>
207+
rw [foldrM_succ]
208+
conv => rhs; rw [foldrM_succ]
209+
simp [ih]
210+
211+
theorem foldrM_add [Monad m] [LawfulMonad m] (f : Fin (n + k) → α → m α) :
212+
foldrM (n + k) f =
213+
fun x => foldrM k (fun i => f (i.natAdd n)) x >>= foldrM n (fun i => f (i.castLE (Nat.le_add_right n k))) := by
214+
induction k with
215+
| zero =>
216+
simp
217+
| succ k ih =>
218+
funext x
219+
simp [foldrM_succ_last, ← Nat.add_assoc, ih]
158220

159221
/-! ### foldl -/
160222

223+
@[congr] theorem foldl_congr {n k : Nat} (w : n = k) (f : α → Fin n → α) :
224+
foldl n f = foldl k (fun x i => f x (i.cast w.symm)) := by
225+
subst w
226+
rfl
227+
161228
theorem foldl_loop_lt (f : α → Fin n → α) (x) (h : i < n) :
162229
foldl.loop n f x i = foldl.loop n f (f x ⟨i, h⟩) (i+1) := by
163230
rw [foldl.loop, dif_pos h]
@@ -187,14 +254,28 @@ theorem foldl_succ_last (f : α → Fin (n+1) → α) (x) :
187254
rw [foldl_succ]
188255
induction n generalizing x with
189256
| zero => simp [foldl_succ, Fin.last]
190-
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp [succ_castSucc]
257+
| succ n ih => rw [foldl_succ, ih (f · ·.succ), foldl_succ]; simp
258+
259+
theorem foldl_add (f : α → Fin (n + m) → α) (x) :
260+
foldl (n + m) f x =
261+
foldl m (fun x i => f x (i.natAdd n))
262+
(foldl n (fun x i => f x (i.castLE (Nat.le_add_right n m))) x):= by
263+
induction m with
264+
| zero => simp
265+
| succ m ih => simp [foldl_succ_last, ih, ← Nat.add_assoc]
266+
191267

192268
theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
193269
foldl n f x = foldlM (m:=Id) n f x := by
194270
induction n generalizing x <;> simp [foldl_succ, foldlM_succ, *]
195271

196272
/-! ### foldr -/
197273

274+
@[congr] theorem foldr_congr {n k : Nat} (w : n = k) (f : Fin n → α → α) :
275+
foldr n f = foldr k (fun i => f (i.cast w.symm)) := by
276+
subst w
277+
rfl
278+
198279
theorem foldr_loop_zero (f : Fin n → α → α) (x) :
199280
foldr.loop n f 0 (Nat.zero_le _) x = x := by
200281
rw [foldr.loop]
@@ -220,7 +301,15 @@ theorem foldr_succ_last (f : Fin (n+1) → α → α) (x) :
220301
foldr (n+1) f x = foldr n (f ·.castSucc) (f (last n) x) := by
221302
induction n generalizing x with
222303
| zero => simp [foldr_succ, Fin.last]
223-
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp [succ_castSucc]
304+
| succ n ih => rw [foldr_succ, ih (f ·.succ), foldr_succ]; simp
305+
306+
theorem foldr_add (f : Fin (n + m) → α → α) (x) :
307+
foldr (n + m) f x =
308+
foldr n (fun i => f (i.castLE (Nat.le_add_right n m)))
309+
(foldr m (fun i => f (i.natAdd n)) x) := by
310+
induction m generalizing x with
311+
| zero => simp
312+
| succ m ih => simp [foldr_succ_last, ih, ← Nat.add_assoc]
224313

225314
theorem foldr_eq_foldrM (f : Fin n → α → α) (x) :
226315
foldr n f x = foldrM (m:=Id) n f x := by

0 commit comments

Comments
 (0)