The goal is attaining the “Reuse” Augustss prefers about lazy evaluation, while not incurring the negative side-effects (i.e. resource and timing indeterminism) of lazy evaluation and also not forsaking encapsulation of resource lifetime management that imperative spaghetti such as unstructured use of iterators ostensibly might entail.

In Haskell we can write:

```
map :: (a -> b) -> [a] -> [b]
some :: (Maybe m) => (a -> m b) -> [a] -> [b]
f :: a -> b
g :: (Maybe m) => a -> m b
let x = some g (map f 0::1)
```

We can I suppose write that in Rust roughly as follows:

```
fn map<A,B,C:Collection>(fn(A) -> B, C<A>) -> C<B>;
fn some<A,B,C:Collection>(fn(A) -> Option<B>, C<A>) -> C<B>;
fn f<A, B>(A) -> B;
fn g<A,B>(A) -> Option<B>;
let x = some(g, map(f, {0, 1}));
```

Since Rust employs eager evaluation strategy, `map`

calls `f`

for every element before `some`

is called; thus if `some`

terminates (when `g`

returns `false`

) before all the elements have been enumerated, Rust has wasted some computation. Whereas, since Haskell employs lazy evaluation strategy, `f`

is only called for those elements which `some`

enumerates.

We need to employ inversion-of-control in an eager language so that the called functions can call and enumerate their callers. But this isn’t straightforward because the generalized structure and composability of `Collection`

semantics must be respected.

The most general forward enumeration function is a `fold`

where `B`

is the current value of the result of the fold and the `Option`

can terminate the enumeration early:

`fn fold<A,B>(Enumerable<A>, B, fn(B, A) -> Option<B>) -> B;`

The functions `map`

and `some`

can be built employing `fold`

.

Afaics, it would be impossible to build our design on the general fold without coroutines or generators, because there is no guarantee that the incremental partial orders of its interim result type can be enumerated incrementally, i.e. there are no assumptions that can be made about the semantics of the unbounded generic result type `B`

.

Afaics, if we were to instead build our design for inversion-of-control on `fn map<A,B,M:Monoid+Enumerable>(M<A>, fn(A) -> Option<B>) -> M<B>`

where the incremental consistency is honored and `M`

is consistent across the functional composition, then the optimization arises of ignoring the structure of the result type, compose the callers’ chain of `fn(A) -> Option<B>`

operations, enumerate the input `Enumerable`

(aka `Iterable`

) on those composed functions, and employ `Monoid::append`

to construct the result. In other words, simply call `map`

with the composed function.

For more general case where `M`

is not consistent but the enumeration can be modeled as an incremental cursor (see the aforementioned quoted reference), we only need a control function with that has a variadic input taking an `Enumerable+Monoid`

paired with each `fn(A) -> Option<B>`

operation in the composition. This control function can encapsulate all the resource lifetime management orthogonal to instance and compositions. I don’t see any reason we need coroutines or generators in this case. The instance of the `Enumerator`

(aka `Iterator`

) maintains the necessary state.

For more general case where the enumeration can’t be modeled as an incremental cursor (see the aforementioned quoted reference), we need to allow the `Enumerable:fold`

method decide when and how many times it will invoke the `fn(B, A) -> Option<B>`

operation so it can then yield to its caller, who can continue its `Enumerable:fold`

. So the input to `fold`

requires a `Yieldable`

interface:

`fn fold<A,B:Yieldable>(Enumerable<A>, B, fn(B, A) -> Option<B>) -> B;`

This `Yieldable`

interface should be implemented with stackless coroutines, which in this special case can be implemented with a function call that inputs and outputs its internal state so each yield (return from the function) can be restarted (by calling the function inputting the last output state). Otherwise known as generators.

The `fn(B, A) -> Option<B>`

operation must be a pure function so that it can’t leak resources to subvert the encapsulation of the resource lifetimes.

I believe this is more and less the rough outline at least to my current understanding of this issue.

Edit: the `fn(B, A) -> Option<B>`

operation does not have complete control over its efficiency w.r.t. to how many successive times it will be invoked relative to the yield. It can’t cache and queue expensive operations in `B`

because it can’t be sure it will be invoked again. Some improvement in this design may be needed.

Edit#2: I don’t think higher-kinded types are required by any of the functions mentioned above. They could possibly required for iterators.