Las preguntas son:
- ¿Los generadores rompen el paradigma de programación funcional? ¿Por qué o por qué no?
- En caso afirmativo, ¿se pueden usar generadores en la programación funcional y cómo?
Considera lo siguiente:
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
El downCounter
método parece apátrida. Además, llamar downCounter
con la misma entrada siempre dará como resultado la misma salida. Sin embargo, al mismo tiempo, las llamadas next()
no producen resultados consistentes.
No estoy seguro de si los generadores rompen o no el paradigma de programación funcional porque en este ejemplo counter
es un objeto generador y, por next()
lo tanto, la llamada produciría los mismos resultados que otro objeto generador creado con exactamente el mismo maxValue
.
Además, llamar someCollection[3]
a una matriz siempre devolvería el cuarto elemento. Del mismo modo, llamar next()
cuatro veces a un objeto generador también siempre devolvería el cuarto elemento.
Para más contexto, estas preguntas se plantearon mientras trabajaba en un kata de programación . La persona que respondió a la pregunta, planteó la pregunta de si los generadores podrían usarse o no en la programación funcional y si tienen o no estado.
Respuestas:
Las funciones del generador no son particularmente especiales. Podemos implementar un mecanismo similar nosotros mismos reescribiendo la función del generador en un estilo basado en devolución de llamada:
Claramente, el
downCounter
es tan puro y funcional como se pone. No hay problema aquí.El protocolo generador utilizado por JavaScript involucra un objeto mutable. Esto no es necesario, consulte el código anterior. En particular, los objetos mutables significan que perdemos la transparencia referencial : la capacidad de reemplazar una expresión por su valor. Mientras que en mi ejemplo,
counter.next().value
será siempre evaluar a25
no importa donde se produce y con qué frecuencia lo repetimos, este no es el caso con el generador de JS - en un momento dado es26
, entonces25
, y lo que realmente podría ser cualquier número. Esto es problemático si pasamos una referencia al generador a otra función:Claramente, los generadores mantienen el estado y, por lo tanto, no son adecuados para la programación funcional "pura". Afortunadamente, no tiene que hacer programación funcional pura, y puede ser pragmático. Si los generadores aclaran su código, debe usarlos sin una mala conciencia. Después de todo, JavaScript no es un lenguaje funcional puro, a diferencia de, por ejemplo, Haskell.
Por cierto, en Haskell no hay diferencia entre devolver una lista y un generador, ya que utiliza una evaluación diferida:
fuente