2013-01-09

ECMAScript.next: array comprehensions and generator comprehensions

Update 2013-03-19: this post now uses the latest ECMAScript.next syntax (as decided during the January 2013 TC39 meeting).

ECMAScript.next will have two kinds of comprehensions: array comprehensions and generator comprehensions. They allow one to quickly assemble an array or a sequence of elements. Comprehensions exist in many programming languages, for example: CoffeeScript, Python, Haskell, Clojure.

Array comprehensions

Array comprehensions look like this:
    [for (x of a) for (y of b) if (x > y) [x,y]]
This is equivalent to calling the following function (which uses ECMAScript.next’s for-of loop [1]).
    function arrayComprehension() {
        let result = [];
        for (let x of a) {
            for (let y of b) {
                if (x > y) {
                    result.push([x,y]);
                }
            }
        }
        return result;
    }
There can be two kinds of clauses inside an array comprehension, in any order (but the first clause must be a for):
  • for
  • if
Array comprehensions are especially convenient for translating one array to another one:
    let numbers = [1,2,3];
    let squares = [for (x of numbers) x*x];
However, Array.prototype.map becomes more convenient in ECMAScript.next, too, because there will be arrow functions [2]:
    let squares = numbers.map(x => x * x);

Generator comprehensions

Generator comprehensions work and look almost like array comprehensions. But they are delimited by parentheses and produce a generator object [1]. That object yields the elements instead of putting them in an array (which means that you can work with potentially infinite sequences). For example:
    (for (x of a) for (y of b) if (x > y) [x,y])
This is equivalent to calling the following generator function.
    function* generatorComprehension() {
        for (x of a) {
            for (y of b) {
                if (x > y) {
                    yield [x,y];
                }
            }
        }
    }
You can iterate over the yielded elements like this:
    let compr = ( ... );
    for (elem of compr) {
        console.log(elem);
    }

Syntax: left-to-right versus right-to-left

ECMAScript.next will use left-to-right syntax: the expression producing the elements comes last, after the clauses. Quoting David Herman:
Note that while Haskell and Python use the right-to-left syntax, F# and C# both have left-to-right syntax.
The advantage of left-to-right syntax is that it mirrors how one would write imperative loops and if statements (in the manner shown above).

Trying out comprehensions in Firefox

You can try out comprehensions in Firefox, but their syntax not the same as in ECMAScript.next (yet):

References

  1. ECMAScript.next: for-of, iterators, generators
  2. ECMAScript.next: arrow functions and method definitions

No comments: