¿Por qué Today () es un ejemplo de una función impura?

38

Parece que, al leer algo como este artículo de Wikipedia sobre "funciones puras" , se enumeran Today()como un ejemplo de una función impura, pero me parece bastante puro. ¿Es porque no hay un argumento de entrada formal? ¿Por qué la hora real del día no se trata como la "entrada a la función" today()? )), la salida sería al mismo tiempo. Today()nunca te da un número al azar. siempre te da la hora del día.

El artículo de Wikipedia dice "diferentes tiempos producirá diferentes resultados", pero eso es como decir que para diferentes x sin(x)te dará diferentes proporciones. Y sin(x)es su ejemplo de una función pura.

Puntilla
fuente
8
Si pasaras a la hora del día, ¿qué haría la función?
JB King el
1
Espero que te dé la hora del día. (No es la función más útil). Pero no tiene ningún argumento, que creo que es la raíz de la respuesta.
Brad
3
¿Puede predecir su salida (en función de los parámetros de entrada que proporcionó)?
Daniel B
1
@DanielB No hay poder predictivo para el parámetro de entrada ausente / nulo que resulta. Lo único que puedo hacer es mirar mi reloj de pulsera (jk mi teléfono celular).
Brad
"¿Por qué la hora real del día no se trata como la" entrada a la función "? Este es, básicamente, el problema que las mónadas intentan resolver. Las funciones puras solo pueden basarse en sus entradas y no pueden tener efectos secundarios. Si hace del "estado del mundo antes que yo" una entrada y un "estado del mundo después de mí" como parte del valor de retorno y pasa estos estados mundiales a través de su programa, puede volver a ser puro.
Sean McSomething

Respuestas:

103

¿Es porque no hay un argumento de entrada formal?

Es porque la salida depende de algo que no es una entrada, es decir, la hora actual.

¿Por qué la hora real del día no se trata como la "entrada a la función"?

Porque no lo pasaste como parámetro. Si lo pasara como parámetro, la función se convertiría en una función de identidad en las fechas, lo cual es bastante inútil. El objetivo de una Today()función es generar algo que depende de un valor externo (constante) (tiempo).

La ventaja de las funciones puras es que su comportamiento es absolutamente reproducible y determinista, lo que facilita tener pruebas formales y garantías estrictas. Siempre hacen lo mismo. Today()es todo lo contrario: siempre (permitiendo granularidad de tiempo) hace algo diferente.

Michael Borgwardt
fuente
2
Entonces, aunque el tiempo de la realidad es una especie de entrada, porque no se da como entrada y está fuera del control de la función (tanto internamente a la función como fuera del control de quien llama Today()) se Today()vuelve impuro. La Today()función podría ser un ejemplo un poco tonto. Más apropiado podría ser alguna Count()función. Dado el mismo número de elementos a contar Count(), siempre se devolverá el mismo número, pero dado que eso está fuera del alcance Count(), es impuro.
Brad
1
@brad, que es algo así como un área gris, hay un argumento real implícito, la matriz o la lista. Dada una lista inmutable y el mismo argumento cada vez, siempre devolverá el mismo valor.
Max
34
"El tiempo de la realidad es una especie de entrada" - sí; de hecho, el estado global está implícitamente disponible (es decir, 'una especie de entrada') para todas las funciones, pero si dependen de él para su resultado , ¡son impuros!
AakashM
44
@Brad count()en la mayoría de los lenguajes de programación es definitivamente puro. Tiene un valor de entrada explícito: la colección cuyo recuento desea. No se confunda con una sintaxis como myCollection.count(); eso es solo azúcar para count(myCollection).
Andres F.
Gran respuesta como siempre, pero no cubre explícitamente las variables libres inmutables. No son una entrada a la función, no se pasan como un parámetro, pero la función depende de ellos, incluso si todavía es referencialmente transparente.
24

sin(x)siempre devolverá el mismo valor, siempre que xpermanezca igual. Today()podría devolver resultados diferentes con el tiempo porque depende de valores fuera de su control . Por ejemplo, si algo más allá del control de su programa cambia el sistema interno del sistema $current_datetime mientras su programa se está ejecutando, de Today()repente producirá resultados diferentes.

FrustratedWithFormsDesigner
fuente
"siempre devolverá un valor diferente" es un poco ... redacción impura . Wikipedia dice "devuelve el día actual de la semana", lo que significa que los valores obtenidos los lunes no diferirán
mosto
77
@gnat: Cierto, a menos que algo externo a su programa haya cambiado el calendario interno de su computadora de modo que de repente pensara que era jueves. Luego, la llamada Today()volvería "jueves" un lunes.
FrustratedWithFormsDesigner
3
@gnat Bueno, no siempre devolverá un valor diferente (casi no hay ninguna función útil que lo haga). Pero, como la mayoría de las funciones impuras, el valor de retorno puede variar incluso durante la ejecución de un solo programa (por ejemplo, si se ejecuta durante la noche).
3
@delnan: Sí, ¡esa es la pesadilla de los ingenuos autores de scripts de bases de datos! : P "¿Pero CÓMO podría faltar 300 registros? ¡El script funcionó bien cuando lo probé ayer por la mañana!"
FrustratedWithFormsDesigner
@delnan eso es seguro. Solo señalé que usar siempre en la redacción inicial (corregido en la respuesta de la versión actual a could ) era algo impreciso
mosquito
13

Today () es una función impura porque su resultado depende de algo que no le das; específicamente, la hora actual del sistema. Por lo tanto, su resultado no es determinista cuando se basa solo en las entradas proporcionadas en la invocación.

Una función pura sería int Add(int a, int b) {return a + b;}. La función funciona únicamente con lo que se proporciona y no utiliza otros datos de estado externos. El resultado natural de esto es que puedes Add(2,2)obtener 4 desde ahora hasta el final de los tiempos. Además, debido a que la función no cambia ningún estado externo (no tiene "efectos secundarios"), Agregar () ing 2 y 2 desde ahora hasta el final de los tiempos no cambiará nada más en el sistema, a menos que luego asigne el resultado de la función a una variable o use el valor para actualizar el estado (que no es una operación realizada por la función en sí). Prácticamente todas las operaciones matemáticas clásicas son funciones puras y pueden implementarse como tales.

Hoy (), por otro lado, puede producir el mismo valor cuando se llama dos veces seguidas, pero no si se llama repetidamente durante varios días. Esto se debe a que depende de datos de estado externos que usted no proporciona como parámetro para la función. Como resultado, es imposible, dentro de los límites del programa, controlar el resultado de la función Today (). Producirá un valor dado en un día determinado, y nunca producirá ese valor en ningún otro día, a menos que cambie el reloj del sistema de la computadora en la que se ejecuta (un cambio que generalmente ocurre fuera de los límites del programa).

Una función impura no es necesariamente algo malo; Se requieren funciones impuras, incluso en lenguajes funcionales, para interactuar con cualquier cosa fuera de los límites del programa, como almacenes de datos, canales de comunicación, pantallas de interfaz de usuario, dispositivos periféricos, etc. Un programa que no hace ninguna de estas cosas es un programa eso es muy limitado en su utilidad; Incluso iría tan lejos como para llamar trivial a un programa de este tipo, ya que sin ningún medio para aceptar la entrada o cualquier vía para informarle sobre su salida, bien podría no estar haciendo nada. Los programas escritos en lenguajes funcionales solo pueden tener la entrada proporcionada por el tiempo de ejecución y producir una salida informada al tiempo de ejecución sin ningún método impuro definido explícitamente, pero eso se debe a que el tiempo de ejecución está abstrayendo todos estos detalles impuros de trabajar dentro de un sistema informático imperfecto,

Es simplemente una cosa muy buena saber cuáles de las funciones que está utilizando son puras y cuáles no, para que pueda tomar buenas decisiones sobre cómo se utilizan. Las funciones impuras, debido a que hacen cosas o dependen de cosas que no son evidentes por su uso, pueden comportarse de manera impredecible si solo se tiene conocimiento del uso. Se requiere un mayor conocimiento del propósito de la función y, por lo tanto, de lo que necesita del estado externo o lo que necesita para colocar un sistema que lo use en un estado consistente y, por lo tanto, esperar un resultado determinista.

KeithS
fuente
8

Parece bastante obvio que esta función falla la primera prueba de pureza dada al comienzo de esa página:

  1. La función siempre evalúa el mismo valor de resultado dados los mismos valores de argumento. El valor del resultado de la función no puede depender de ninguna información oculta o estado que pueda cambiar a medida que avanza la ejecución del programa o entre diferentes ejecuciones del programa, ni puede depender de ninguna entrada externa de los dispositivos de E / S.

