2015-07-05 3 views
0

Мне кажется совершенно естественным, что генераторы, которые очень похожи на массивы, должны поддерживать самые основные операции с списком, такие как map(), filter() и reduce(). Я что-то упускаю?Почему генераторы не поддерживают map()?

Я написал код для map и кажется достаточно простым, но было бы гораздо лучше иметь все функции, встроенные во всех генераторах:

let fancyGen = g => { 
    let rv = function*() { 
    for (let x of g) 
     yield x; 
    } 
    rv.map = function*(p) { 
    for (let x of g) 
     yield p(x); 
    } 
    return rv; 
} 

Я новичок в генераторах, поэтому любые комментарии по коду приветствуются. В частности, это лучший способ написать «генератор идентичности»?

ответ

2

Почему генераторы не поддерживают карту()?

Потому что его слишком легко заполнить как реализацию пользовательского пространства. ES3 не включает в себя методы массива итераций либо, возможно, будет видеть трансформаторы для итераторов в ES7 :-)

генераторов, которые функционируют очень похожи Массивами

Нет, пожалуйста, прекратите и различать итераторов от генераторов:

  • итератор представляет собой объект с .next() способом, который соответствует протоколу итератора.
  • Генератор - это итератор, созданный функцией генератора (function*). Его метод .next() принимает аргумент, который является результатом каждого yield внутри функции генератора. Он также имеет методы .return() и .throw().

Вы в основном заинтересованы в итераторах, где мы не прошедшие значение next, и не заботимся о конечном результате - так же, как for of петель делают. Мы можем расширить их с нужными методами легко:

var IteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); 
IteratorPrototype.map = function*(f) { 
    for (var x of this) 
     yield f(x); 
}; 
IteratorPrototype.filter = function*(p) { 
    for (var x of this) 
     if (p(x)) 
      yield x; 
}; 
IteratorPrototype.scan = function*(f, acc) { 
    for (var x of this) 
     yield acc = f(acc, x); 
    return acc; 
}; 
IteratorPrototype.reduce = function(f, acc) { 
    for (var x of this) 
     acc = f(acc, x); 
    return acc; 
}; 

Это должно быть достаточно для начала, и наиболее распространенные случаи использования. Правильная библиотека расширит это до генераторов, чтобы значения были переданы соответствующим образом, а также будет решать проблему, что итераторы могут использоваться только один раз, прежде чем они исчерпаны (в отличие от массивов).

+0

Отличительные генераторы от итераторов - это как различие пуделей от собак - пудели * - это собаки, хотя не все собаки пудели. В обратном случае кейн-итераторы, которые не являются генераторами, неудобны и трудны в работе, поэтому я ограничиваю свои интересы генераторами (и обращается к синтаксису 'for..of'). – Malvolio

+1

Мне кажется, что 'reduce()' не должно быть функцией генератора. – Malvolio

+0

@ Malvolio: На самом деле генераторы гораздо более капризны и трудны в работе, чем обычные итераторы. Вы довольно редко сталкиваетесь с ними - все методы '[Symbol.iterator]' возвращают итераторы, а не генераторы. Доступ к генераторам через 'for of' не использует их полную мощность. – Bergi