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

Reply via email to