Tenga en cuenta que, dado que no requiere argumentos, solo hay un conjunto posible de valores de argumento: el conjunto vacío. Y esta función puede devolver resultados diferentes para el mismo 'valor (es) de argumento'.

Además, el valor resultado de la función no depende de "... estado oculto que puede cambiar a medida que avanza la ejecución del programa". Entonces otro fracaso.

AakashM
fuente
@ JörgWMittag No estoy seguro de dónde afirmo que una función sin argumentos no puede devolver un valor.
AakashM
Pedo cerebral. Leí "solo hay un posible conjunto de valores de retorno ".
Jörg W Mittag el
8

() => 1sería una función pura, ya que siempre devuelve 1. Today()puede devolver "lunes" o "martes" o casi cualquier otro valor.

Otra forma de pensar es que las funciones puras no dependen del estado. El mundo generalmente se considera estado. Necesita saber el estado de la realidad para saber qué día es hoy.

Sin embargo, no necesita saber nada especial sobre el estado del mundo para saber qué sin(x)es. Y siempre llamar a sin(x)un determinado xdevolverá el mismo valor.

Guvante
fuente
Wikipedia dice "Devuelve el día actual de la semana", lo que significa que puede volver los lunes, martes, etc, pero no "01/23/2013" ni "01/24/2013"
mosquito
77
@gnat: Actualizado, pero la diferencia no fue realmente material.
Guvante
2

Date(timestamp)Sería una función pura. Por su idempotencia. Y porque no habría efectos secundarios.

Today()puede variar su resultado dependiendo de cuándo lo llame. Eso es lo que lo hace impuro. No es idempotente. Sin embargo, no tiene efectos secundarios, pero eso no lo hace puro.

Florian Margaine
fuente
2

Aquí hay un pequeño pseudocódigo en el que pienso cuando hablo de funciones puras

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Si eso se ejecuta indefinidamente y nunca puede activar la afirmación, es una función pura. Más aún, si tiene una función que usa args, entonces una pequeña modificación ...

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Si puede usar eso después de cada asignación de variables en su aplicación, y no cambia los resultados en su aplicación, y nunca puede fallar la afirmación, entonces es una función pura.

Drake Clarris
fuente
2

Primero, no existe una función sin argumento (o una matriz sin índices o un mapa sin claves). Es la característica definitoria de una función asignar uno o más valores de argumento a otro valor.

Por lo tanto, todaytampoco es una función en absoluto, por lo tanto, no es una función pura. O podemos interpretar la sintaxis

today()

un poco para que signifique

today   ()      -- today, applied to the value ()

En Haskell, por ejemplo, esto sería válido:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

porque hay un tipo () con un solo valor ().

La pregunta es solo, ¿cómo se puede todaycalcular el día de la semana, si solo tiene ()? Simplemente no es posible sin leer el temporizador del sistema, directamente o mediante funciones auxiliares impuras.

El temporizador del sistema es un excelente ejemplo para el estado global.

Ingo
fuente
1

El problema today()es que puede producir un resultado diferente si se llama dos o más veces en una función.

Aquí hay un ejemplo de código que podría introducir un error.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

Es posible en el ejemplo anterior. Que la segunda ifdeclaración no se ejecutará. Incluso si el primero lo hizo. Dejar un recurso en mal estado.

Reactgular
fuente
1

Para ser una función pura, proporcionar los mismos parámetros debe dar el mismo resultado cada vez.

Cada vez que llamamos Today(), le proporcionamos los mismos parámetros (ninguno) y, sin embargo, no necesariamente obtenemos el mismo resultado (lunes, martes, etc.).

Zantier
fuente
44
esto parece simplemente repetir el punto hecho y explicado en una respuesta superior que se publicó hace aproximadamente dos años. No vale la pena chocar dos años cuestión con el contenido de esa manera
mosquito
1
No estoy muy familiarizado con cómo funciona stackexchange, pero pensé que, dado que esto estaba en las principales preguntas, ya había sido eliminado. En cuanto a repetir un punto, recuerdo haber leído en meta que puede ser útil tener múltiples respuestas similares. Siento que el mío es sucinto y potencialmente útil.
Zantier