Pourquoi Today () est-il un exemple de fonction impure?

38

Il semble que lorsque vous lisez quelque chose comme cet article Wikipedia sur les "fonctions pures" , ils citent Today()en exemple une fonction impure, mais cela me semble assez pur. Est-ce parce qu'il n'y a pas d'argument d'entrée formel? Pourquoi l’heure du jour n’est-elle pas traitée comme une "entrée de la fonction", auquel cas, si vous lui avez donné la même entrée, c’est-à-dire exécutée today()deux fois à la même heure, ou si vous avez voyagé dans le temps pour l'exécuter à nouveau (peut-être une hypothèse: )), la sortie serait la même heure. Today()ne vous donne jamais un nombre aléatoire. il vous donne toujours l'heure du jour.

L'article de Wikipédia dit "des moments différents donneront des résultats différents", mais c'est comme si vous disiez pour différentes x sin(x)vous donnerait des ratios différents. Et sin(x)est leur exemple d'une fonction pure.

Brad
la source
8
Si vous aviez dépassé l'heure, que ferait la fonction?
JB King
1
Je m'attendrais à ce qu'il vous donne l'heure de la journée. (pas la fonction la plus utile). Mais il n’ya pas d’argument, ce qui, je pense, est la racine de la réponse.
Brad
3
Pouvez-vous prédire sa sortie (en fonction des paramètres d'entrée que vous avez fournis)?
Daniel B
1
@DanielB Il n'existe aucun pouvoir prédictif pour le paramètre d'entrée absent / nul. La seule chose que je peux faire est de regarder ma montre (jk mon téléphone portable).
Brad
"Pourquoi l'heure actuelle de la journée n'est-elle pas traitée comme" l'entrée dans la fonction ""? C'est en gros le problème que les monades tentent de résoudre. Les fonctions pures ne peuvent être basées que sur leurs entrées et ne peuvent avoir aucun effet secondaire. Si vous faites de "l'état du monde devant moi" une entrée et que "l'état du monde après moi" fasse partie de la valeur de retour et transmettez ces états mondiaux à travers votre programme, vous pouvez redevenir pur.
Sean McSomething

Réponses:

103

Est-ce parce qu'il n'y a pas d'argument d'entrée formel?

C'est parce que la sortie dépend de quelque chose qui n'est pas une entrée, à savoir l'heure actuelle.

Pourquoi l'heure actuelle de la journée n'est-elle pas traitée comme "l'entrée dans la fonction"

Parce que vous ne l'avez pas passé en paramètre. Si vous le transmettiez en tant que paramètre, la fonction deviendrait une fonction d'identité à la date, ce qui est plutôt inutile. L’intérêt d’une Today()fonction est de produire quelque chose qui dépend d’une valeur externe (heure) qui change constamment.

L'avantage des fonctions pures réside dans le fait que leur comportement est absolument reproductible et déterministe, ce qui facilite l'obtention de preuves formelles et de garanties fermes. Ils font toujours la même chose. Today()est à peu près le contraire: il fait toujours (en tenant compte de la granularité temporelle) quelque chose de différent.

Michael Borgwardt
la source
2
Ainsi, même si le temps de la réalité est en quelque sorte une entrée, car elle n'est pas donnée en entrée et est en dehors du contrôle de la fonction (à la fois en interne pour la fonction et en dehors du contrôle de celui qui appelle Today()) Today()devient impur. La Today()fonction pourrait être un peu un exemple stupide. Une fonction peut être plus appropriée Count(). Donner le même nombre d'éléments à compter Count()retournera toujours le même nombre, mais comme il est hors de portée, Count()il est impur.
Brad
1
@brad c'est un peu une zone grise - il y a un argument réel implicite - le tableau ou la liste. Avec une liste immuable et le même argument à chaque fois, la même valeur sera toujours renvoyée.
Max
34
"le temps de la réalité est en quelque sorte une entrée" - oui; en effet, l'état global est implicitement disponible (c.-à-d. «une sorte d'entrée») pour toutes les fonctions, mais si elles en dépendent pour leur résultat, elles sont impures!
AakashM
4
@ Brad count()sur la plupart des langages de programmation est définitivement pur. Il a une valeur d'entrée explicite: la collection dont vous souhaitez compter le nombre. Ne soyez pas dérouté par une syntaxe telle que myCollection.count(); c'est juste du sucre pour count(myCollection).
Andres F.
Bonne réponse, comme toujours, mais cela ne couvre pas explicitement les variables libres immuables. Ils ne constituent pas une entrée dans la fonction - ils ne sont pas passés en tant que paramètre - mais la fonction en dépend même si elle est toujours transparente au sens référentiel.
24

sin(x)retournera toujours la même valeur, tant qu'elle xreste la même. Today()peut renvoyer des résultats différents dans le temps, car cela dépend de valeurs hors de votre contrôle . Par exemple, si quelque chose au-delà du contrôle de votre programme change le système interne du système $current_datetime pendant que votre programme est en cours d'exécution, les résultats Today()seront soudainement différents.

