|
| 1 | +/- |
| 2 | +Copyright (c) 2025 Lean FRO, LLC. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Paul Reichert |
| 5 | +-/ |
| 6 | +prelude |
| 7 | +import Std.Data.Iterators.Basic |
| 8 | +import Std.Data.Iterators.Producers |
| 9 | +import Std.Data.Iterators.Consumers |
| 10 | +import Std.Data.Iterators.Internal |
| 11 | + |
| 12 | +/-! |
| 13 | +# Iterators |
| 14 | +
|
| 15 | +The `Std.Data.Iterators` module provides a uniform abstraction over data that can be iterated over |
| 16 | +in a sequential way, with a focus on convenience and efficiency. It is heavily inspired by Rust's |
| 17 | +iterator library and Haskell's `streamly`. |
| 18 | +
|
| 19 | +An iterator is an abstraction of a sequence of values that may or may not terminate. For example, |
| 20 | +every list can be traversed with an iterator via `List.iter`. |
| 21 | +
|
| 22 | +Most users of the iterator API will just put together existing library functions that |
| 23 | +create, combine and consume iterators. Consider a simple example: |
| 24 | +
|
| 25 | +```lean |
| 26 | +-- [1, 2, 3].iter : Iter (α := ListIterator α) Nat (α being implicit) |
| 27 | +#check [1, 2, 3].iter |
| 28 | +
|
| 29 | +-- 12 |
| 30 | +#eval [1, 2, 3].iter.map (· * 2) |>.fold (init := 0) (· + ·) |
| 31 | +``` |
| 32 | +
|
| 33 | +An iterator that emits values in `β` is an element of the type `Iter (α := ?) β`. The implicit |
| 34 | +type argument `α` contains stateful information about the iterator. `IterM (α := ?) m β` represents |
| 35 | +iterators over a monad `m`. In both cases, the implementation is provided by a typeclass |
| 36 | +`Iterator α m β`, where `m` is a monad in which the iteration happens. |
| 37 | +
|
| 38 | +The heart of an iterator `it : Iter β` is its `it.step` function, which returns `it.Step α β`. |
| 39 | +Here, `it.Step` is a type that either (1) provides an output value in `β` and a |
| 40 | +successor iterator (`yield`), (2) provides only a successor iterator with no output (`skip`), or |
| 41 | +(3) signals that the iterator has finished and will provide no more outputs (`done`). |
| 42 | +For technical reasons related to termination proofs, the returned `it.Step` also contains proof |
| 43 | +that it is a "plausible" step obtained from `it`. |
| 44 | +
|
| 45 | +The `step` function can also be used by hand: |
| 46 | +
|
| 47 | +```lean |
| 48 | +def sumrec (l : List Nat) : Nat := |
| 49 | + go (l.iter.map (2 * ·)) 0 |
| 50 | +where |
| 51 | + go it acc := |
| 52 | + match it.step with |
| 53 | + | .yield it' n _ => go it' (acc + n) |
| 54 | + | .skip it' _ => go it' acc |
| 55 | + | .done _ => acc |
| 56 | + termination_by it.finitelyManySteps |
| 57 | +``` |
| 58 | +
|
| 59 | +In general, iterators do not need to terminate after finitely many steps. This example |
| 60 | +works because the iterator type at hand has an instance of the `Std.Iterators.Finite` typeclass. |
| 61 | +Iterators that may not terminate but will not end up in an infinite sequence of `.skip` |
| 62 | +steps are called productive. This behavior is encoded in the `Std.Iterators.Productive` typeclass. |
| 63 | +
|
| 64 | +## Stability |
| 65 | +
|
| 66 | +The API for the usage of iterators provided in this module can be considered stable, as well as |
| 67 | +the API for the verification of programms using iterators, unless explicitly stated otherwise. |
| 68 | +
|
| 69 | +Contrarily, the API for implementation of new iterators, including the design of the `Iterator` |
| 70 | +typeclass, is still experimental and will change in the future. It is already planned that there |
| 71 | +will be a breaking change to make the iterators more flexible with regard to universes, a change |
| 72 | +that needs to wait for a language feature. |
| 73 | +
|
| 74 | +## Module structure |
| 75 | +
|
| 76 | +A distinction that cuts through the whole module is that between pure and monadic |
| 77 | +iterators. Each submodule contains a dedicated `Monadic` sub-submodule. |
| 78 | +
|
| 79 | +All of the following module names are prefixed with `Std.Data.Iterators`. |
| 80 | +
|
| 81 | +### Basic iterator API |
| 82 | +
|
| 83 | +* `Basic` defines `Iter` and `IterM` as well as `Iterator`, `Finite` |
| 84 | + and `Productive` typeclasses. |
| 85 | +* `Producers` provides iterator implementations for common data types. |
| 86 | +* `Consumers` provides functions that take one or more iterators, iterate over them and potentially |
| 87 | + return some result. Examples are the `toList` function and an instance for the `ForIn` typeclass. |
| 88 | + These operations allow for what is also known as *internal iteration*, where the caller delegates |
| 89 | + the control flow during the iteration to the called consumer. |
| 90 | +* `Combinators` will provide operations that transform one or more iterators into a new iterator |
| 91 | + as soon as the first such combinator has been implemented. |
| 92 | +
|
| 93 | +### Verification API |
| 94 | +
|
| 95 | +`Lemmas` will provide the means to verify programs that use iterators. |
| 96 | +
|
| 97 | +### Implementation details |
| 98 | +
|
| 99 | +`Internal` contains code that should not be relied upon because it may change in the future. |
| 100 | +This whole module is explicitly experimental and it is not advisable for downstream users to |
| 101 | +expect stability to implement their own iterators at this point in time. |
| 102 | +
|
| 103 | +-/ |
0 commit comments