javascript - zufallszahl - math.random() java




Ist eine Funktion, die Math.random() aufruft, rein? (6)

Ist das Folgende eine reine Funktion?

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

Nach meinem Verständnis folgt eine reine Funktion diesen Bedingungen:

  1. Es gibt einen aus den Parametern berechneten Wert zurück
  2. Es macht keine andere Arbeit als den Rückgabewert zu berechnen

Wenn diese Definition korrekt ist, ist meine Funktion eine reine Funktion? Oder ist mein Verständnis dafür, was eine reine Funktion definiert, falsch?


Aus mathematischer Sicht ist Ihre Unterschrift nicht

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

aber

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

wo die environment in der Lage ist, Ergebnisse von Math.random() . Wenn Sie den Zufallswert generieren, wird die Umgebung als Nebeneffekt mutiert, sodass Sie auch eine neue Umgebung zurückgeben, die nicht der ersten entspricht!

Mit anderen Worten, wenn Sie irgendeine Art von Eingabe benötigen, die nicht aus anfänglichen Argumenten (dem Teil <number, number> ) stammt, müssen Sie über eine Ausführungsumgebung verfügen (die in diesem Beispiel den Status für Math bereitstellt). Dasselbe gilt für andere Dinge, die in anderen Antworten erwähnt werden, wie z. B. E / A oder ähnliches.

Als Analogie können Sie auch feststellen, wie objektorientierte Programmierung dargestellt werden kann - wenn wir sagen, z

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

dann benutzen wir eigentlich

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

Das Objekt, dessen Methode aufgerufen wurde, ist Teil der Umgebung. Und warum der SomeClass Teil des Ergebnisses? Weil sich auch der Zustand von something hätte ändern können!


Die einfache Antwort auf Ihre Frage lautet, dass Math.random() die Regel # 2 verletzt.

Viele andere Antworten hier haben darauf hingewiesen, dass das Vorhandensein von Math.random() bedeutet, dass diese Funktion nicht rein ist. Aber ich denke, es lohnt sich zu sagen, warum Math.random() Funktionen verwendet, die es verwenden.

Wie alle Pseudozufallszahlengeneratoren beginnt Math.random() mit einem "Startwert". Dieser Wert wird dann als Ausgangspunkt für eine Kette von Bitmanipulationen auf niedriger Ebene oder für andere Operationen verwendet, die zu einer unvorhersehbaren (aber nicht wirklich zufälligen ) Ausgabe führen.

In JavaScript ist der Prozess implementierungsabhängig, und im Gegensatz zu vielen anderen Sprachen bietet JavaScript keine Möglichkeit, den Startwert auszuwählen :

Die Implementierung wählt den anfänglichen Startwert für den Zufallszahlenerzeugungsalgorithmus aus; Sie kann vom Benutzer nicht ausgewählt oder zurückgesetzt werden.

Aus diesem Grund ist diese Funktion nicht rein: JavaScript verwendet im Wesentlichen einen impliziten Funktionsparameter, über den Sie keine Kontrolle haben. Es liest diesen Parameter aus Daten, die an anderer Stelle berechnet und gespeichert wurden, und verstößt daher gegen Regel 2 in Ihrer Definition.

Wenn Sie dies zu einer reinen Funktion machen möchten, können Sie einen der here beschriebenen alternativen Zufallszahlengeneratoren verwenden. Nennen Sie diesen Generator seedable_random . Es akzeptiert einen Parameter (den Startwert) und gibt eine "zufällige" Zahl zurück. Natürlich ist diese Zahl nicht wirklich zufällig. es wird eindeutig durch den Samen bestimmt. Deshalb ist dies eine reine Funktion. Die Ausgabe von seedable_random ist nur "zufällig" in dem Sinne, dass es schwierig ist, die Ausgabe basierend auf der Eingabe vorherzusagen.

Die reine Version dieser Funktion müsste drei Parameter annehmen:

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

Für jedes gegebene Dreifach von (min, max, seed) Parametern wird immer das gleiche Ergebnis zurückgegeben.

Beachten Sie: Wenn die Ausgabe von seedable_random wirklich zufällig sein soll, müssen Sie einen Weg finden, den Samen zufällig zu sortieren! Und jede Strategie, die Sie angewendet haben, ist unweigerlich nicht rein, da Sie dazu Informationen von einer Quelle außerhalb Ihrer Funktion sammeln müssen. Wie mtraceur und jpmc26 mich erinnern, umfasst dies alle physikalischen Ansätze: Hardware-Zufallszahlengeneratoren , Webcams mit Objektivdeckeln , atmosphärische Geräuschsammler - sogar Lava-Lampen . All dies beinhaltet die Verwendung von Daten, die außerhalb der Funktion berechnet und gespeichert werden.


Nein, das ist es nicht. Sie können das Ergebnis überhaupt nicht herausfinden, sodass dieser Code nicht getestet werden kann. Um diesen Code testbar zu machen, müssen Sie die Komponente extrahieren, die die Zufallszahl generiert:

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

Jetzt können Sie den Generator verspotten und Ihren Code richtig testen:

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

Und in Ihrem "Produktions" -Code:

const result = test(1, 2, Math.random);

Nein, es ist keine reine Funktion, da ihre Ausgabe nicht nur von der bereitgestellten Eingabe abhängt (Math.random () kann jeden Wert ausgeben), während reine Funktionen immer denselben Wert für dieselben Eingaben ausgeben sollten.

Wenn eine Funktion rein ist, ist es sicher, mehrere Anrufe mit denselben Eingängen zu optimieren und das Ergebnis eines früheren Anrufs einfach wiederzuverwenden.

PS Zumindest für mich und für viele andere hat Redux den Begriff der reinen Funktion populär gemacht. Direkt aus den Redux-Dokumenten :

Dinge, die Sie niemals in einem Untersetzungsgetriebe tun sollten:

  • Mutiere seine Argumente;

  • Führen Sie Nebenwirkungen wie API-Aufrufe und Routing-Übergänge durch.

  • Rufen Sie nicht reine Funktionen auf, z. B. Date.now () oder Math.random ().



Würden Sie gut mit den folgenden:

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

äquivalent sein zu

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

?

Sie sehen, die Definition von pure ist eine Funktion, deren Ausgabe sich nur durch ihre Eingaben ändert. Wenn wir sagen, dass JavaScript eine Möglichkeit hätte, eine Funktion zu markieren und diese zu nutzen, könnte der Optimierer den ersten Ausdruck als zweiten Ausdruck umschreiben.

Ich habe praktische Erfahrung damit. SQL Server erlaubte getdate() und newid() in "reinen" Funktionen und das Optimierungsprogramm würde Aufrufe nach Belieben deduplizieren. Manchmal würde dies etwas Dummes tun.





pure-function