88prelude
99public import Init.Data.Iterators.Consumers.Monadic.Partial
1010public import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
11+ public import Init.Internal.ExtrinsicTermination
1112
1213@[expose] public section
1314
@@ -51,25 +52,7 @@ class IteratorCollect (α : Type w) (m : Type w → Type w') (n : Type w → Typ
5152 Maps the emitted values of an iterator using the given function and collects the results in an
5253 `Array`. This is an internal implementation detail. Consider using `it.map f |>.toArray` instead.
5354 -/
54- toArrayMapped [Finite α m] :
55- (lift : ⦃δ : Type w⦄ → m δ → n δ) → {γ : Type w} → (β → n γ) → IterM (α := α) m β → n (Array γ)
56-
57- /--
58- `IteratorCollectPartial α m` provides efficient implementations of collectors for `α`-based
59- iterators. Right now, it is limited to a potentially optimized partial `toArray` implementation.
60-
61- This class is experimental and users of the iterator API should not explicitly depend on it.
62- They can, however, assume that consumers that require an instance will work for all iterators
63- provided by the standard library.
64- -/
65- class IteratorCollectPartial (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
66- {β : Type w} [Iterator α m β] where
67- /--
68- Maps the emitted values of an iterator using the given function and collects the results in an
69- `Array`. This is an internal implementation detail.
70- Consider using `it.map f |>.allowNontermination.toArray` instead.
71- -/
72- toArrayMappedPartial :
55+ toArrayMapped :
7356 (lift : ⦃δ : Type w⦄ → m δ → n δ) → {γ : Type w} → (β → n γ) → IterM (α := α) m β → n (Array γ)
7457
7558end Typeclasses
@@ -82,20 +65,21 @@ This is an internal function used in `IteratorCollect.defaultImplementation`.
8265It iterates over an iterator and applies `f` whenever a value is emitted before inserting the result
8366of `f` into an array.
8467-/
85- @[always_inline, inline]
68+ @[always_inline, inline, no_expose ]
8669def IterM.DefaultConsumers.toArrayMapped {α β : Type w} {m : Type w → Type w'}
87- {n : Type w → Type w''} [Monad n] [Iterator α m β] [Finite α m]
70+ {n : Type w → Type w''} [Monad n] [Iterator α m β]
8871 (lift : ⦃α : Type w⦄ → m α → n α) {γ : Type w} (f : β → n γ)
8972 (it : IterM (α := α) m β) : n (Array γ) :=
73+ letI : MonadLift m n := ⟨lift (α := _)⟩
9074 go it #[]
9175where
92- @[specialize]
93- go [Monad n] [Finite α m] (it : IterM (α := α) m β) a := letI : MonadLift m n := ⟨lift (α := _)⟩; do
94- match (← it.step).inflate with
95- | .yield it' b _ => go it' (a.push (← f b))
96- | .skip it' _ => go it' a
97- | .done _ => return a
98- termination_by it.finitelyManySteps
76+ go it (acc : Array γ) : n (Array γ) :=
77+ letI : MonadLift m n := ⟨lift (α := _)⟩
78+ extrinsicFix₂ (C₂ := fun _ _ => n (Array γ)) ( fun it acc recur => do
79+ match (← it.step).inflate.val with
80+ | .yield it' out => recur it' (acc.push (← f out))
81+ | .skip it' => recur it' acc
82+ | .done => return acc) it acc
9983
10084/--
10185This is the default implementation of the `IteratorLoop` class.
@@ -110,7 +94,8 @@ def IteratorCollect.defaultImplementation {α β : Type w} {m : Type w → Type
11094 toArrayMapped := IterM.DefaultConsumers.toArrayMapped
11195
11296/--
113- Asserts that a given `IteratorCollect` instance is equal to `IteratorCollect.defaultImplementation`.
97+ Asserts that a given `IteratorCollect` instance is equal to `IteratorCollect.defaultImplementation`
98+ *if the underlying iterator is finite* .
11499(Even though equal, the given instance might be vastly more efficient.)
115100-/
116101class LawfulIteratorCollect (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
@@ -135,65 +120,27 @@ instance (α β : Type w) (m : Type w → Type w') (n : Type w → Type w'') [Mo
135120 letI : IteratorCollect α m n := .defaultImplementation
136121 ⟨fun _ => rfl⟩
137122
138- /--
139- This is an internal function used in `IteratorCollectPartial.defaultImplementation`.
140-
141- It iterates over an iterator and applies `f` whenever a value is emitted before inserting the result
142- of `f` into an array.
143- -/
144- @[always_inline, inline]
145- partial def IterM.DefaultConsumers.toArrayMappedPartial {α β : Type w} {m : Type w → Type w'}
146- {n : Type w → Type w''} [Monad n] [Iterator α m β]
147- (lift : {α : Type w} → m α → n α) {γ : Type w} (f : β → n γ)
148- (it : IterM (α := α) m β) : n (Array γ) :=
149- go it #[]
150- where
151- @[specialize]
152- go [Monad n] (it : IterM (α := α) m β) a := letI : MonadLift m n := ⟨lift⟩; do
153- match (← it.step).inflate with
154- | .yield it' b _ => go it' (a.push (← f b))
155- | .skip it' _ => go it' a
156- | .done _ => return a
157-
158- /--
159- This is the default implementation of the `IteratorLoopPartial` class.
160- It simply iterates through the iterator using `IterM.step`, incrementally building up the desired
161- data structure. For certain iterators, more efficient implementations are possible and should be
162- used instead.
163- -/
164- @[always_inline, inline]
165- def IteratorCollectPartial.defaultImplementation {α β : Type w} {m : Type w → Type w'}
166- {n : Type w → Type w''} [Monad n] [Iterator α m β] :
167- IteratorCollectPartial α m n where
168- toArrayMappedPartial := IterM.DefaultConsumers.toArrayMappedPartial
169-
170123/--
171124Traverses the given iterator and stores the emitted values in an array.
172-
173- This function requires a `Finite` instance proving that the iterator will finish after a finite
174- number of steps. If the iterator is not finite or such an instance is not available, consider using
175- `it.allowNontermination.toArray` instead of `it.toArray`. However, it is not possible to formally
176- verify the behavior of the partial variant.
177125-/
178126@[always_inline, inline]
179- def IterM.toArray {α β : Type w} {m : Type w → Type w'} [Monad m]
180- [Iterator α m β] [Finite α m] [IteratorCollect α m m]
181- (it : IterM (α := α) m β) : m (Array β) :=
127+ def IterM.toArray {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
128+ [IteratorCollect α m m] (it : IterM (α := α) m β) : m (Array β) :=
182129 IteratorCollect.toArrayMapped (fun ⦃_⦄ => id) pure it
183130
184131/--
185132Traverses the given iterator and stores the emitted values in an array.
186133
187- This is a partial, potentially nonterminating, function. It is not possible to formally verify
188- its behavior. If the iterator has a `Finite` instance, consider using `IterM.toArray` instead.
134+ This function is deprecated. Instead of `it.allowNontermination.toArray`, use `it.toArray`.
189135-/
190- @[always_inline, inline]
136+ @[always_inline, inline, deprecated IterM.toArray (since := "2025-10-15") ]
191137def IterM.Partial.toArray {α : Type w} {m : Type w → Type w'} {β : Type w} [Monad m]
192- [Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollectPartial α m m] : m (Array β) :=
193- IteratorCollectPartial.toArrayMappedPartial ( fun ⦃_⦄ => id) pure it.it
138+ [Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollect α m m] : m (Array β) :=
139+ it.it.toArray
194140
195141end ToArray
196142
143+ -- TODO:
197144/--
198145Traverses the given iterator and stores the emitted values in reverse order in a list. Because
199146lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
@@ -237,28 +184,22 @@ where
237184/--
238185Traverses the given iterator and stores the emitted values in a list. Because
239186lists are prepend-only, `toListRev` is usually more efficient that `toList`.
240-
241- This function requires a `Finite` instance proving that the iterator will finish after a finite
242- number of steps. If the iterator is not finite or such an instance is not available, consider using
243- `it.allowNontermination.toList` instead of `it.toList`. However, it is not possible to
244- formally verify the behavior of the partial variant.
245187-/
246188@[always_inline, inline]
247189def IterM.toList {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
248- [Iterator α m β] [Finite α m] [ IteratorCollect α m m] (it : IterM (α := α) m β) : m (List β) :=
190+ [Iterator α m β] [IteratorCollect α m m] (it : IterM (α := α) m β) : m (List β) :=
249191 Array.toList <$> IterM.toArray it
250192
251193/--
252194Traverses the given iterator and stores the emitted values in a list. Because
253195lists are prepend-only, `toListRev` is usually more efficient that `toList`.
254196
255- This is a partial, potentially nonterminating, function. It is not possible to formally verify
256- its behavior. If the iterator has a `Finite` instance, consider using `IterM.toList` instead.
197+ This function is deprecated. Instead of `it.allowNontermination.toList`, use `it.toList`.
257198-/
258- @[always_inline, inline]
199+ @[always_inline, inline, deprecated IterM.toList (since := "2025-10-15") ]
259200def IterM.Partial.toList {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
260- [Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollectPartial α m m] :
201+ [Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollect α m m] :
261202 m (List β) :=
262- Array.toList <$> it.toArray
203+ Array.toList <$> it.it. toArray
263204
264205end Std.Iterators
0 commit comments