-
Notifications
You must be signed in to change notification settings - Fork 89
/
Monadic.lean
154 lines (141 loc) · 7.61 KB
/
Monadic.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/-
Copyright (c) 2021 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Gabriel Ebner
-/
import Batteries.Classes.SatisfiesM
/-!
# Results about monadic operations on `Array`, in terms of `SatisfiesM`.
The pure versions of these theorems are proved in `Batteries.Data.Array.Lemmas` directly,
in order to minimize dependence on `SatisfiesM`.
-/
namespace Array
theorem SatisfiesM_foldlM [Monad m] [LawfulMonad m]
{as : Array α} (motive : Nat → β → Prop) {init : β} (h0 : motive 0 init) {f : β → α → m β}
(hf : ∀ i : Fin as.size, ∀ b, motive i.1 b → SatisfiesM (motive (i.1 + 1)) (f b as[i])) :
SatisfiesM (motive as.size) (as.foldlM f init) := by
let rec go {i j b} (h₁ : j ≤ as.size) (h₂ : as.size ≤ i + j) (H : motive j b) :
SatisfiesM (motive as.size) (foldlM.loop f as as.size (Nat.le_refl _) i j b) := by
unfold foldlM.loop; split
· next hj =>
split
· cases Nat.not_le_of_gt (by simp [hj]) h₂
· exact (hf ⟨j, hj⟩ b H).bind fun _ => go hj (by rwa [Nat.succ_add] at h₂)
· next hj => exact Nat.le_antisymm h₁ (Nat.ge_of_not_lt hj) ▸ .pure H
simp [foldlM]; exact go (Nat.zero_le _) (Nat.le_refl _) h0
theorem SatisfiesM_mapM [Monad m] [LawfulMonad m] (as : Array α) (f : α → m β)
(motive : Nat → Prop) (h0 : motive 0)
(p : Fin as.size → β → Prop)
(hs : ∀ i, motive i.1 → SatisfiesM (p i · ∧ motive (i + 1)) (f as[i])) :
SatisfiesM
(fun arr => motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i])
(Array.mapM f as) := by
rw [mapM_eq_foldlM]
refine SatisfiesM_foldlM (m := m) (β := Array β)
(motive := fun i arr => motive i ∧ arr.size = i ∧ ∀ i h2, p i (arr[i.1]'h2)) ?z ?s
|>.imp fun ⟨h₁, eq, h₂⟩ => ⟨h₁, eq, fun _ _ => h₂ ..⟩
· case z => exact ⟨h0, rfl, nofun⟩
· case s =>
intro ⟨i, hi⟩ arr ⟨ih₁, eq, ih₂⟩
refine (hs _ ih₁).map fun ⟨h₁, h₂⟩ => ⟨h₂, by simp [eq], fun j hj => ?_⟩
simp [get_push] at hj ⊢; split; {apply ih₂}
cases j; cases (Nat.le_or_eq_of_le_succ hj).resolve_left ‹_›; cases eq; exact h₁
theorem SatisfiesM_mapM' [Monad m] [LawfulMonad m] (as : Array α) (f : α → m β)
(p : Fin as.size → β → Prop)
(hs : ∀ i, SatisfiesM (p i) (f as[i])) :
SatisfiesM
(fun arr => ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i])
(Array.mapM f as) :=
(SatisfiesM_mapM _ _ (fun _ => True) trivial _ (fun _ h => (hs _).imp (⟨·, h⟩))).imp (·.2)
theorem size_mapM [Monad m] [LawfulMonad m] (f : α → m β) (as : Array α) :
SatisfiesM (fun arr => arr.size = as.size) (Array.mapM f as) :=
(SatisfiesM_mapM' _ _ (fun _ _ => True) (fun _ => .trivial)).imp (·.1)
theorem SatisfiesM_anyM [Monad m] [LawfulMonad m] (p : α → m Bool) (as : Array α) (start stop)
(hstart : start ≤ min stop as.size) (tru : Prop) (fal : Nat → Prop) (h0 : fal start)
(hp : ∀ i : Fin as.size, i.1 < stop → fal i.1 →
SatisfiesM (bif · then tru else fal (i + 1)) (p as[i])) :
SatisfiesM
(fun res => bif res then tru else fal (min stop as.size))
(anyM p as start stop) := by
let rec go {stop j} (hj' : j ≤ stop) (hstop : stop ≤ as.size) (h0 : fal j)
(hp : ∀ i : Fin as.size, i.1 < stop → fal i.1 →
SatisfiesM (bif · then tru else fal (i + 1)) (p as[i])) :
SatisfiesM
(fun res => bif res then tru else fal stop)
(anyM.loop p as stop hstop j) := by
unfold anyM.loop; split
· next hj =>
exact (hp ⟨j, Nat.lt_of_lt_of_le hj hstop⟩ hj h0).bind fun
| true, h => .pure h
| false, h => go hj hstop h hp
· next hj => exact .pure <| Nat.le_antisymm hj' (Nat.ge_of_not_lt hj) ▸ h0
termination_by stop - j
simp only [Array.anyM_eq_anyM_loop]
exact go hstart _ h0 fun i hi => hp i <| Nat.lt_of_lt_of_le hi <| Nat.min_le_left ..
theorem SatisfiesM_anyM_iff_exists [Monad m] [LawfulMonad m]
(p : α → m Bool) (as : Array α) (start stop) (q : Fin as.size → Prop)
(hp : ∀ i : Fin as.size, start ≤ i.1 → i.1 < stop → SatisfiesM (· = true ↔ q i) (p as[i])) :
SatisfiesM
(fun res => res = true ↔ ∃ i : Fin as.size, start ≤ i.1 ∧ i.1 < stop ∧ q i)
(anyM p as start stop) := by
cases Nat.le_total start (min stop as.size) with
| inl hstart =>
refine (SatisfiesM_anyM _ _ _ _ hstart
(fal := fun j => start ≤ j ∧ ¬ ∃ i : Fin as.size, start ≤ i.1 ∧ i.1 < j ∧ q i)
(tru := ∃ i : Fin as.size, start ≤ i.1 ∧ i.1 < stop ∧ q i) ?_ ?_).imp ?_
· exact ⟨Nat.le_refl _, fun ⟨i, h₁, h₂, _⟩ => (Nat.not_le_of_gt h₂ h₁).elim⟩
· refine fun i h₂ ⟨h₁, h₃⟩ => (hp _ h₁ h₂).imp fun hq => ?_
unfold cond; split <;> simp at hq
· exact ⟨_, h₁, h₂, hq⟩
· refine ⟨Nat.le_succ_of_le h₁, h₃.imp fun ⟨j, h₃, h₄, h₅⟩ => ⟨j, h₃, ?_, h₅⟩⟩
refine Nat.lt_of_le_of_ne (Nat.le_of_lt_succ h₄) fun e => hq (Fin.eq_of_val_eq e ▸ h₅)
· intro
| true, h => simp only [true_iff]; exact h
| false, h =>
simp only [false_iff]
exact h.2.imp fun ⟨j, h₁, h₂, hq⟩ => ⟨j, h₁, Nat.lt_min.2 ⟨h₂, j.2⟩, hq⟩
| inr hstart =>
rw [anyM_stop_le_start (h := hstart)]
refine .pure ?_; simp; intro j h₁ h₂
cases Nat.not_lt.2 (Nat.le_trans hstart h₁) (Nat.lt_min.2 ⟨h₂, j.2⟩)
theorem SatisfiesM_foldrM [Monad m] [LawfulMonad m]
{as : Array α} (motive : Nat → β → Prop)
{init : β} (h0 : motive as.size init) {f : α → β → m β}
(hf : ∀ i : Fin as.size, ∀ b, motive (i.1 + 1) b → SatisfiesM (motive i.1) (f as[i] b)) :
SatisfiesM (motive 0) (as.foldrM f init) := by
let rec go {i b} (hi : i ≤ as.size) (H : motive i b) :
SatisfiesM (motive 0) (foldrM.fold f as 0 i hi b) := by
unfold foldrM.fold; simp; split
· next hi => exact .pure (hi ▸ H)
· next hi =>
split; {simp at hi}
· next i hi' =>
exact (hf ⟨i, hi'⟩ b H).bind fun _ => go _
simp [foldrM]; split; {exact go _ h0}
· next h => exact .pure (Nat.eq_zero_of_not_pos h ▸ h0)
theorem SatisfiesM_mapIdxM [Monad m] [LawfulMonad m] (as : Array α) (f : Fin as.size → α → m β)
(motive : Nat → Prop) (h0 : motive 0)
(p : Fin as.size → β → Prop)
(hs : ∀ i, motive i.1 → SatisfiesM (p i · ∧ motive (i + 1)) (f i as[i])) :
SatisfiesM
(fun arr => motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i])
(Array.mapIdxM as f) := by
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p ⟨i, h⟩ bs[i]) (hm : motive j) :
SatisfiesM
(fun arr => motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i])
(Array.mapIdxM.map as f i j h bs) := by
induction i generalizing j bs with simp [mapIdxM.map]
| zero =>
have := (Nat.zero_add _).symm.trans h
exact .pure ⟨this ▸ hm, h₁ ▸ this, fun _ _ => h₂ ..⟩
| succ i ih =>
refine (hs _ (by exact hm)).bind fun b hb => ih (by simp [h₁]) (fun i hi hi' => ?_) hb.2
simp at hi'; simp [get_push]; split
· next h => exact h₂ _ _ h
· next h => cases h₁.symm ▸ (Nat.le_or_eq_of_le_succ hi').resolve_left h; exact hb.1
simp [mapIdxM]; exact go rfl nofun h0
theorem size_modifyM [Monad m] [LawfulMonad m] (a : Array α) (i : Nat) (f : α → m α) :
SatisfiesM (·.size = a.size) (a.modifyM i f) := by
unfold modifyM; split
· exact .bind_pre <| .of_true fun _ => .pure <| by simp only [size_set]
· exact .pure rfl