As perguntas são:
- Os geradores quebram o paradigma de programação funcional? Por que ou por que não?
- Se sim, os geradores podem ser usados na programação funcional e como?
Considere o seguinte:
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
O downCounter
método parece sem estado. Além disso, chamar downCounter
com a mesma entrada sempre resultará na mesma saída. No entanto, ao mesmo tempo, a chamada next()
não produz resultados consistentes.
Não tenho certeza se os geradores quebram ou não o paradigma de programação funcional, porque neste exemplo counter
é um objeto gerador e, portanto, a chamada next()
produziria os mesmos resultados que outro objeto gerador criado exatamente com o mesmo maxValue
.
Além disso, chamar someCollection[3]
uma matriz sempre retornaria o quarto elemento. Da mesma forma, chamar next()
quatro vezes em um objeto gerador também sempre retornaria o quarto elemento.
Para mais contexto, essas questões foram levantadas durante o trabalho em um kata de programação . A pessoa que respondeu à pergunta levantou a questão de saber se os geradores poderiam ou não ser usados na programação funcional e se eles mantêm ou não o estado.
Respostas:
As funções do gerador não são particularmente especiais. Podemos implementar um mecanismo semelhante, reescrevendo a função do gerador em um estilo baseado em retorno de chamada:
Claramente, o
downCounter
é o mais puro e funcional possível. Não há nenhum problema aqui.O protocolo do gerador usado pelo JavaScript envolve um objeto mutável. Isso não é necessário, veja o código acima. Em particular, objetos mutáveis significam que perdemos transparência referencial - a capacidade de substituir uma expressão por seu valor. Enquanto no meu exemplo,
counter.next().value
vai sempre ser avaliada como25
não importa onde ela ocorre e como muitas vezes repeti-lo, este não é o caso com o gerador JS - em um ponto que é26
, então25
, e que poderia realmente ser qualquer número. Isso é problemático se passarmos uma referência ao gerador para outra função:Tão claramente que os geradores mantêm o estado e, portanto, não são adequados para a programação funcional "pura". Felizmente, você não precisa fazer programação funcional pura e pode ser pragmático. Se os geradores tornarem seu código mais claro, você deverá usá-los sem consciência. Afinal, o JavaScript não é uma linguagem funcional pura, ao contrário de Haskell.
A propósito, em Haskell, não há diferença entre retornar uma lista e um gerador, pois ele usa uma avaliação lenta:
fonte