Slightly different approach that I've found [1] quite useful.
Consider this simple function:
function range(start,end) {
var i = start;
return function() {
if( i < end ) return i++;
}
}
It returns so called iterator function (not an Iterator but just a function).
and imagine that for/in ( or for/of )
for(var el in something)
statement is modified to support functions as collections. So body of
the for loop is called until function
`something` returns anything but not void.
Having this this we can write something like this:
for(var i in range(12,48)) {
console.log(i);
}
In principle this simple change eliminates need of most of
generator/yield cases.
I am not sure if it close to the problem you describe but something
tells me that it is.
[1]
http://www.codeproject.com/Articles/33662/TIScript-language-a-gentle-extension-of-JavaScript
On Tue, Jul 30, 2013 at 5:21 AM, Claude Pache <[email protected]> wrote:
>
> TL;DR: We propose to add functionalities to the `for/of` loop that make all
> features of generators (and iterators) available. Currently, the features
> unavailable in `for/of` loops are: values sent to the generator that are
> retrieved by the `yield` expression, and closing value produced by the
> generator using the `return` statement. The pretext is to make it possible to
> rewrite naturally `someArray.reduce(functionExpression)` et al. when used
> inside a generator function, so that `functionExpression` could contain
> `yield` statements, a problem raised in a recent thread.
>
>
> In a recent thread [1], it has been noted that, when using `.forEach` and
> friends inside a generator, you cannot use `yield` inside the callback.
>
> There has been some reflections on how to fix generators in order to avoid
> that defect; but it was taking the problem by the wrong side, for the issue
> does not come from the generator function,
> but from the `.forEach` construct: it uses a first-class callback function
> where `for/of` uses a second-class block.
>
> Let's see how to reimplement `.forEach` et al. with ES6 tools, so that it
> just works. Consider a generic loop:
>
> ```
> // `arr` is an array
> for (let v of arr) {
> // do something with with v
> }
> ```
>
> Suppose that you want to run the loop only for even-ranked items of the
> array. You could do something like this:
>
> ```
> Array.prototype.forEachEven = function(f, o) {
> // For simplicity, we ignore the issue of sparse arrays.
> for (let i = 0; i < this.length; i += 2) {
> f.call(o, this[i], i, this)
> }
> }
>
> arr.forEachEven(function(v) {
> // do something with v
> // But you can't use yield, break or return :-(
> }, this)
> ```
>
> However, instead of transforming the entire for/of loop, it is more on-focus
> to act on the iteration part only. I mean the following:
>
> ```
> function* gEven(iterable) {
> let i = 0
> for (let x of iterable) {
> if (i % 2 === 0) {
> yield x
> }
> i += 1
> }
> }
>
> for (let v of gEven(arr)) {
> // do something with with v
> // You can use yield, break or return here, and it will just work :-)
> }
> ```
>
> As you see, no more callback, no more problem. (For sure, you can *also* use
> `yield*` inside the loop in order to abstract away some code; but the focus
> of this message is on the iteration protocol.)
>
> Now (and from here the things are becoming interesting), let us try to
> reimplement `Array.prototype.some` and `Array.prototype.reduce`
> using that pattern:
>
> ```
> r = arr.some(function(v) {
> let condition
> // compute `condition`
> return condition
> }, this)
>
> r = arr.reduce(function(x, v) {
> let combined
> // combine `x` and `v` into `combined`
> return combined
> }, initialValue)
> ```
>
> Here, we need:
> (1) retrieve the intermediate results returned by the callback (`condition`
> and `combined` in our examples);
> (2) provide the final result of the loop (the value that'll be stored in `r`)
>
> On the side of generators, all is already done, for you can:
> (1) retrieve an intermediate result by evaluating a `yield` expression;
> (2) produce the final result using a `return` statement.
> or, more generally, in the case of iterators:
> (1) an intermediate result is retrieved by the first argument of the `next`
> method`;
> (2) the final result is produced by returning `{ done: true, value: result }`.
>
> Thus, we obtain:
> ```
> function* gSome(iterator) {
> for (let v of iterator) {
> if (yield v)
> return true
> }
> return false
> }
>
> function* gReduce(iterator, r) {
> for (let v of iterator) {
> r = yield [r, v]
> }
> return r
> }
> ```
>
> However, on the side of the `for/of loop`, there is currently (to my
> knowledge) no way to send or retrieve results to/from the iterator being
> traversed.
> Therefore, I propose to add the functionality:
>
> (1) Sending an intermediate result to the iterator: use a `continue with
> expression` statement.
> (2) Producing the final result: The for/of loop becomes an expression, which
> evaluates to either:
> (a) the closing value sent by the iterator, or:
> (b) the `expression` of a `break with expression` statement.
>
> (There is no LineTerminator between `continue/break` and `with`. The use of
> the reserved word `with` means that it can't be confused with a label.)
> Using that syntax, our loops are written as following:
>
> ```
> r = for (let v of gSome(arr)) {
> let condition
> // compute `condition`, using `yield` ad libitum
> continue with condition
> }
>
> r = for (let [x, v] of gReduce(arr, initialValue)) {
> let combined
> // combine `x` and `v` into `combined`, using `yield` ad libitum
> continue with combined
> }
>
> r = for (let x of itr) {
> break with 42
> }
> // `r` will be equal to 42 if `itr` is not empty
> ```
>
> Naturally, you can also use labels:
> ```
> break label with expression;
> continue label with expression;
> ```
>
> It is true that the examples chosen are academic in the sense it isn't harder
> to write:
> ```
> var r = initialValue
> for (let v of arr) {
> let combined
> // combine `r` and `v` into `combined`, using `yield` ad libitum
> r = combined
> }
> ```
>
> Netherveless, it is a shame that some nice features of iteration protocol are
> unavailable in `for/of` loops, which is probably intended to be the main
> consumer of iterators.
>
> (And, if nothing else, it is a nice opportunity for the `with` keyword to
> redeem itself. :-P)
>
> —Claude
>
> [1] generators vs forEach:
> https://mail.mozilla.org/pipermail/es-discuss/2013-July/031919.html
>
>
> _______________________________________________
> es-discuss mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/es-discuss
--
Andrew Fedoniouk.
http://terrainformatica.com
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss