Skip to content

Commit 254202f

Browse files
committed
basic forIn support
1 parent 428ead0 commit 254202f

File tree

14 files changed

+232
-78
lines changed

14 files changed

+232
-78
lines changed

src/Std/Data/Iterators/Basic.lean

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,13 @@ def IterM.IsPlausibleSuccessorOf {α : Type w} {m : Type w → Type w'} {β : Ty
360360
(it' it : IterM (α := α) m β) : Prop :=
361361
∃ step, step.successor = some it' ∧ it.IsPlausibleStep step
362362

363+
inductive IterM.IsPlausibleIndirectOutput {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
364+
: IterM (α := α) m β → β → Prop where
365+
| direct {it : IterM (α := α) m β} {out : β} : it.IsPlausibleOutput out →
366+
it.IsPlausibleIndirectOutput out
367+
| indirect {it it' : IterM (α := α) m β} {out : β} : it'.IsPlausibleSuccessorOf it →
368+
it'.IsPlausibleIndirectOutput out → it.IsPlausibleIndirectOutput out
369+
363370
def IterM.IsInLineageOf {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
364371
(it' it : IterM (α := α) m β) : Prop :=
365372
it' = it ∨ Relation.TransGen IterM.IsPlausibleSuccessorOf it' it
@@ -475,6 +482,34 @@ def Iter.IsPlausibleSuccessorOf {α : Type w} {β : Type w} [Iterator α Id β]
475482
(it' it : Iter (α := α) β) : Prop :=
476483
it'.toIterM.IsPlausibleSuccessorOf it.toIterM
477484

485+
inductive Iter.IsPlausibleIndirectOutput {α β : Type w} [Iterator α Id β] :
486+
Iter (α := α) β → β → Prop where
487+
| direct {it : Iter (α := α) β} {out : β} : it.IsPlausibleOutput out →
488+
it.IsPlausibleIndirectOutput out
489+
| indirect {it it' : Iter (α := α) β} {out : β} : it'.IsPlausibleSuccessorOf it →
490+
it'.IsPlausibleIndirectOutput out → it.IsPlausibleIndirectOutput out
491+
492+
theorem Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM {α β : Type w}
493+
[Iterator α Id β] {it : Iter (α := α) β} {out : β} :
494+
it.IsPlausibleIndirectOutput out ↔ it.toIterM.IsPlausibleIndirectOutput out := by
495+
constructor
496+
· intro h
497+
induction h with
498+
| direct h =>
499+
exact .direct h
500+
| indirect h _ ih =>
501+
exact .indirect h ih
502+
· intro h
503+
rw [← Iter.toIter_toIterM (it := it)]
504+
generalize it.toIterM = it at ⊢ h
505+
induction h with
506+
| direct h =>
507+
exact .direct h
508+
| indirect h h' ih =>
509+
rename_i it it' out
510+
replace h : it'.toIter.IsPlausibleSuccessorOf it.toIter := h
511+
exact .indirect (α := α) h ih
512+
478513
/--
479514
Asserts that a certain iterator `it'` could plausibly be the directly succeeding iterator of another
480515
given iterator `it` while no value is emitted (see `IterStep.skip`).

src/Std/Data/Iterators/Combinators/Monadic/Take.lean

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,7 @@ instance Take.instIteratorLoop [Monad m] [Monad n] [Iterator α m β]
145145

146146
instance Take.instIteratorForPartial [Monad m] [Monad n] [Iterator α m β]
147147
[IteratorLoopPartial α m n] [MonadLiftT m n] :
148-
IteratorLoopPartial (Take α m β) m n where
149-
forInPartial lift {γ} it init f := do
150-
Prod.fst <$> IteratorLoopPartial.forInPartial lift it.internalState.inner (γ := γ × Nat)
151-
(init, it.internalState.remaining)
152-
fun out acc =>
153-
match acc.snd with
154-
| 0 => pure <| .done acc
155-
| n + 1 => (fun | .yield x => .yield ⟨x, n⟩ | .done x => .done ⟨x, n⟩) <$> f out acc.fst
148+
IteratorLoopPartial (Take α m β) m n :=
149+
.defaultImplementation
156150

157151
end Std.Iterators

src/Std/Data/Iterators/Combinators/Monadic/TakeWhile.lean

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ it terminates.
155155
-/
156156
@[always_inline, inline]
157157
def IterM.takeWhile [Monad m] (P : β → Bool) (it : IterM (α := α) m β) :=
158-
(it.takeWhileM (pure ∘ ULift.up ∘ P) : IterM m β)
158+
(it.takeWhileWithPostcondition (fun x => PostconditionT.pure (.up <| P x)) : IterM m β)
159159

160160
/--
161161
`it.PlausibleStep step` is the proposition that `step` is a possible next step from the
@@ -239,14 +239,7 @@ instance TakeWhile.instIteratorLoop [Monad m] [Monad n] [Iterator α m β]
239239

240240
instance TakeWhile.instIteratorLoopPartial [Monad m] [Monad n] [Iterator α m β]
241241
[IteratorLoopPartial α m n] [MonadLiftT m n] {P} :
242-
IteratorLoopPartial (TakeWhile α m β P) m n where
243-
forInPartial lift {γ} it init f := do
244-
IteratorLoopPartial.forInPartial lift it.internalState.inner (γ := γ)
245-
init
246-
fun out acc => do match ← (P out).operation with
247-
| ⟨.up true, _⟩ => match ← f out acc with
248-
| .yield c => pure (.yield c)
249-
| .done c => pure (.done c)
250-
| ⟨.up false, _⟩ => pure (.done acc)
242+
IteratorLoopPartial (TakeWhile α m β P) m n :=
243+
.defaultImplementation
251244

252245
end Std.Iterators

src/Std/Data/Iterators/Consumers/Loop.lean

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ namespace Std.Iterators
2424

2525
instance (α : Type w) (β : Type w) (n : Type w → Type w') [Monad n]
2626
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
27-
ForIn n (Iter (α := α) β) β where
28-
forIn it init f :=
29-
IteratorLoop.finiteForIn (fun δ (c : Id δ) => pure c.run) |>.forIn it.toIterM init f
27+
ForIn' n (Iter (α := α) β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
28+
forIn' it init f :=
29+
IteratorLoop.finiteForIn' (fun δ (c : Id δ) => pure c.run) |>.forIn' it.toIterM init
30+
fun out h acc =>
31+
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
3032

3133
instance (α : Type w) (β : Type w) (n : Type w → Type w') [Monad n]
3234
[Iterator α Id β] [IteratorLoopPartial α Id n] :

src/Std/Data/Iterators/Consumers/Monadic/Loop.lean

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ class IteratorLoop (α : Type w) (m : Type w → Type w') {β : Type w} [Iterato
6262
forIn : ∀ (_lift : (γ : Type w) → m γ → n γ) (γ : Type w),
6363
(plausible_forInStep : β → γ → ForInStep γ → Prop) →
6464
IteratorLoop.WellFounded α m plausible_forInStep →
65-
IterM (α := α) m β → γ →
66-
((b : β) → (c : γ) → n (Subtype (plausible_forInStep b c))) → n γ
65+
(it : IterM (α := α) m β) → γ →
66+
((b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (plausible_forInStep b c))) →
67+
n γ
6768

6869
/--
6970
`IteratorLoopPartial α m` provides efficient implementations of loop-based consumers for `α`-based
@@ -76,7 +77,8 @@ provided by the standard library.
7677
class IteratorLoopPartial (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β]
7778
(n : Type w → Type w'') where
7879
forInPartial : ∀ (_lift : (γ : Type w) → m γ → n γ) {γ : Type w},
79-
IterM (α := α) m β → γ → ((b : β) → (c : γ) → n (ForInStep γ)) → n γ
80+
(it : IterM (α := α) m β) → γ →
81+
((b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (ForInStep γ)) → n γ
8082

8183
class IteratorSize (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
8284
size : IterM (α := α) m β → m (ULift Nat)
@@ -115,16 +117,20 @@ def IterM.DefaultConsumers.forIn {m : Type w → Type w'} {α : Type w} {β : Ty
115117
(plausible_forInStep : β → γ → ForInStep γ → Prop)
116118
(wf : IteratorLoop.WellFounded α m plausible_forInStep)
117119
(it : IterM (α := α) m β) (init : γ)
118-
(f : (b : β) → (c : γ) → n (Subtype (plausible_forInStep b c))) : n γ :=
120+
(f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (plausible_forInStep b c))) : n γ :=
119121
haveI : WellFounded _ := wf
120122
letI : MonadLift m n := ⟨fun {γ} => lift γ⟩
121123
do
122124
match ← it.step with
123-
| .yield it' out _ =>
124-
match ← f out init with
125-
| ⟨.yield c, _⟩ => IterM.DefaultConsumers.forIn lift _ plausible_forInStep wf it' c f
125+
| .yield it' out h =>
126+
match ← f out (.direct ⟨_, h⟩) init with
127+
| ⟨.yield c, _⟩ =>
128+
IterM.DefaultConsumers.forIn lift _ plausible_forInStep wf it' c
129+
(fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc)
126130
| ⟨.done c, _⟩ => return c
127-
| .skip it' _ => IterM.DefaultConsumers.forIn lift _ plausible_forInStep wf it' init f
131+
| .skip it' h =>
132+
IterM.DefaultConsumers.forIn lift _ plausible_forInStep wf it' init
133+
(fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc)
128134
| .done _ => return init
129135
termination_by IteratorLoop.WFRel.mk wf it init
130136
decreasing_by
@@ -159,15 +165,19 @@ partial def IterM.DefaultConsumers.forInPartial {m : Type w → Type w'} {α : T
159165
{n : Type w → Type w''} [Monad n]
160166
(lift : ∀ γ, m γ → n γ) (γ : Type w)
161167
(it : IterM (α := α) m β) (init : γ)
162-
(f : (b : β) → (c : γ) → n (ForInStep γ)) : n γ :=
168+
(f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (ForInStep γ)) : n γ :=
163169
letI : MonadLift m n := ⟨fun {γ} => lift γ⟩
164170
do
165171
match ← it.step with
166-
| .yield it' out _ =>
167-
match ← f out init with
168-
| .yield c => IterM.DefaultConsumers.forInPartial lift _ it' c f
172+
| .yield it' out h =>
173+
match ← f out (.direct ⟨_, h⟩) init with
174+
| .yield c =>
175+
IterM.DefaultConsumers.forInPartial lift _ it' c
176+
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
169177
| .done c => return c
170-
| .skip it' _ => IterM.DefaultConsumers.forInPartial lift _ it' init f
178+
| .skip it' h =>
179+
IterM.DefaultConsumers.forInPartial lift _ it' init
180+
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
171181
| .done _ => return init
172182

173183
/--
@@ -202,27 +212,28 @@ theorem IteratorLoop.wellFounded_of_finite {m : Type w → Type w'}
202212
exact WellFoundedRelation.wf
203213

204214
/--
205-
This `ForIn`-style loop construct traverses a finite iterator using an `IteratorLoop` instance.
215+
This `ForIn'`-style loop construct traverses a finite iterator using an `IteratorLoop` instance.
206216
-/
207217
@[always_inline, inline]
208-
def IteratorLoop.finiteForIn {m : Type w → Type w'} {n : Type w → Type w''}
218+
def IteratorLoop.finiteForIn' {m : Type w → Type w'} {n : Type w → Type w''}
209219
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
210220
(lift : ∀ γ, m γ → n γ) :
211-
ForIn n (IterM (α := α) m β) β where
212-
forIn {γ} [Monad n] it init f :=
221+
ForIn' n (IterM (α := α) m β) βfun it out => it.IsPlausibleIndirectOutput out⟩ where
222+
forIn' {γ} [Monad n] it init f :=
213223
IteratorLoop.forIn (α := α) (m := m) lift γ (fun _ _ _ => True)
214224
wellFounded_of_finite
215-
it init ((⟨·, .intro⟩) <$> f · ·)
225+
it init (fun out h acc => (⟨·, .intro⟩) <$> f out h acc)
216226

217227
instance {m : Type w → Type w'} {n : Type w → Type w''}
218228
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
219229
[MonadLiftT m n] :
220-
ForIn n (IterM (α := α) m β) β := IteratorLoop.finiteForIn (fun _ => monadLift)
230+
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ :=
231+
IteratorLoop.finiteForIn' (fun _ => monadLift)
221232

222233
instance {m : Type w → Type w'} {n : Type w → Type w''}
223234
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [MonadLiftT m n] :
224-
ForIn n (IterM.Partial (α := α) m β) β where
225-
forIn it init f :=
235+
ForIn' n (IterM.Partial (α := α) m β) βfun it out => it.it.IsPlausibleIndirectOutput out⟩ where
236+
forIn' it init f :=
226237
IteratorLoopPartial.forInPartial (α := α) (m := m) (fun _ => monadLift) it.it init f
227238

228239
instance {m : Type w → Type w'} {n : Type w → Type w''}

src/Std/Data/Iterators/Lemmas/Combinators/Monadic/TakeWhile.lean

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,35 @@ theorem IterM.step_takeWhile {α m β} [Monad m] [LawfulMonad m] [Iterator α m
4848
{it : IterM (α := α) m β} {P} :
4949
(it.takeWhile P).step = (do
5050
match ← it.step with
51-
| .yield it' out h => match P out with
52-
| true => pure <| .yield (it'.takeWhile P) out (.yield h True.intro)
53-
| false => pure <| .done (.rejected h True.intro)
51+
| .yield it' out h => match h' : P out with
52+
| true => pure <| .yield (it'.takeWhile P) out (.yield h (congrArg ULift.up h'))
53+
| false => pure <| .done (.rejected h (congrArg ULift.up h'))
5454
| .skip it' h => pure <| .skip (it'.takeWhile P) (.skip h)
5555
| .done h => pure <| .done (.done h)) := by
56-
simp only [takeWhile, step_takeWhileM]
56+
simp only [takeWhile, step_takeWhileWithPostcondition]
5757
apply bind_congr
5858
intro step
5959
cases step using PlausibleIterStep.casesOn
6060
· simp only [Function.comp_apply, PlausibleIterStep.yield, PlausibleIterStep.done, pure_bind]
61-
cases P _ <;> rfl
61+
simp only [PostconditionT.pure, pure_bind]
62+
split <;> split <;> simp_all
6263
· simp
6364
· simp
6465

66+
theorem TakeWhile.Monadic.isPlausibleSuccessorOf_inner_of_isPlausibleSuccessorOf {α m β P} [Monad m] [Iterator α m β]
67+
{it' it : IterM (α := TakeWhile α m β P) m β} (h : it'.IsPlausibleSuccessorOf it) :
68+
it'.internalState.inner.IsPlausibleSuccessorOf it.internalState.inner := by
69+
rcases h with ⟨step, h, h'⟩
70+
cases step
71+
· rename_i out
72+
cases h
73+
cases h'
74+
rename_i it' h' h''
75+
exact ⟨.yield it' out, rfl, h'⟩
76+
· cases h
77+
cases h'
78+
rename_i it' h'
79+
exact ⟨.skip it', rfl, h'⟩
80+
· cases h
81+
6582
end Std.Iterators

src/Std/Data/Iterators/Lemmas/Combinators/TakeWhile.lean

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ theorem Iter.takeWhile_eq {α β} [Iterator α Id β] {P}
1818
theorem Iter.step_takeWhile {α β} [Iterator α Id β] {P}
1919
{it : Iter (α := α) β} :
2020
(it.takeWhile P).step = (match it.step with
21-
| .yield it' out h => match P out with
22-
| true => .yield (it'.takeWhile P) out (.yield h True.intro)
23-
| false => .done (.rejected h True.intro)
21+
| .yield it' out h => match h' : P out with
22+
| true => .yield (it'.takeWhile P) out (.yield h (congrArg _ h'))
23+
| false => .done (.rejected h (congrArg _ h'))
2424
| .skip it' h => .skip (it'.takeWhile P) (.skip h)
2525
| .done h => .done (.done h)) := by
2626
simp [Iter.takeWhile_eq, Iter.step, toIterM_toIter, IterM.step_takeWhile]
2727
generalize it.toIterM.step.run = step
2828
cases step using PlausibleIterStep.casesOn
2929
· simp only [IterM.Step.toPure_yield, PlausibleIterStep.yield, toIter_toIterM, toIterM_toIter]
30-
cases P _ <;> rfl
30+
split <;> split <;> (try exfalso; simp_all; done) <;> simp_all
3131
· simp
3232
· simp
3333

@@ -43,36 +43,41 @@ theorem Iter.atIdxSlow?_takeWhile {α β}
4343
simp only [Option.any_some]
4444
apply Eq.symm
4545
split
46-
· cases h' : P out
47-
· exfalso; simp_all
48-
· simp
49-
· cases h' : P out
46+
· -- Ugh, this is so ugly
47+
have : (match h' : P out with | true => Unit.unit | false => Unit.unit) = .unit := sorry
48+
split at this
5049
· simp
5150
· exfalso; simp_all
51+
· have : (match h' : P out with | true => Unit.unit | false => Unit.unit) = .unit := sorry
52+
split at this
53+
· exfalso; simp_all
54+
· simp
5255
case case2 it it' out h h' l ih =>
5356
simp only [Nat.succ_eq_add_one, atIdxSlow?.eq_def (it := it.takeWhile P), step_takeWhile, h']
5457
simp only [atIdxSlow?.eq_def (it := it), h']
55-
cases hP : P out
56-
· simp
57-
intro h
58-
specialize h 0 (Nat.zero_le _)
59-
simp at h
60-
exfalso; simp_all
61-
· simp [ih]
58+
have : (match h' : P out with | true => Unit.unit | false => Unit.unit) = .unit := sorry
59+
split at this
60+
· rename_i hP
61+
simp only [ih]
6262
split
6363
· rename_i h
6464
rw [if_pos]
6565
intro k hk
6666
split
6767
· exact hP
68-
· simp at hk
68+
· simp only [Nat.succ_eq_add_one, Nat.add_le_add_iff_right] at hk
6969
exact h _ hk
7070
· rename_i hl
7171
rw [if_neg]
7272
intro hl'
7373
apply hl
7474
intro k hk
7575
exact hl' (k + 1) (Nat.succ_le_succ hk)
76+
· simp only [right_eq_ite_iff]
77+
intro h
78+
specialize h 0 (Nat.zero_le _)
79+
simp only at h
80+
exfalso; simp_all
7681
case case3 l it it' h h' ih =>
7782
simp only [atIdxSlow?.eq_def (it := it.takeWhile P), step_takeWhile, h', ih]
7883
simp only [atIdxSlow?.eq_def (it := it), h']
@@ -131,4 +136,10 @@ theorem Iter.toArray_takeWhile_of_finite {α β} [Iterator α Id β] {P}
131136
(it.takeWhile P).toArray = it.toArray.takeWhile P := by
132137
rw [← toArray_toList, ← toArray_toList, List.takeWhile_toArray, toList_takeWhile_of_finite]
133138

139+
theorem TakeWhile.isPlausibleSuccessorOf_inner_of_isPlausibleSuccessorOf {α β P}
140+
[Iterator α Id β]
141+
{it' it : Iter (α := TakeWhile α Id β P) β} (h : it'.IsPlausibleSuccessorOf it) :
142+
it'.internalState.inner.IsPlausibleSuccessorOf it.internalState.inner :=
143+
TakeWhile.Monadic.isPlausibleSuccessorOf_inner_of_isPlausibleSuccessorOf h
144+
134145
end Std.Iterators

src/Std/Data/Iterators/Lemmas/Consumers/Loop.lean

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,24 @@ import Std.Data.Iterators.Consumers.Loop
1313

1414
namespace Std.Iterators
1515

16+
theorem Iter.forIn'_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
17+
{m : Type w → Type w''} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
18+
{γ : Type w} {it : Iter (α := α) β} {init : γ}
19+
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → m (ForInStep γ)} :
20+
ForIn'.forIn' it init f =
21+
IterM.DefaultConsumers.forIn (fun _ c => pure c.run) γ (fun _ _ _ => True)
22+
IteratorLoop.wellFounded_of_finite it.toIterM init
23+
(fun out h acc => (⟨·, .intro⟩) <$>
24+
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
25+
cases hl.lawful; rfl
26+
1627
theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
1728
{m : Type w → Type w''} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
1829
{γ : Type w} {it : Iter (α := α) β} {init : γ}
1930
{f : β → γ → m (ForInStep γ)} :
2031
ForIn.forIn it init f =
2132
IterM.DefaultConsumers.forIn (fun _ c => pure c.run) γ (fun _ _ _ => True)
22-
IteratorLoop.wellFounded_of_finite it.toIterM init ((⟨·, .intro⟩) <$> f · ·) := by
33+
IteratorLoop.wellFounded_of_finite it.toIterM init (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
2334
cases hl.lawful; rfl
2435

2536
theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]

0 commit comments

Comments
 (0)