Pytania są następujące:
- Czy generatory łamią paradygmat programowania funkcjonalnego? Dlaczego lub dlaczego nie?
- Jeśli tak, czy generatory mogą być używane w programowaniu funkcjonalnym i jak?
Rozważ następujące:
function * downCounter(maxValue) {
yield maxValue;
yield * downCounter(maxValue > 0 ? maxValue - 1 : 0);
}
let counter = downCounter(26);
counter.next().value; // 26
counter.next().value; // 25
// ...etc
downCounter
Metodą wydaje bezstanowy. Również wywoływanie downCounter
z tym samym wejściem zawsze będzie skutkować tym samym wyjściem. Jednocześnie jednak wywoływanie next()
nie daje spójnych wyników.
Nie jestem pewien, czy generatory łamią paradygmat programowania funkcjonalnego, ponieważ w tym przykładzie counter
jest obiektem generatora, a więc wywołanie next()
dałoby takie same wyniki jak inny obiekt generatora utworzony z dokładnie takim samym maxValue
.
Również wywołanie someCollection[3]
tablicy zawsze zwróci czwarty element. Podobnie, next()
czterokrotne wywołanie obiektu generatora zawsze zwróci czwarty element.
Dla większego kontekstu pytania te zostały podniesione podczas pracy nad kata programistycznym . Osoba, która odpowiedziała na pytanie, zadała pytanie, czy generatory mogą być używane w programowaniu funkcjonalnym i czy posiadają stan.
Odpowiedzi:
Funkcje generatora nie są szczególnie szczególne. Możemy sami zaimplementować podobny mechanizm, przepisując funkcję generatora w stylu opartym na wywołaniu zwrotnym:
Oczywiście
downCounter
jest tak czysty i funkcjonalny, jak to tylko możliwe. Tutaj nie ma problemu.Protokół generatora używany przez JavaScript obejmuje obiekt zmienny. Nie jest to konieczne, patrz powyższy kod. W szczególności zmienne obiekty oznaczają, że tracimy przejrzystość referencyjną - możliwość zastąpienia wyrażenia jego wartością. Podczas gdy w moim przykładzie zawsze
counter.next().value
będzie oceniać bez względu na to, gdzie wystąpi i jak często go powtarzamy, nie jest tak w przypadku generatora JS - w pewnym momencie jest to i może być naprawdę dowolna liczba. Jest to problematyczne, jeśli przekazujemy odwołanie do generatora innej funkcji:25
26
25
Tak wyraźnie, generatory utrzymują stan i dlatego nie nadają się do „czystego” programowania funkcjonalnego. Na szczęście nie musisz robić czysto funkcjonalnego programowania i może być raczej pragmatyczny. Jeśli generatory sprawią, że Twój kod będzie wyraźniejszy, powinieneś go używać bez zbędnego sumienia. W końcu JavaScript nie jest czysto funkcjonalnym językiem, w przeciwieństwie do np. Haskell.
Nawiasem mówiąc, w Haskell nie ma różnicy między zwracaniem listy a generatorem, ponieważ używa on leniwej oceny:
źródło