what react pure functional-programming purely-functional

functional programming - react - ¿Cómo se realizan los efectos secundarios en la programación funcional pura?



pure function react (2)

Haskell, un lenguaje funcional puro, maneja funciones "impuras" usando "mónadas". Una mónada es básicamente un patrón que hace que sea fácil encadenar llamadas de función con el paso de continuación. Conceptualmente, la función de impresión en Haskell básicamente toma tres parámetros: la cadena a imprimir, el estado del programa y el resto del programa. Llama al resto del programa mientras pasa en un nuevo estado del programa donde la cadena está en la pantalla. De esta forma, ningún estado ha sido modificado.

Hay muchas explicaciones en profundidad sobre cómo funcionan las mónadas porque, por alguna razón, la gente piensa que es un concepto difícil de entender: no lo es. Puede encontrar muchos buscando en Internet, creo que este es el que más me gusta: http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html

Estoy tratando con el concepto de programación funcional desde hace un tiempo y lo encuentro bastante interesante, fascinante y emocionante. Especialmente la idea de funciones puras es asombrosa, en varios términos.

Pero hay una cosa que no entiendo: cómo lidiar con los efectos secundarios cuando te restringes a funciones puras.

Por ejemplo, si quiero calcular la suma de dos números, puedo escribir una función pura (en JavaScript):

var add = function (first, second) { return first + second; };

No hay problema. Pero, ¿y si quiero imprimir el resultado en la consola? La tarea de "imprimir algo en la consola" no es pura por definición, pero ¿cómo podría / debo lidiar con esto en un lenguaje de programación puramente funcional?


Hay algunos enfoques para esto. Una cosa que debes aceptar es que en algún momento existe una máquina mágica e impura que toma expresiones puras y las vuelve impuras al interactuar con el entorno. Se supone que no debes hacer preguntas sobre esta máquina mágica.

Hay dos enfoques que puedo pensar en la parte superior de mi cabeza. Existe al menos un tercero que he olvidado.

E / S Streams

El enfoque que es más fácil de entender podría ser la transmisión de E / S. Su función main toma un argumento: una secuencia de cosas que han sucedido en el sistema, esto incluye pulsaciones de teclas, archivos en el sistema de archivos, etc. Su función main también devuelve una cosa: una secuencia de cosas que desea que suceda en el sistema.

Las transmisiones son como listas, fíjate, solo tú puedes compilarlas un elemento a la vez y el destinatario recibirá el elemento tan pronto como lo hayas creado. Su programa puro lee de dicho flujo y agrega su propio flujo cuando quiere que el sistema haga algo.

El pegamento que hace que todo este trabajo funcione es una máquina mágica que se encuentra fuera de tu programa, lee de la secuencia de "solicitud" y pone cosas en la secuencia de "respuestas". Si bien tu programa es puro, esta máquina mágica no lo es.

El flujo de salida podría verse así:

[print(''Hello, world! What is your name?''), input(), create_file(''G:/testfile''), create_file(''C:/testfile''), write_file(filehandle, ''John'')]

y la corriente de entrada correspondiente sería

[''John'', IOException(''There is no drive G:, could not create file!''), filehandle]

Vea cómo la input en la salida resultó en ''John'' aparece en el in-stream? Ese es el principio.

E / S monádica

Monadic I / O es lo que hace Haskell, y lo hace realmente bien. Puede imaginar esto como construir un árbol gigante de comandos de E / S con operadores para unirlos, y luego su función main devuelve esta expresión masiva a una máquina mágica que se encuentra fuera de su programa y ejecuta los comandos y realiza las operaciones indicadas. Esta máquina mágica es impura, mientras que tu programa de construcción de expresiones es puro.

Es posible que desee imaginar este árbol de comandos que se ve algo así como

main | +---- Cmd_Print(''Hello, world! What is your name?'') +---- Cmd_WriteFile | +---- Cmd_Input | +---+ return validHandle(IOResult_attempt, IOResult_safe) + Cmd_StoreResult Cmd_CreateFile(''G:/testfile'') IOResult_attempt + Cmd_StoreResult Cmd_CreateFile(''C:/testfile'') IOResult_safe

Lo primero que hace es imprimir un saludo. Lo siguiente que hace es que quiere escribir un archivo. Para poder escribir en el archivo, primero debe leer desde la entrada lo que se supone que debe escribir en el archivo. Entonces se supone que tiene un identificador de archivo para escribir. Lo obtiene de una función llamada validHandle que devuelve el identificador válido de dos alternativas. De esta manera, puedes mezclar lo que parece un código impuro con lo que parece un código puro.

Esta "explicación" está al borde de hacer preguntas sobre la máquina mágica sobre la que se supone que no debes hacer preguntas, así que voy a concluir con algunas sabidurías.

  • La E / S real monádica no se parece en nada a mi ejemplo aquí. Mi ejemplo es una de las posibles explicaciones de cómo se puede ver la E / S monádica "debajo del capó" sin romper la pureza.

  • No intente usar mis ejemplos para comprender cómo trabajar con E / S pura. Cómo funciona algo bajo el capó es algo completamente diferente de cómo haces las cosas con él. Si nunca antes habías visto un automóvil en tu vida, tampoco te convertirías en un buen conductor al leer los planos de uno.

    La razón por la que sigo diciendo que se supone que no debes hacer preguntas sobre la máquina mágica que realmente hace las cosas es que cuando los programadores aprenden cosas, tienden a querer hurgar en la maquinaria para tratar de resolverlo. No recomiendo hacerlo para E / S pura. Es posible que la maquinaria no le enseñe nada sobre cómo usar diferentes variantes de E / S.

    Esto es similar a cómo no aprende Java mirando el bytecode de JVM desmontado.

  • Aprende a usar E / S monádicas y E / S basadas en flujos. Es una experiencia genial y siempre es bueno tener más herramientas debajo de su cinturón de herramientas.