Как отработать генератор? - PullRequest
0 голосов
/ 12 января 2019

Я реализовал every как генератор для преждевременного прерывания итерации:

const every = (f, iter) => function* () {
  for (const value of iter) {
    const ret = f(value);
    yield ret;
    if (!ret) break;
  }
} ();

const exhaustEvery = iter => {
  for (value of iter) {
    if (!value)
      return false;
  }

  return true;
};

exhaustEvery(every(x => x % 2 === 1, [1,3,5])); // true

Это кажется довольно громоздким, потому что я должен реализовать отдельную функцию выпуска для каждой итерационной функции. Указывает ли это на неправильное использование генераторов?

Ответы [ 3 ]

0 голосов
/ 12 января 2019

Есть генераторы, которые не могут быть исчерпаны, например:

function *fibonacci(n) {
  const infinite = !n && n !== 0;
  let current = 0;
  let next = 1;
  
  while (infinite || n--) {
    yield current;
    [current, next] = [next, current + next];
  }
}

// let [...first10] = fibonacci(10);
// alert(first10);
// the above is finite generator and shows how you can exhaust it,
// but what if it is initiated like the following:

let noexhaust = fibonacci();
alert(noexhaust.next().value);
alert(noexhaust.next().value);
alert(noexhaust.next().value);
alert(noexhaust.next().value);
// and so on...

Так каким должно быть поведение вашего кода, если он сталкивается с бесконечным генератором?

0 голосов
/ 12 января 2019

Если вы знаете, что ваш генератор закончится (что не гарантируют генераторы), вы можете распределить значения с помощью [...res]. В случае вашего генератора вы можете просто посмотреть на последнее значение:

const every = (f, iter) => function*() {
  for (const value of iter) {
    const ret = f(value);
    yield ret;
    if (!ret) break;
  }
}();


let res = [...every(x => x % 2 === 1, [1, 3, 5])]; // true
console.log(res[res.length - 1])

res = [...every(x => x % 2 === 1, [1, 3, 5, 8, 2, 5, 9])]; // false
console.log(res[res.length - 1])

Но если вы делаете все это только для того, чтобы сгенерировать список из генератора, может быть лучший способ с простой функцией.

0 голосов
/ 12 января 2019

Не имеет смысла, что every является генератором, так как он не генерирует значения сам, он просто возвращает истину или ложь, поэтому это может быть просто:

 function every(iterator, predicate) {
    let value, done;
    do {
      ({ value, done } = iterator.next());
      if(!predicate(value)) return false;
    } while(!done)
    return true;
}

every([1, 2, 3].values(), it => it < 3) // false
...