En programación, ¿cuáles son los beneficios de la transparencia referencial ?
RT hace una de las principales diferencias entre los paradigmas funcionales e imperativos, y los defensores del paradigma funcional lo utilizan a menudo como una clara ventaja sobre el imperativo; pero en todos sus esfuerzos, estos defensores nunca explican por qué es un beneficio para mí como programador .
Claro, tendrán sus explicaciones académicas de cuán "puro" y "elegante" es, pero ¿cómo lo hace mejor que un código menos "puro"? ¿Cómo me beneficia en mi programación diaria?
Nota: Esto no es un duplicado de ¿Qué es la transparencia referencial? Este último aborda el tema de lo que es RT, mientras que esta pregunta aborda sus beneficios (que pueden no ser tan intuitivos).
fuente
Respuestas:
El beneficio es que las funciones puras hacen que su código sea más fácil de razonar. O, en otras palabras, los efectos secundarios aumentan la complejidad de su código.
Tome un ejemplo de
computeProductPrice
método.Un método puro le pediría una cantidad de producto, una moneda, etc. Usted sabe que siempre que se llame al método con los mismos argumentos, siempre producirá el mismo resultado.
Un método no puro será más complejo de usar y depurar. Dado que depende del estado de las variables que no sean los argumentos y posiblemente las altere, significa que podría producir resultados diferentes cuando se llama varias veces, o no tener el mismo comportamiento cuando no se llama o se llama demasiado pronto o demasiado tarde.
Ejemplo
Imagine que hay un método en el marco que analiza un número:
No tiene transparencia referencial, porque depende de:
La variable de entorno que especifica el sistema de numeración, que es Base 10 u otra cosa.
La variable dentro de la
math
biblioteca que especifica la precisión de los números para analizar. Entonces, con el valor de1
, el análisis de la cadena"12.3456"
dará12.3
.La cultura, que define el formato esperado. Por ejemplo, con
fr-FR
, el análisis"12.345"
dará12345
, porque el carácter de separación debería ser,
, no.
Imagine lo fácil o difícil que sería trabajar con tal método. Con la misma entrada, puede tener resultados radicalmente diferentes dependiendo del momento en que llame al método, porque algo, en algún lugar, cambió la variable de entorno o cambió la cultura o estableció una precisión diferente. El carácter no determinista del método conduciría a más errores y más pesadillas de depuración. Llamar
math.parse("12345")
y obtener5349
una respuesta ya que algún código paralelo estaba analizando números octales no es bueno.¿Cómo arreglar este método obviamente roto? Mediante la introducción de la transparencia referencial. En otras palabras, deshaciéndose del estado global y moviendo todo a los parámetros del método:
Ahora que el método es puro, sabe que no importa cuándo lo llame, siempre producirá el mismo resultado para los mismos argumentos.
fuente
packet = socket.recv()
referencialmente transparente en lugar de derrotar el punto de la función.invariant
? O son los mismos que paraen_us
, en cuyo caso, por qué molestarse, o corresponden a algún otro país, en cuyo caso, cuál y por qué este en lugar deen_us
, o tienen sus reglas específicas que no coinciden con ningún país de todos modos , lo que sería inútil. Realmente no hay una "respuesta verdadera" entre12,345.67
y12 345,67
: cualquier "regla predeterminada" funcionará para algunos países, y no funcionará para otros.12345
analiza como 12345,12 345
o12,345
o12.345
es un error.12.345
analizado como un número invariante de coma flotante siempre produce 12.345, de acuerdo con la convención del lenguaje de programación de usar. como el separador decimal. Las cadenas se ordenan por sus puntos de código Unicode y distinguen entre mayúsculas y minúsculas. Y así.¿A menudo agrega un punto de interrupción a un punto en su código y ejecuta la aplicación en el depurador para averiguar qué está sucediendo? Si lo hace, eso se debe principalmente a que no está utilizando la transparencia referencial (RT) en sus diseños. Y así que tengo que ejecutar el código para resolver lo que hace.
Todo el punto de RT es que el código es altamente determinista, es decir, puede leer el código y calcular lo que hace, cada vez, para el mismo conjunto de entradas. Una vez que comience a agregar variables mutantes, algunas de las cuales tienen un alcance más allá de una sola función, no puede simplemente leer el código. Dicho código debe ejecutarse, ya sea en la cabeza o en el depurador, para determinar cómo funciona realmente.
Cuanto más simple sea leer y razonar el código, más sencillo será mantener y detectar errores, de modo que ahorre tiempo y dinero para usted y su empleador.
fuente
La gente usa el término "más fácil de razonar", pero nunca explica lo que eso significa. Considere el siguiente ejemplo:
Son
result1
yresult2
el mismo o diferente? Sin transparencia referencial, no tienes idea. En realidad, debe leer el cuerpo defoo
para asegurarse, y posiblemente el cuerpo de cualquier funciónfoo
, y así sucesivamente.Las personas no se dan cuenta de esta carga porque están acostumbradas, pero si vas a trabajar en un entorno puramente funcional durante un mes o dos, regresas y la sientes, y es un gran problema .
Hay tantos mecanismos de defensa que las personas hacen para solucionar la falta de transparencia referencial. Para mi pequeño ejemplo, es posible que desee mantener la
result1
memoria, porque no sabría si cambiaría. Luego tengo un código con dos estados: antesresult1
se almacenó y después. Con la transparencia referencial, puedo recalcularlo fácilmente, siempre que el recálculo no lleve mucho tiempo.fuente
result1
yresult2
son los mismos. Otro aspecto importante es que sifoo("bar", 12)
es referencialmente transparente, entonces no tiene que preguntarse si esta llamada ha producido algunos efectos en otro lugar (¿establecer algunas variables? ¿Eliminar un archivo? Lo que sea).Yo diría: la transparencia referencial no solo es buena para la programación funcional, sino para todos los que trabajan con funciones porque sigue el principio del mínimo asombro.
Tiene una función y puede razonar mejor sobre lo que hace porque no hay factores externos que deba tener en cuenta, para una entrada dada, la salida siempre será la misma. Incluso en mi lenguaje imperativo trato de seguir este paradigma tanto como sea posible, lo siguiente que básicamente se deduce automáticamente de esto es: pequeñas funciones fáciles de entender en lugar de las horribles funciones de más de 1000 líneas que a veces ejecuto.
Esas grandes funciones hacen magia y me da miedo tocarlas porque pueden romperse de manera espectacular.
Entonces, las funciones puras no son algo solo para la programación funcional, sino para todos los programas.
fuente