FrustratedWithFormsDesigner
la source
"retournera toujours une valeur différente" est un peu ... une formulation impure . Wikipedia dit « renvoie le jour de la semaine » , qui signifie que les valeurs obtenues les lundis ne différeront pas
moucheron
7
@gnat: C'est vrai, à moins que quelque chose de externe à votre programme change le calendrier interne de votre ordinateur, de sorte qu'il pense soudainement que c'est jeudi. Ensuite, l'appel Today()reviendrait "jeudi" un lundi.
FrustratedWithFormsDesigner
3
@gnat Eh bien, il ne retournera pas toujours une valeur différente (aucune fonction utile ne le fait). Mais, comme la plupart des fonctions impures, la valeur de retour peut varier même pendant l'exécution d'un programme unique (par exemple, s'il est exécuté pendant la nuit).
3
@delnan: Oui, c'est le fléau des auteurs de scripts de base de données naïfs! : P "Mais comment pourrait-il manquer 300 enregistrements? Le script a bien fonctionné quand je l'ai testé hier matin!"
FrustratedWithFormsDesigner
@delnan c'est sûr. Je ne fait remarquer que l' utilisation toujours dans le libellé initial (corrigé dans la version actuelle de réponse à pouvait ) était quelque peu imprécise
moucheron
13

Today () est une fonction impure car son résultat dépend de quelque chose que vous ne lui donnez pas. spécifiquement, l'heure système actuelle. Par conséquent, son résultat n'est pas déterministe lorsqu'il est basé uniquement sur les entrées fournies lors de l'appel.

Une fonction pure serait int Add(int a, int b) {return a + b;}. La fonction fonctionne uniquement avec ce qui est donné et n'utilise aucune autre donnée d'état externe. Le résultat naturel de cela est que vous pouvez Add(2,2)obtenir 4 à partir de maintenant et jusqu'à la fin des temps. De plus, comme la fonction ne modifie aucun état externe (elle n’a aucun "effet secondaire"), Add () ing 2 et 2 à partir de maintenant jusqu’à la fin des temps ne changera rien d’autre dans le système, sauf si affectez le résultat de la fonction à une variable ou utilisez autrement la valeur pour mettre à jour l'état (qui n'est pas une opération effectuée par la fonction elle-même). Pratiquement toutes les opérations mathématiques classiques sont des fonctions pures et peuvent être implémentées en tant que telles.

Today (), en revanche, peut produire la même valeur lorsqu'il est appelé deux fois de suite, mais pas s'il est appelé à plusieurs reprises pendant plusieurs jours. En effet, cela dépend des données d'état externes qui ne vous sont pas fournies en tant que paramètre de la fonction. Par conséquent, il est impossible, dans les limites du programme, de contrôler le résultat de la fonction Today (). Il produira une valeur donnée un jour donné et ne produira jamais cette valeur un autre jour, à moins que vous ne modifiiez l'horloge système de l'ordinateur sur lequel il est exécuté (changement se produisant généralement en dehors des limites du programme).

Une fonction impure n'est pas nécessairement une mauvaise chose. des fonctions impures sont nécessaires, même dans les langages fonctionnels, pour interagir avec tout ce qui est en dehors du programme, comme des magasins de données, des pipelines de communication, des affichages d'interface utilisateur, des périphériques, etc. Un programme qui ne fait rien de tout cela est un programme cela est fortement limité dans son utilité; J'irais même jusqu'à appeler un tel programme trivial, car sans aucun moyen d'accepter une entrée ou une avenue pour vous informer de sa sortie, il pourrait tout aussi bien ne rien faire. Les programmes écrits dans des langages fonctionnels ne peuvent avoir que les entrées fournies par le moteur d’exécution et produire une sortie rapportée au moteur d’exécution sans méthode impure explicitement définie, mais c’est parce que le moteur d’exécution détourne tous ces détails impurs du travail dans un système informatique imparfait,

C'est simplement une très bonne chose de savoir quelles fonctions que vous utilisez sont pures et lesquelles ne le sont pas, afin que vous puissiez prendre les bonnes décisions quant à la façon dont elles sont utilisées. Les fonctions impures, parce qu'elles font des choses ou dépendent de choses qui ne sont pas apparentes dans leur utilisation, peuvent se comporter de manière imprévisible si elles ne connaissent que leur utilisation. Une connaissance supplémentaire de l'objectif de la fonction, et donc de ce dont elle a besoin ou ce qu'il fait à un état externe, est nécessaire pour placer un système qui l'utilise dans un état cohérent et ainsi obtenir un résultat déterministe.

KeithS
la source
8

Il semble assez évident que cette fonction échoue au premier test de pureté donné au tout début de cette page:

  1. La fonction évalue toujours la même valeur de résultat avec les mêmes valeurs d'argument. La valeur du résultat de la fonction ne peut dépendre d'aucune information cachée ni d'aucun état susceptible de changer au fur et à mesure de l'exécution du programme ou entre différentes exécutions du programme, ni des entrées externes des périphériques d'E / S.

Notez que comme il ne nécessite aucun argument, il n’existe qu’un seul ensemble de valeurs d’argument: l’ensemble vide. Et cette fonction peut et retourne des résultats différents pour la même 'valeur (s) d'argument'.

En outre, la valeur du résultat de la fonction ne dépend « cachée ... état qui peut changer à mesure que l'exécution du programme ». Donc, un autre échec.

AakashM
la source
@ JörgWMittag Je ne sais pas trop où j'affirme qu'une fonction sans argument ne peut pas renvoyer de valeur.
AakashM
PET de cerveau. J'ai lu "il n'y a qu'un seul ensemble possible de valeurs de retour ".
Jörg W Mittag
8

() => 1serait une fonction pure, car elle retourne toujours 1. Today()peut retourner "lundi" ou "mardi" ou presque toute autre valeur.

Une autre façon de penser est que les fonctions pures ne dépendent pas de l'état. Le monde est généralement considéré comme un état. Vous devez connaître l'état de réalité pour savoir quel jour nous sommes.

Cependant, vous n'avez besoin de rien savoir de particulier sur l'état du monde pour savoir ce que sin(x)c'est. Et chaque appel à sin(x)pour une donnée xretournera la même valeur.

Guvante
la source
Wikipedia dit « renvoie le jour de la semaine », ce qui signifie qu'il peut revenir lundi, mardi , etc. , mais pas « 23/01/2013 » ni « 24/01/2013 »
moucheron
7
@gnat: Mise à jour, mais la différence n'était pas vraiment importante.
Guvante
2

Date(timestamp)serait une fonction pure. En raison de son idempotence. Et parce qu'il n'y aurait aucun effet secondaire.

Today()peut varier le résultat en fonction du moment où vous l'appelez. C'est ce qui le rend impur. Ce n'est pas idempotent. Cela n'a cependant aucun effet secondaire, mais cela ne le rend pas pur.

Florian Margaine
la source
2

Voici un petit pseudo-code auquel je pense en discutant de fonctions pures

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

Si cela fonctionne indéfiniment et qu'il ne peut jamais déclencher l'assertion, c'est une fonction pure. Plus encore, si vous avez une fonction qui utilise des arguments, alors une petite modification ....

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

Si vous pouvez utiliser cela après chaque affectation de variable dans votre application et que cela ne change pas les résultats dans votre application, et que l'assertion ne peut jamais échouer, alors c'est une fonction pure.

Drake Clarris
la source
2

Premièrement, il n’existe pas de fonction sans argument (ni de tableau sans index ni de mappe sans clé). C'est la caractéristique qui définit une fonction de mapper une ou plusieurs valeurs d'argument sur une autre valeur.

Par conséquent, todaysoit n'est pas une fonction du tout, donc pas de fonction pure. Ou on peut interpréter la syntaxe

today()

un peu pour que cela signifie

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

En Haskell, par exemple, ceci serait valide:

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

car il y a un type () avec une valeur unique ().

La question est seulement, comment peut todaycalculer le jour de la semaine, si seulement il a ()? Ce n'est tout simplement pas possible sans lire la minuterie du système, directement ou via des fonctions d'assistance impures.

Le minuteur système est un excellent exemple d'état global.

Ingo
la source
1

Le problème today()est que cela peut donner un résultat différent s'il est appelé deux fois ou plus dans une fonction.

Voici un exemple de code pouvant introduire un bogue.

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.....
     }
}

C'est possible dans l'exemple ci-dessus. Que la deuxième ifdéclaration ne sera pas exécutée. Même si le premier l'a fait. Laisser une ressource en mauvais état.

Réactionnel
la source
1

Pour être une fonction pure, fournir les mêmes paramètres doit donner le même résultat à chaque fois.

Chaque fois que nous appelons Today(), nous lui fournissons les mêmes paramètres (aucun) et n'obtenons pas nécessairement le même résultat (lundi, mardi, etc.).

Zantier
la source
4
cela semble simplement répéter le point soulevé et expliqué dans une réponse qui a été publiée il y a environ deux ans. Pas la peine de poser une question vieille de deux ans avec un contenu comme celui-ci
Gnat le
1
Je ne connais pas très bien le fonctionnement de stackexchange, mais je me suis dit que puisque c'était l'une des principales questions, il avait déjà été supprimé. En ce qui concerne le fait de répéter un point, je me souviens d’avoir lu sur la méta qu’il pouvait être utile d’avoir plusieurs réponses similaires. Je pense que le mien est succinct et potentiellement utile.
Zantier