Est une fonction qui appelle les mathématiques.random() pur?

est-ce une fonction pure?

function test(min,max) {
   return  Math.random() * (max - min) + min;
}

ma compréhension est qu'une fonction pure suit ces conditions:

  1. il renvoie une valeur calculée à partir des paramètres
  2. Il ne fait pas de travail autre que le calcul de la valeur de retour

si cette définition est correcte, ma fonction est-elle une fonction pure? Ou ma compréhension de ce qui définit une fonction pure incorrect?

107
demandé sur coldspeed 2017-10-31 15:14:43

9 réponses

Non, ça ne l'est pas. Avec la même entrée, cette fonction renvoie des valeurs différentes. Et alors vous ne pouvez pas construire une 'table' qui cartographie les entrées et les sorties.

D'après L'article de Wikipedia pour Pure function :

la fonction évalue toujours la même valeur de résultat donnée la même valeur de l'argument(s). La valeur du résultat de la fonction ne peut dépendre de informations cachées ou état qui peut changer tandis que l'exécution du programme produit, ou entre les différentes exécutions du programme, il ne peut compter sur une entrée externe à partir de périphériques d'e/S

aussi, une autre chose est qu'une fonction pure peut être remplacée par un tableau qui représente la cartographie à partir de l'entrée et la sortie, comme expliqué dans ce fil .

si vous voulez réécrire cette fonction et la changer en une fonction pure, vous devez passer la valeur aléatoire comme un argument trop

function test(random, min, max) {
   return random * (max - min) + min;
}

et puis l'appeler ainsi (exemple, avec 2 et 5 min et max):

test( Math.random(), 2, 5)
178
répondu Christian Benseler 2017-10-31 18:17:53

la réponse simple à votre question Est que Math.random() viole la règle #2.

Beaucoup d'autres réponses ici ont souligné que la présence de Math.random() signifie que cette fonction n'est pas pur. Mais je pense qu'il est intéressant de dire pourquoi Math.random() taints fonctions qui l'utilisent.

comme tous les générateurs de nombres de pseudorandom, Math.random() commence par une valeur de" graine". Il utilise ensuite que valeur comme point de départ d'une chaîne de manipulations de bits de bas niveau ou d'autres opérations qui donnent une sortie imprévisible (mais pas vraiment aléatoire ).

dans JavaScript, le processus impliqué dépend de la mise en œuvre, et contrairement à beaucoup d'autres langues, JavaScript fournit aucune façon de sélectionner la graine :

l'implémentation sélectionne la graine initiale au nombre aléatoire algorithme de génération; il ne peut pas être choisi ou réinitialisé par l'utilisateur.

C'est pourquoi cette fonction n'est pas pure: JavaScript utilise essentiellement un paramètre de fonction implicite sur lequel vous n'avez aucun contrôle. Il lit ce paramètre à partir de données calculées et stockées ailleurs, et viole donc la règle n ° 2 de votre définition.

si vous voulez en faire une fonction pure, vous pouvez utiliser l'un des générateurs de nombres aléatoires alternatifs décrit ici . Appelez ce générateur seedable_random . Il prend un paramètre (la graine) et renvoie un nombre "aléatoire". Bien sûr, ce nombre n'est pas vraiment aléatoire du tout; il est uniquement déterminé par la graine. C'est pourquoi c'est une fonction pure. La sortie de seedable_random n'est "aléatoire" dans le sens que la prévision de la sortie sur l'entrée est difficile.

la version pure de cette fonction devrait prendre trois paramètres:

function test(min, max, seed) {
   return  seedable_random(seed) * (max - min) + min;
}

pour n'importe quel triple de (min, max, seed) paramètres, cela retournera toujours le même résultat.

notez que si vous vouliez que la sortie de seedable_random soit vraiment aléatoire, vous auriez besoin de trouver un moyen de randomiser la graine! Et quelle que soit la stratégie que vous utilisiez, elle serait inévitablement Non pure, parce qu'elle vous exigerait de recueillir des informations à partir d'une source extérieure à votre fonction. Comme mtraceur et jpmc26 rappelle-moi, cela inclut toutes les physique des approches: matériel générateurs de nombres aléatoires , webcams avec bouchon d'objectif , bruit atmosphérique collectionneurs -- même lampes lava . Tout cela implique l'utilisation de données calculées et stockées en dehors de la fonction.

48
répondu senderle 2017-11-02 12:55:25

une fonction pure est une fonction dont la valeur de retour n'est déterminée que par ses valeurs d'entrée, sans effets secondaires observables

