This PR introduces a new fixpoint combinator, `WellFounded.extrinsicFix`. A termination proof, if provided at all, can be given extrinsically, i.e., looking at the term from the outside, and is only required if one intends to formally verify the behavior of the fixpoint. The new combinator is then applied to the iterator API. Consumers such as `toList` or `ForIn` no longer require a proof that the underlying iterator is finite. If one wants to ensure the termination of them intrinsically, there are strictly terminating variants available as, for example, `it.ensureTermination.toList` instead of `it.toList`.
680 lines
24 KiB
Text
680 lines
24 KiB
Text
/-
|
||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Paul Reichert
|
||
-/
|
||
module
|
||
|
||
prelude
|
||
public import Init.Data.Iterators.Consumers.Collect
|
||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||
|
||
set_option linter.missingDocs true
|
||
|
||
public section
|
||
|
||
/-!
|
||
# Loop consumers
|
||
|
||
This module provides consumers that iterate over a given iterator, applying a certain user-supplied
|
||
function in every iteration. Concretely, the following operations are provided:
|
||
|
||
* `ForIn` instances
|
||
* `Iter.fold`, the analogue of `List.foldl`
|
||
* `Iter.foldM`, the analogue of `List.foldlM`
|
||
|
||
These operations are implemented using the `IteratorLoop` type class.
|
||
-/
|
||
|
||
namespace Std.Iterators
|
||
|
||
/--
|
||
A `ForIn'` instance for iterators. Its generic membership relation is not easy to use,
|
||
so this is not marked as `instance`. This way, more convenient instances can be built on top of it
|
||
or future library improvements will make it more comfortable.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||
ForIn' n (Iter (α := α) β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||
forIn' it init f :=
|
||
IteratorLoop.finiteForIn' (fun _ _ f c => f c.run) |>.forIn' it.toIterM init
|
||
fun out h acc =>
|
||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
|
||
|
||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||
ForIn n (Iter (α := α) β) β :=
|
||
haveI : ForIn' n (Iter (α := α) β) β _ := Iter.instForIn'
|
||
instForInOfForIn'
|
||
|
||
/--
|
||
An implementation of `for h : ... in ... do ...` notation for partial iterators.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.Partial.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||
ForIn' n (Iter.Partial (α := α) β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||
forIn' it init f :=
|
||
haveI := @Iter.instForIn'
|
||
forIn' it.it init f
|
||
|
||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||
ForIn n (Iter.Partial (α := α) β) β :=
|
||
haveI : ForIn' n (Iter.Partial (α := α) β) β _ := Iter.Partial.instForIn'
|
||
instForInOfForIn'
|
||
|
||
/--
|
||
A `ForIn'` instance for iterators that is guaranteed to terminate after finitely many steps.
|
||
It is not marked as an instance because the membership predicate is difficult to work with.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.Total.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||
[Iterator α Id β] [IteratorLoop α Id n] [Finite α Id] :
|
||
ForIn' n (Iter.Total (α := α) β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||
forIn' it init f := Iter.instForIn'.forIn' it.it init f
|
||
|
||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||
[Iterator α Id β] [IteratorLoop α Id n] [Finite α Id] :
|
||
ForIn n (Iter.Total (α := α) β) β :=
|
||
haveI : ForIn' n (Iter.Total (α := α) β) β _ := Iter.Total.instForIn'
|
||
instForInOfForIn'
|
||
|
||
instance {m : Type x → Type x'}
|
||
{α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id m] [Monad m] :
|
||
ForM m (Iter (α := α) β) β where
|
||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||
|
||
instance {m : Type x → Type x'}
|
||
{α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id m] [Monad m] :
|
||
ForM m (Iter.Partial (α := α) β) β where
|
||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||
|
||
instance {m : Type x → Type x'}
|
||
{α : Type w} {β : Type w} [Monad m] [Iterator α Id β] [IteratorLoop α Id m] [Finite α Id] :
|
||
ForM m (Iter.Total (α := α) β) β where
|
||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||
|
||
/--
|
||
Folds a monadic function over an iterator from the left, accumulating a value starting with `init`.
|
||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||
|
||
It is equivalent to `it.toList.foldlM`.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.foldM {m : Type x → Type x'} [Monad m]
|
||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id m] (f : γ → β → m γ)
|
||
(init : γ) (it : Iter (α := α) β) : m γ :=
|
||
ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x)
|
||
|
||
/--
|
||
Folds a monadic function over an iterator from the left, accumulating a value starting with `init`.
|
||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||
|
||
It is equivalent to `it.toList.foldlM`.
|
||
|
||
This function is deprecated. Instead of `it.allowNontermination.foldM`, use `it.foldM`.
|
||
-/
|
||
@[always_inline, inline, deprecated Iter.foldM (since := "2025-12-04")]
|
||
def Iter.Partial.foldM {m : Type x → Type x'} [Monad m]
|
||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id m] (f : γ → β → m γ)
|
||
(init : γ) (it : Iter.Partial (α := α) β) : m γ :=
|
||
it.it.foldM (init := init) f
|
||
|
||
/--
|
||
Folds a monadic function over an iterator from the left, accumulating a value starting with `init`.
|
||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||
|
||
It is equivalent to `it.toList.foldlM`.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using `Iter.foldM`.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.Total.foldM {m : Type x → Type x'} [Monad m]
|
||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id m] [Finite α Id] (f : γ → β → m γ)
|
||
(init : γ) (it : Iter.Total (α := α) β) : m γ :=
|
||
it.it.foldM (init := init) f
|
||
|
||
/--
|
||
Folds a function over an iterator from the left, accumulating a value starting with `init`.
|
||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||
|
||
It is equivalent to `it.toList.foldl`.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id Id] (f : γ → β → γ)
|
||
(init : γ) (it : Iter (α := α) β) : γ :=
|
||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||
|
||
/--
|
||
Folds a function over an iterator from the left, accumulating a value starting with `init`.
|
||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||
|
||
It is equivalent to `it.toList.foldl`.
|
||
|
||
This function is deprecated. Instead of `it.allowNontermination.fold`, use `it.fold`.
|
||
-/
|
||
@[always_inline, inline, deprecated Iter.fold (since := "2025-12-04")]
|
||
def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id Id] (f : γ → β → γ)
|
||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||
it.it.fold (init := init) f
|
||
|
||
/--
|
||
Folds a function over an iterator from the left, accumulating a value starting with `init`.
|
||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||
|
||
It is equivalent to `it.toList.foldl`.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using `Iter.fold`.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.Total.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id Id] [Finite α Id] (f : γ → β → γ)
|
||
(init : γ) (it : Iter.Total (α := α) β) : γ :=
|
||
it.it.fold (init := init) f
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||
any element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
-/
|
||
@[always_inline]
|
||
def Iter.anyM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||
[Iterator α Id β] [IteratorLoop α Id m]
|
||
(p : β → m Bool) (it : Iter (α := α) β) : m Bool :=
|
||
ForIn.forIn it false (fun x _ => do
|
||
if ← p x then
|
||
return .done true
|
||
else
|
||
return .yield false)
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||
any element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using {name}`Iter.anyM`.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.Total.anyM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||
(p : β → m Bool) (it : Iter.Total (α := α) β) : m Bool :=
|
||
it.it.anyM p
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||
any element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
-/
|
||
@[inline]
|
||
def Iter.any {α β : Type w}
|
||
[Iterator α Id β] [IteratorLoop α Id Id]
|
||
(p : β → Bool) (it : Iter (α := α) β) : Bool :=
|
||
(it.anyM (fun x => pure (f := Id) (p x))).run
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||
any element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using {name}`Iter.any`.
|
||
-/
|
||
@[inline]
|
||
def Iter.Total.any {α β : Type w}
|
||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||
(p : β → Bool) (it : Iter.Total (α := α) β) : Bool :=
|
||
it.it.any p
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||
all element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.allM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||
[Iterator α Id β] [IteratorLoop α Id m]
|
||
(p : β → m Bool) (it : Iter (α := α) β) : m Bool :=
|
||
ForIn.forIn it true (fun x _ => do
|
||
if ← p x then
|
||
return .yield true
|
||
else
|
||
return .done false)
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||
all element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
|
||
This variant terminates after finitely mall steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using {name}`Iter.allM`.
|
||
-/
|
||
@[always_inline, inline]
|
||
def Iter.Total.allM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||
(p : β → m Bool) (it : Iter.Total (α := α) β) : m Bool :=
|
||
it.it.allM p
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||
all element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
-/
|
||
@[inline]
|
||
def Iter.all {α β : Type w}
|
||
[Iterator α Id β] [IteratorLoop α Id Id]
|
||
(p : β → Bool) (it : Iter (α := α) β) : Bool :=
|
||
(it.allM (fun x => pure (f := Id) (p x))).run
|
||
|
||
set_option doc.verso true in
|
||
/--
|
||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||
all element emitted by the iterator {name}`it`.
|
||
|
||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||
examined in order of iteration.
|
||
|
||
This variant terminates after finitely mall steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using {name}`Iter.all`.
|
||
-/
|
||
@[inline]
|
||
def Iter.Total.all {α β : Type w}
|
||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||
(p : β → Bool) (it : Iter.Total (α := α) β) : Bool :=
|
||
it.it.all p
|
||
|
||
/--
|
||
Returns the first non-`none` result of applying the monadic function `f` to each output
|
||
of the iterator, in order. Returns `none` if `f` returns `none` for all outputs.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `some _`. The outputs of `it` are
|
||
examined in order of iteration.
|
||
|
||
If the iterator is not finite, this function might run forever. The variant
|
||
`it.ensureTermination.findSomeM?` always terminates after finitely many steps.
|
||
|
||
Example:
|
||
```lean example
|
||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findSomeM? fun i => do
|
||
if i < 5 then
|
||
return some (i * 10)
|
||
if i ≤ 6 then
|
||
IO.println s!"Almost! {i}"
|
||
return none
|
||
```
|
||
```output
|
||
Almost! 6
|
||
Almost! 5
|
||
```
|
||
```output
|
||
some 10
|
||
```
|
||
-/
|
||
@[inline]
|
||
def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m] [Iterator α Id β]
|
||
[IteratorLoop α Id m] (it : Iter (α := α) β) (f : β → m (Option γ)) :
|
||
m (Option γ) :=
|
||
ForIn.forIn it none (fun x _ => do
|
||
match ← f x with
|
||
| none => return .yield none
|
||
| some fx => return .done (some fx))
|
||
|
||
/--
|
||
Returns the first non-`none` result of applying the monadic function `f` to each output
|
||
of the iterator, in order. Returns `none` if `f` returns `none` for all outputs.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `some _`. The outputs of `it` are
|
||
examined in order of iteration.
|
||
|
||
This function is deprecated. Instead of `it.allowNontermination.findSomeM?`, use `it.findSomeM?`.
|
||
|
||
Example:
|
||
```lean example
|
||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findSomeM? fun i => do
|
||
if i < 5 then
|
||
return some (i * 10)
|
||
if i ≤ 6 then
|
||
IO.println s!"Almost! {i}"
|
||
return none
|
||
```
|
||
```output
|
||
Almost! 6
|
||
Almost! 5
|
||
```
|
||
```output
|
||
some 10
|
||
```
|
||
-/
|
||
@[inline, deprecated Iter.findSomeM? (since := "2025-12-04")]
|
||
def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||
[Iterator α Id β] [IteratorLoop α Id m] (it : Iter.Partial (α := α) β)
|
||
(f : β → m (Option γ)) :
|
||
m (Option γ) :=
|
||
it.it.findSomeM? f
|
||
|
||
/--
|
||
Returns the first non-`none` result of applying the monadic function `f` to each output
|
||
of the iterator, in order. Returns `none` if `f` returns `none` for all outputs.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `some _`. The outputs of `it` are
|
||
examined in order of iteration.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using `Iter.findSomeM?`.
|
||
|
||
Example:
|
||
```lean example
|
||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findSomeM? fun i => do
|
||
if i < 5 then
|
||
return some (i * 10)
|
||
if i ≤ 6 then
|
||
IO.println s!"Almost! {i}"
|
||
return none
|
||
```
|
||
```output
|
||
Almost! 6
|
||
Almost! 5
|
||
```
|
||
```output
|
||
some 10
|
||
```
|
||
-/
|
||
@[inline]
|
||
def Iter.Total.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id] (it : Iter.Total (α := α) β)
|
||
(f : β → m (Option γ)) :
|
||
m (Option γ) :=
|
||
it.it.findSomeM? f
|
||
|
||
/--
|
||
Returns the first non-`none` result of applying `f` to each output of the iterator, in order.
|
||
Returns `none` if `f` returns `none` for all outputs.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `some _`.The outputs of `it` are examined in order of
|
||
iteration.
|
||
|
||
If the iterator is not finite, this function might run forever. The variant
|
||
`it.ensureTermination.findSome?` always terminates after finitely many steps.
|
||
|
||
Examples:
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
|
||
-/
|
||
@[inline]
|
||
def Iter.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id Id] (it : Iter (α := α) β) (f : β → Option γ) :
|
||
Option γ :=
|
||
Id.run (it.findSomeM? (pure <| f ·))
|
||
|
||
/--
|
||
Returns the first non-`none` result of applying `f` to each output of the iterator, in order.
|
||
Returns `none` if `f` returns `none` for all outputs.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `some _`.The outputs of `it` are examined in order of
|
||
iteration.
|
||
|
||
This function is deprecated. Instead of `it.allowNontermination.findSome?`, use `it.findSome?`.
|
||
|
||
Examples:
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
|
||
-/
|
||
@[inline, deprecated Iter.findSome? (since := "2025-12-04")]
|
||
def Iter.Partial.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id Id] (it : Iter.Partial (α := α) β) (f : β → Option γ) :
|
||
Option γ :=
|
||
it.it.findSome? f
|
||
|
||
/--
|
||
Returns the first non-`none` result of applying `f` to each output of the iterator, in order.
|
||
Returns `none` if `f` returns `none` for all outputs.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `some _`.The outputs of `it` are examined in order of
|
||
iteration.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using `Iter.findSome?`.
|
||
|
||
Examples:
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.ensureTermination.findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.ensureTermination.findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
|
||
-/
|
||
@[inline]
|
||
def Iter.Total.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||
[IteratorLoop α Id Id] [Finite α Id] (it : Iter.Total (α := α) β) (f : β → Option γ) :
|
||
Option γ :=
|
||
it.it.findSome? f
|
||
|
||
/--
|
||
Returns the first output of the iterator for which the monadic predicate `p` returns `true`, or
|
||
`none` if no such element is found.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `true`. The outputs of `it` are examined in order of
|
||
iteration.
|
||
|
||
If the iterator is not finite, this function might run forever. The variant
|
||
`it.ensureTermination.findM?` always terminates after finitely many steps.
|
||
|
||
Example:
|
||
```lean example
|
||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findM? fun i => do
|
||
if i < 5 then
|
||
return true
|
||
if i ≤ 6 then
|
||
IO.println s!"Almost! {i}"
|
||
return false
|
||
```
|
||
```output
|
||
Almost! 6
|
||
Almost! 5
|
||
```
|
||
```output
|
||
some 1
|
||
```
|
||
-/
|
||
@[inline]
|
||
def Iter.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||
[IteratorLoop α Id m] (it : Iter (α := α) β) (f : β → m (ULift Bool)) :
|
||
m (Option β) :=
|
||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||
|
||
/--
|
||
Returns the first output of the iterator for which the monadic predicate `p` returns `true`, or
|
||
`none` if no such element is found.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `true`. The outputs of `it` are examined in order of
|
||
iteration.
|
||
|
||
This function is deprecated. Instead of `it.ensureTermination.findM?`, use `it.findM?`.
|
||
|
||
Example:
|
||
```lean example
|
||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findM? fun i => do
|
||
if i < 5 then
|
||
return true
|
||
if i ≤ 6 then
|
||
IO.println s!"Almost! {i}"
|
||
return false
|
||
```
|
||
```output
|
||
Almost! 6
|
||
Almost! 5
|
||
```
|
||
```output
|
||
some 1
|
||
```
|
||
-/
|
||
@[inline, deprecated Iter.findM? (since := "2025-12-04")]
|
||
def Iter.Partial.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||
[IteratorLoop α Id m] (it : Iter.Partial (α := α) β) (f : β → m (ULift Bool)) :
|
||
m (Option β) :=
|
||
it.it.findM? f
|
||
|
||
/--
|
||
Returns the first output of the iterator for which the monadic predicate `p` returns `true`, or
|
||
`none` if no such element is found.
|
||
|
||
`O(|it|)`. Short-circuits when `f` returns `true`. The outputs of `it` are examined in order of
|
||
iteration.
|
||
|
||
This variant requires terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using `Iter.findM?`.
|
||
|
||
Example:
|
||
```lean example
|
||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findM? fun i => do
|
||
if i < 5 then
|
||
return true
|
||
if i ≤ 6 then
|
||
IO.println s!"Almost! {i}"
|
||
return false
|
||
```
|
||
```output
|
||
Almost! 6
|
||
Almost! 5
|
||
```
|
||
```output
|
||
some 1
|
||
```
|
||
-/
|
||
@[inline]
|
||
def Iter.Total.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||
[IteratorLoop α Id m] [Finite α Id] (it : Iter.Total (α := α) β) (f : β → m (ULift Bool)) :
|
||
m (Option β) :=
|
||
it.it.findM? f
|
||
|
||
/--
|
||
Returns the first output of the iterator for which the predicate `p` returns `true`, or `none` if
|
||
no such output is found.
|
||
|
||
`O(|it|)`. Short-circuits upon encountering the first match. The elements in `it` are examined in
|
||
order of iteration.
|
||
|
||
If the iterator is not finite, this function might run forever. The variant
|
||
`it.ensureTermination.find?` always terminates after finitely many steps.
|
||
|
||
Examples:
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 5) = some 1`
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 1) = none`
|
||
-/
|
||
@[inline]
|
||
def Iter.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||
(it : Iter (α := α) β) (f : β → Bool) : Option β :=
|
||
Id.run (it.findM? (pure <| .up <| f ·))
|
||
|
||
/--
|
||
Returns the first output of the iterator for which the predicate `p` returns `true`, or `none` if
|
||
no such output is found.
|
||
|
||
`O(|it|)`. Short-circuits upon encountering the first match. The elements in `it` are examined in
|
||
order of iteration.
|
||
|
||
This function is deprecated. Instead of `it.allowNontermination.find?`, use `it.find?`.
|
||
|
||
Examples:
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.find? (· < 5) = some 1`
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.find? (· < 1) = none`
|
||
-/
|
||
@[inline, deprecated Iter.find? (since := "2025-12-04")]
|
||
def Iter.Partial.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||
(it : Iter.Partial (α := α) β) (f : β → Bool) : Option β :=
|
||
it.it.find? f
|
||
|
||
/--
|
||
Returns the first output of the iterator for which the predicate `p` returns `true`, or `none` if
|
||
no such output is found.
|
||
|
||
`O(|it|)`. Short-circuits upon encountering the first match. The elements in `it` are examined in
|
||
order of iteration.
|
||
|
||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||
finite. If such a proof is not available, consider using `Iter.find?`.
|
||
|
||
Examples:
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 5) = some 1`
|
||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 1) = none`
|
||
-/
|
||
@[inline]
|
||
def Iter.Total.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||
(it : Iter.Total (α := α) β) (f : β → Bool) : Option β :=
|
||
it.it.find? f
|
||
|
||
/--
|
||
Steps through the whole iterator, counting the number of outputs emitted.
|
||
|
||
**Performance**:
|
||
|
||
This function's runtime is linear in the number of steps taken by the iterator.
|
||
-/
|
||
@[always_inline, inline, expose]
|
||
def Iter.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||
(it : Iter (α := α) β) : Nat :=
|
||
it.toIterM.count.run.down
|
||
|
||
/--
|
||
Steps through the whole iterator, counting the number of outputs emitted.
|
||
|
||
**Performance**:
|
||
|
||
This function's runtime is linear in the number of steps taken by the iterator.
|
||
-/
|
||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||
(it : Iter (α := α) β) : Nat :=
|
||
it.count
|
||
|
||
/--
|
||
Steps through the whole iterator, counting the number of outputs emitted.
|
||
|
||
**Performance**:
|
||
|
||
This function's runtime is linear in the number of steps taken by the iterator.
|
||
-/
|
||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-12-04")]
|
||
def Iter.Partial.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||
(it : Iter.Partial (α := α) β) : Nat :=
|
||
it.it.toIterM.count.run.down
|
||
|
||
/--
|
||
Steps through the whole iterator, counting the number of outputs emitted.
|
||
|
||
**Performance**:
|
||
|
||
This function's runtime is linear in the number of steps taken by the iterator.
|
||
-/
|
||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||
(it : Iter.Partial (α := α) β) : Nat :=
|
||
it.it.count
|
||
|
||
end Std.Iterators
|