Digamos que tenemos una función pura normal como
function add(a, b) {
return a + b
}
Y luego lo modificamos de modo que tenga un efecto secundario
function add(a, b) {
writeToDatabase(Math.random())
return a + b;
}
Por lo que sé, no se considera una función pura porque a menudo escucho que las personas llaman a las funciones puras "funciones sin efectos secundarios". Sin embargo, se comporta como una función pura en cuanto al hecho de que devolverá la misma salida para las mismas entradas.
¿Hay un nombre diferente para este tipo de función, no tiene nombre o sigue siendo puro y estoy equivocado acerca de la definición de pureza?
writeToDatabase
falla, podría desencadenar una excepción, haciendo que su segundaadd
función produzca una excepción a veces incluso si se llama con los mismos argumentos que antes no tenían problemas ... la mayoría de las veces tener efectos secundarios introduce este tipo de condiciones relacionadas con errores que se rompen "pureza de entrada-salida".F(x)
se define para devolvertrue
si se llama con el mismo argumento que la llamada anterior. Claramente con la secuencia{1,2,2} => {undefined, false, true}
esto es determinista, pero da diferentes resultados paraF(2)
.Respuestas:
No estoy seguro de las definiciones universales de pureza, pero desde el punto de vista de Haskell (un lenguaje donde los programadores tienden a preocuparse por cosas como la pureza y la transparencia referencial), solo la primera de sus funciones es "pura". La segunda versión de
add
no es pura . Entonces, en respuesta a su pregunta, lo llamaría "impuro";)Según esta definición, una función pura es una función que:
Con esta definición, está claro que su segunda función no puede considerarse pura, ya que infringe la regla 2. Es decir, los siguientes dos programas NO son equivalentes:
y
Esto se debe a que aunque ambas funciones devolverán el mismo valor, la función
f
escribirá en la base de datos dos veces, ¡perog
escribirá una vez! Es muy probable que las escrituras en la base de datos sean parte del comportamiento observable de su programa, en cuyo caso le he mostrado que su segunda versiónadd
no es "pura".Si las escrituras en la base de datos no son una parte observable del comportamiento de su programa, entonces ambas versiones de
add
pueden considerarse equivalentes y puras. Pero no puedo pensar en un escenario en el que escribir en la base de datos no importe. ¡Incluso la tala importa!fuente
f(x)
depende no solo dex
, sino también de alguna variable global externay
. Luego, sif
tiene la propiedad de RT, puede intercambiar libremente todas sus ocurrencias con su valor de retorno siempre que no lo toquey
. Sí, mi ejemplo es dudoso. Pero lo importante es: sif
escribe en la base de datos (o escribe en un registro) pierde la propiedad de RT: ahora no importa si dejay
intacto global , sabe el significado de su programa cambia dependiendo de si realmente llamarf
o simplemente usar su valor de retorno.Tal función se llama
Con respecto al estado:
Según la definición de una función que utilice, una función no tiene estado. Si vienes del mundo orientado a objetos, recuerda que
x.f(y)
es un método. Como una función se vería asíf(x,y)
. Y si le gustan los cierres con alcance léxico cerrado, recuerde que el estado inmutable también podría ser parte de la expresión de funciones. Es solo un estado mutable que impactaría las funciones de naturaleza determinista. Entonces f (x) = x + 1 es determinista siempre que el 1 no cambie. No importa dónde esté almacenado el 1.Sus funciones son ambas deterministas. Tu primero es también una función pura. Tu segundo no es puro.
El punto 1 significa determinista . El punto 2 significa transparencia referencial . Juntos significan que una función pura solo permite que sus argumentos y su valor devuelto cambien. Nada más causa cambio. Nada más ha cambiado.
fuente
Math.random()
. Entonces, no, a menos que supongamos un PRNG (en lugar de un RNG físico) Y consideremos que los PRNG indican parte de la entrada (que no es, la referencia está codificada), no es determinista.Si no le importa el efecto secundario, entonces es referencialmente transparente. Por supuesto, es posible que no te importe, pero a alguien más le importa, por lo que la aplicabilidad del término depende del contexto.
No conozco un término general para precisamente las propiedades que describe, pero un subconjunto importante son aquellos que son idempotentes . En ciencias de la computación, un poco diferente a las matemáticas *, una función idempotente es aquella que puede repetirse con el mismo efecto; es decir, el resultado del efecto secundario neto de hacerlo muchas veces es el mismo que hacerlo una vez.
Entonces, si su efecto secundario fuera actualizar una base de datos con un cierto valor en una determinada fila, o crear un archivo con contenido exactamente consistente, entonces sería idempotente , pero si se agrega a la base de datos o se agrega a un archivo , entonces no lo haría.
Las combinaciones de funciones idempotentes pueden o no ser idempotentes en su conjunto.
* El uso de idempotente de manera diferente en ciencias de la computación que las matemáticas parece provenir de un uso incorrecto del término matemático que se adoptó porque el concepto es útil.
fuente
(f x, f x)
conlet y = f x in (y, y)
correrá en fuera de espacio en el disco excepciones doble de rápido se podría argumentar que estos son casos extremos que no le importan, pero con una definición tan difusa, podríamos llamarlonew Random().Next()
referencialmente transparente porque, diablos, de todos modos no me importa qué número obtengo.Random.Next
en .NET tiene efectos secundarios. Mucho más. Si puedeNext
, asígnelo a una variable y luegoNext
vuelva a llamar y asígnelo a otra variable, lo más probable es que no sean iguales. ¿Por qué? Porque invocarNext
cambia algún estado interno oculto en elRandom
objeto. Este es el polo opuesto de la transparencia referencial. No entiendo su afirmación de que los "efectos principales" no pueden ser efectos secundarios. En el código imperativo es más común que no que el efecto principal sea un efecto secundario, porque los programas imperativos tienen estado por naturaleza.No sé cómo se llaman tales funciones (o si incluso hay algún nombre sistemático), pero llamaría a una función que no es pura (ya que otras respuestas se acobardan) pero siempre devuelve el mismo resultado si se proporciona con los mismos parámetros. parámetros "(en comparación con la función de sus parámetros y algún otro estado). Lo llamaría simplemente función, pero desafortunadamente cuando decimos "función" en el contexto de la programación, queremos decir algo que no tiene que ser una función real.
fuente
Básicamente depende de si te importa o no la impureza. Si la semántica de esta tabla es que no le importa cuántas entradas hay, entonces es puro. De lo contrario, no es puro.
O para decirlo de otra manera, está bien siempre que las optimizaciones basadas en la pureza no rompan la semántica del programa.
Un ejemplo más realista sería si intentara depurar esta función y agregara declaraciones de registro. Técnicamente, el registro es un efecto secundario. ¿Los registros lo hacen impuro? No.
fuente
Diría que lo mejor que podemos preguntar no es cómo lo llamaríamos, sino cómo analizaríamos un código de este tipo. Y mi primera pregunta clave en dicho análisis sería:
Esto es sencillo de ilustrar en Haskell (y esta oración es solo medio chiste). Un ejemplo del caso "no" sería algo como esto:
En este ejemplo, la acción que tomamos (imprimir la línea
"I'm doubling some number"
) no tiene impacto en la relación entrex
y el resultado. Esto significa que podemos refactorizarlo de esta manera (usando laApplicative
clase y su*>
operador), lo que muestra que la función y el efecto son de hecho ortogonales:Entonces, en este caso, yo personalmente diría que es un caso en el que puedes factorizar una función pura. Gran parte de la programación de Haskell se trata de esto: aprender a factorizar las partes puras del código efectivo.
Un ejemplo del tipo "sí", donde las partes pura y efectiva no son ortogonales:
Ahora, la cadena que imprime depende del valor de
x
. La función de la parte (multiplicarx
por dos), sin embargo, no depende de los efectos en absoluto, por lo que todavía puede factorizar un vistazo:Podría seguir deletreando otros ejemplos, pero espero que esto sea suficiente para ilustrar el punto con el que comencé: no lo "llamas" algo, analizas cómo se relacionan las partes pura y efectiva y las factorizas cuando es así. a su ventaja.
Esta es una de las razones por las que Haskell usa su
Monad
clase tan ampliamente. Las mónadas son (entre otras cosas) una herramienta para realizar este tipo de análisis y refactorización.fuente
Las funciones que están destinadas a causar efectos secundarios a menudo se denominan efectivas . Ejemplo https://slpopejoy.github.io/posts/Effectful01.html
fuente