en utilisant les mathématiques.aléatoire, vous déterminez sa valeur par quelque chose d'autre que des valeurs d'entrée. Ce n'est pas une fonction pure.

source

38
répondu TKoL 2017-10-31 13:50:55

non, ce n'est pas une fonction pure parce que sa sortie ne dépend pas seulement de l'entrée fournie (Math.random() peut afficher n'importe quelle valeur), tandis que les fonctions pures devrait toujours la même valeur pour les mêmes entrées.

si une fonction est pure, il est sûr d'optimiser les appels multiples avec les mêmes entrées et juste réutiliser le résultat d'un appel plus tôt.

P. S pour moi au moins et pour beaucoup d'autres, redux fait le terme pure fonction populaire. Directement à partir de la redux docs :

choses qu'il ne faut jamais faire à l'intérieur d'un réducteur:

  • Muter ses arguments;

  • effectuer des effets secondaires comme des appels API et des transitions de routage;

  • appeler fonctions non pures, p.ex. Date.maintenant() ou les maths.aléatoire.)(

25
répondu Shubhnik Singh 2017-11-05 10:58:50

d'un point de vue mathématique, votre signature n'est pas

test: <number, number> -> <number>

mais

test: <environment, number, number> -> <environment, number>

où le environment est capable de fournir les résultats de Math.random() . Et en fait générer la valeur aléatoire mute l'environnement comme un effet secondaire, donc vous retournez aussi un nouvel environnement, qui n'est pas égal au premier!

En d'autres termes, si vous avez besoin de tout type d'entrée qui ne viennent pas de arguments initiaux (la partie <number, number> ), alors vous devez être fourni avec l'environnement d'exécution (qui dans cet exemple fournit l'État pour Math ). Il en va de même pour d'autres éléments mentionnés dans d'autres réponses, comme les E/S ou autres.


par analogie, vous pouvez également remarquer comment la programmation orientée objet peut être représentée - si nous disons, par exemple

SomeClass something
T result = something.foo(x, y)

alors en fait nous utilisons

foo: <something: SomeClass, x: Object, y: Object> -> <SomeClass, T>

avec l'objet dont la méthode est invoquée faisant partie de l'environnement. Et pourquoi la partie SomeClass du résultat? Parce que l'état de something aurait pu changer aussi bien!

20
répondu Adam Kotwasinski 2017-11-02 16:42:16

fonctions pures toujours retourner la même valeur pour la même entrée. Les fonctions pures sont prévisibles et sont transparentes référentielles ce qui signifie que nous pouvons remplacer l'appel de fonction par la sortie retournée et cela ne changera pas le fonctionnement du programme.

https://github.com/MostlyAdequate/mostly-adequate-guide/blob/master/ch3.md

11
répondu Rishabh Mishra 2017-12-27 17:44:38

en plus des autres réponses qui soulignent à juste titre que cette fonction n'est pas déterministe, elle a aussi un effet secondaire: elle provoquera des appels futurs à math.random() pour retourner une réponse différente. Et un générateur de nombres aléatoires qui n'a pas cette propriété effectuera généralement une sorte d'E/S, comme lire à partir d'un périphérique aléatoire fourni par L'OS. L'un ou l'autre est verboten pour une fonction pure.

9
répondu Davislor 2017-11-01 04:25:51

Non, ça ne l'est pas. Vous ne pouvez pas comprendre le résultat du tout, donc ce morceau de code ne peut pas être testé. Pour rendre ce code testable, vous devez extraire le composant qui génère le nombre aléatoire:

function test(min, max, generator) {
  return  generator() * (max - min) + min;
}

maintenant, vous pouvez vous moquer du générateur et tester votre code correctement:

const result = test(1, 2, () => 3);
result == 4 //always true

et dans votre code de "production":

const result = test(1, 2, Math.random);
7
répondu Héctor 2017-10-31 12:27:24

seriez-vous d'accord avec ce qui suit:

return ("" + test(0,1)) + test(0,1);

être l'équivalent de

var temp = test(0, 1);
return ("" + temp) + temp;

?

vous voyez, la définition de pure est une fonction dont la sortie ne change pas avec autre chose que ses entrées. Si nous disons que JavaScript a un moyen de marquer une fonction pure et de tirer avantage de cela, l'optimiseur serait autorisé à réécrire la première expression comme la seconde.

j'ai expérience pratique avec cette. SQL server a permis getdate() et newid() dans les fonctions" pure " et l'optimiseur serait dedupe appels à volonté. Parfois, ça faisait quelque chose de stupide.

2
répondu Joshua 2017-11-03 01:59:17