14

Here's a ES6 generator:

function *Gen() {
    var input1 = yield 'output1'
}

var gen = Gen()

gen.next('input1').value // return 'output1'

gen called 1st time, return output1 but the variable input1 doesn't equal 'input1' which passed in , the value of input actually is the 'input2', 2nd time next('input2')called

My question is how to access the input1 which is the first time next called, something like:

function *Gen() {
    var input 1 = param1
    var input2 = yield 'output1'
}
mko
  • 21,334
  • 49
  • 130
  • 191
  • 1
    Well-known problem. The usual solution is to yield a dummy initial value which is thrown away, but servers to "seed" the generator. –  Jul 04 '15 at 08:39

5 Answers5

26

When you obtain the generator you don't have yields you can push value to (you are at the beginning of the generator function). You need to trigger the generator and reach the first yield by calling gen.next() without any arguments. At this point you have an yield at your disposal and you can push your value via gen.next('input1') effectively replacing the expression yield 'output1' with the value you passed to next - 'input1'. Then you need another yield or a return to provide your custom value to the consumer of the generator. Here is the code:

function *Gen() {
    var input1 = yield 'output1'
    return input1
}

var gen = Gen()

gen.next();
gen.next('input1').value // return 'input1'
gkostadinoff
  • 276
  • 3
  • 3
  • 2
    `When you obtain the generator you don't have yields you can push value to (you are at the beginning of the generator function)` +1 – RIYAJ KHAN Mar 04 '18 at 06:35
7

This great article about generator answered my question, input1 has been tossed away, there's no way to access it. It's weird but true

mko
  • 21,334
  • 49
  • 130
  • 191
  • 2
    Please include the relevant parts of the article to your answer, otherwise If the link goes down it won't hold any value anymore. – totymedli Sep 29 '21 at 08:01
3

First, let's simply this example:

function *createGenerator(input) {
    yield input
}

var generator = createGenerator('input')

console.log(
    generator
    .next()
    .value
)
// input

So you can pass a value into the generator on creation and pull it out, but if you've already created the generator, the only way to get a value in is by passing it through .next. But which .next?

function *createGenerator() {
    const input = yield
    yield input
}

var generator = createGenerator()

console.log(
    generator
    .next('input1')
    .value
)
// undefined

console.log(
    generator
    .next('input2')
    .value
)
// input2

As you can see in this example, the first input doesn't come through, but the second does. That's because your code executes in a generator up to the first yield and then stops. Because of that, the first value you pass in will be missing because there's no code to evaluate it.

Let's look at another example:

function *createGenerator() {
    const input1 = yield
    const input2 = yield input1
    yield input2
}

var generator = createGenerator()

console.log(
    generator
    .next('input0')
    .value
)
// undefined

console.log(
    generator
    .next('input1')
    .value
)
// input1

console.log(
    generator
    .next('input2')
    .value
)
// input2

console.log(
    generator
    .next('input3')
    .value
)
// undefined

When you call .next the second time, you evaluate the value passed in, and keep processing code until the next yield. In this case, you execute yield input, but nothing to the left of it because that's technically the "next line" of execution in JavaScript's AST.

Kevin Ghadyani
  • 6,829
  • 6
  • 44
  • 62
2

If you want a parametrised generator function you can use a higher order function that returns generator:

function myGenerator(startFrom) {
    return (function *() {
        var i = startFrom;
        while (true) yield i++;
    })();
}

var gen = myGenerator(5);
console.log(gen.next().value) // 5
console.log(gen.next().value) // 6
console.log(gen.next().value) // 7

Higher order generators can be of use too:

function getGenerator(baseStartFrom, expStartFrom) {
    return (function *() {
        var a = baseStartFrom;
        while (true) {
          yield (function *() {
              var i = expStartFrom;
              while (true) yield Math.pow(a, i++);
          })();
          a++;
        }
    })();
}

var gen = getGenerator(2, 3);
var gen2 = gen.next().value; // generator yields powers of 2
  console.log(gen2.next().value); // 8
  console.log(gen2.next().value); // 16
  console.log(gen2.next().value); // 32
var gen3 = gen.next().value; // generator yields powers of 3
  console.log(gen3.next().value); // 27
  console.log(gen3.next().value); // 81
  console.log(gen3.next().value); // 243

The sample is most likely useless but the same approach can be used, for example, to generate random number generators.

esp
  • 7,314
  • 6
  • 49
  • 79
  • 1
    Huh? That's not a higher-order function. And could be replaced by the trivial `function* myGenerator(i) { while (true) yield i++; }` – Bergi Feb 26 '15 at 23:17
  • @Bergi you can indeed :) Somehow I thought you cannot. Thanks. What's wrong with "higher-order" term? – esp Mar 09 '15 at 09:53
  • To me, neither of your generators matches the definition of [higher-order functions](https://en.wikipedia.org/wiki/Higher-order_function) – Bergi Mar 09 '15 at 10:11
  • doesn't return functions indeed... probably did originally. – esp Mar 17 '15 at 22:09
  • i upvoted this -- it's awesome and was exactly what i needed, thank you – mad.meesh Oct 20 '17 at 16:32
0

This works for me to generate a random number by passing the max value it should return.

function *GenerateRandomNumber(maxNo){
    while(true){
        yield Math.floor(Math.random() * maxNo);
    }
}

let randomGenerator = GenerateRandomNumber(10);
randomGenerator.next().value; // A random Number between 0 - 9
suban khoja
  • 151
  • 1
  • 4