Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
49
rated 0 times [  51] [ 2]  / answers: 1 / hits: 19604  / 11 Years ago, mon, december 30, 2013, 12:00:00

I came up with this simple experiment after reading the documentation on generators from MDN:


var nodes = {
type: 'root',
value: [
{ type: 'char', value: 'a' },
{ type: 'char', value: 'b' },
{ type: 'char', value: 'c' },
],
};

function* recursiveGenerator(node) {
if (node.type === 'root') {
node.value.forEach(function (subnode) {
for (var suffix of recursiveGenerator(subnode)) {
yield suffix;
}
});
}

else {
yield node.value;
}
}

for (generated of recursiveGenerator(nodes)) {
console.log(generated);
}

Running it on node.js v0.11.9 with the --harmony flag set produces the following error:


alix@900X4C:~$ node --version
v0.11.9
alix@900X4C:~$ node --harmony test.js

/home/alix/test.js:14
yield suffix;
^^^^^^
SyntaxError: Unexpected identifier

I also tried using for ... in ... and the let keyword instead of var, but without any success.


I don't understand what yield* does exactly, but if I use it within the for loop I get instead:


alix@900X4C:~$ node --harmony test.js 

/home/alix/test.js:14
yield* suffix;
^
ReferenceError: yield is not defined

If I replace the yield in the for with console.log() it outputs a, b and c. What am I doing wrong?




Edit


Here's a minimalistic generator, showing that node.js knows what to do with generators:


function* alpha() {
yield 'a';
yield 'b';
yield 'c';
}

for (var suffix of alpha()) {
console.log(suffix);
}

Output:


alix@900X4C:~$ node --harmony y.js 
a
b
c



Solution (thanks @Andrew)


function* recursiveGenerator(node) {
if (node.type === 'root') {
for (var i = 0; i < node.value.length; ++i) {
var subnode = node.value[i];

for (var suffix of recursiveGenerator(subnode)) {
yield suffix;
}
}
}

else {
yield node.value;
}
}

for (generated of recursiveGenerator(nodes)) {
console.log(generated);
}

More From » node.js

 Answers
45

Summarizing the comments: you can't use yield inside a regular function, so you can't use yield with forEach. Here an example of generatorized foreach:



function * foreach (arr, fn) {
var i

for (i = 0; i < arr.length; i++) {
yield * fn(arr[i])
}
}

function * gen (number) {
yield number + 1
yield number + 2
yield number + 3
}

function * other () {
yield * foreach([1, 2, 3], gen)
}

for (var i of other()) {
console.log(i)
}


UPDATE
Also the original problem can be solved quite elegantly using such a helper:



var nodes = {
type: 'root',
value: [
{ type: 'char', value: 'a' },
{ type: 'char', value: 'b' },
{ type: 'root', value: [
{ type: 'char', value: 'c' },
{ type: 'char', value: 'd' },
{ type: 'char', value: 'e' },
]
},
],
}

function * foreach (arr, fn) {
var i

for (i = 0; i < arr.length; i++) {
yield * fn(arr[i])
}
}

function * value (val) {
yield val
}

function * recursiveGenerator(node) {
yield * node.type === 'root' ? foreach(node.value, recursiveGenerator) : value(node.value)
}

for (var generated of recursiveGenerator(nodes)) {
console.log(generated);
}


So the generator itself becomes a one-liner!


[#73493] Friday, December 27, 2013, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
ervindouglasm

Total Points: 451
Total Questions: 103
Total Answers: 102

Location: Turkmenistan
Member since Thu, Dec 1, 2022
2 Years ago
;