Warum ist Today () ein Beispiel für eine unreine Funktion?

38

Wenn man so etwas wie diesen Wikipedia-Artikel über "reine Funktionen" liest, scheinen sie Today()als Beispiel für eine unreine Funktion aufzulisten, aber es scheint mir ziemlich rein. Liegt es daran, dass es kein formales Eingabeargument gibt? Warum wird die aktuelle Uhrzeit nicht als "Eingabe für die Funktion" behandelt, wenn Sie dieselbe Eingabe vorgenommen haben, dh today()zweimal zur selben Zeit ausgeführt haben oder die Zeit zurückgereist sind, um sie erneut auszuführen (möglicherweise eine Hypothese: )), wäre die Ausgabe zur gleichen Zeit. Today()gibt dir niemals eine Zufallszahl. es gibt dir immer die Tageszeit.

Der Wikipedia-Artikel sagt, dass "unterschiedliche Zeiten unterschiedliche Ergebnisse liefern", aber das heißt, dass "für unterschiedliche Zeiten" x sin(x)unterschiedliche Verhältnisse ergeben. Und sin(x)ist ihr Beispiel für eine reine Funktion.

Brad
quelle
8
Wenn Sie die Tageszeit überschritten haben, was würde die Funktion tun?
JB King
1
Ich würde erwarten, dass es Ihnen die Tageszeit gibt. (nicht die nützlichste Funktion). Aber es gibt keine Argumente, von denen ich denke, dass sie die Wurzel der Antwort sind.
Brad
3
Können Sie die Ausgabe vorhersagen (basierend auf den von Ihnen angegebenen Eingabeparametern)?
Daniel B
1
@DanielB Es gibt keine Vorhersagekraft für den Fehlen / Null-Eingabeparameter, der sich herausstellt. Ich kann nur auf meine Armbanduhr schauen (auf mein Handy).
Brad
"Warum wird die aktuelle Uhrzeit nicht als" Eingabe für die Funktion "behandelt?" Dies ist im Grunde das Problem, das Monaden zu lösen versuchen. Reine Funktionen können nur auf ihren Eingaben basieren und dürfen keine Nebenwirkungen haben. Wenn Sie den "Zustand der Welt vor mir" zu einem Input und den "Zustand der Welt nach mir" zu einem Teil des Rückgabewerts machen und diese Weltzustände durch Ihr Programm leiten, können Sie wieder rein sein.
Sean McSomething

Antworten:

103

Liegt es daran, dass es kein formales Eingabeargument gibt?

Dies liegt daran, dass die Ausgabe von etwas abhängt, das keine Eingabe ist, nämlich der aktuellen Uhrzeit.

Warum wird die aktuelle Uhrzeit nicht als "Eingabe für die Funktion" behandelt?

Weil Sie es nicht als Parameter übergeben haben. Wenn Sie es als Parameter übergeben, wird die Funktion bei Datumsangaben zu einer Identitätsfunktion, was ziemlich nutzlos ist. Der springende Punkt einer Today()Funktion ist, etwas auszugeben, das von einem externen und sich ständig ändernden Wert (Zeit) abhängt.

Der Vorteil von reinen Funktionen ist, dass ihr Verhalten absolut reproduzierbar und deterministisch ist, was formale Beweise und strenge Garantien erleichtert. Sie machen immer das Gleiche. Today()ist so ziemlich das Gegenteil: es macht immer (unter Berücksichtigung der Zeitgranularität) etwas anderes.

Michael Borgwardt
quelle
2
Auch wenn die Zeit der Realität eine Art Eingabe ist, wird sie unrein , da sie nicht als Eingabe gegeben wird und außerhalb der Kontrolle der Funktion (sowohl innerhalb der Funktion als auch außerhalb der Kontrolle desjenigen, der anruft Today()) liegt Today(). Die Today()Funktion könnte ein bisschen albern sein. Geeigneter könnte eine Count()Funktion sein. Wenn die Anzahl der zu zählenden Elemente gleich ist, Count()wird immer die gleiche Anzahl zurückgegeben, da dies jedoch außerhalb des Geltungsbereichs liegt Count(), ist dies unrein.
Brad
1
@brad ist eine Art Grauzone - es gibt ein implizites tatsächliches Argument - das Array oder die Liste. Bei einer unveränderlichen Liste und dem gleichen Argument wird immer der gleiche Wert zurückgegeben.
Max
34
"Die Zeit der Realität ist eine Art Input" - ja; in der Tat ist der globale Zustand implizit für alle Funktionen verfügbar (dh "eine Art Eingabe"), aber wenn sie für ihr Ergebnis davon abhängen, sind sie unrein!
AakashM
4
@ Brad count()auf den meisten Programmiersprachen ist definitiv rein. Es hat einen expliziten Eingabewert: die Sammlung, deren Anzahl Sie möchten. Lassen Sie sich nicht durch eine Syntax wie verwirren myCollection.count(); das ist nur zucker für count(myCollection).
Andres F.
Gute Antwort wie immer, aber es werden nicht explizit unveränderliche freie Variablen behandelt. Sie sind keine Eingabe für die Funktion - nicht als Parameter übergeben -, aber die Funktion hängt von ihnen ab, auch wenn sie noch referenziell transparent ist.
24

sin(x)gibt immer den gleichen Wert zurück, solange er gleich xbleibt. Today()kann im Laufe der Zeit unterschiedliche Ergebnisse liefern, da dies von Werten abhängt, die außerhalb Ihrer Kontrolle liegen . Wenn zum Beispiel etwas außerhalb der Kontrolle Ihres Programms das interne System ändert, $current_datetime während Ihr Programm ausgeführt wird, Today()ergeben sich plötzlich andere Ergebnisse.

FrustratedWithFormsDesigner
quelle
"wird immer einen anderen Wert zurückgeben" ist eine etwas ... unreine Formulierung. Wikipedia sagt : „Gibt den aktuellen Tag der Woche“ , was bedeutet , dass montags erhaltenen Werte werden nicht abweichen
gnat
7
@gnat: Stimmt, es sei denn, etwas außerhalb Ihres Programms hat den internen Kalender Ihres Computers so geändert, dass plötzlich angenommen wurde, es sei Donnerstag. Dann Today()würde ein Anruf an einem Montag "Donnerstag" zurückgeben.
FrustratedWithFormsDesigner
3
@gnat Nun, es wird nicht immer ein anderer Wert zurückgegeben (es gibt kaum eine nützliche Funktion, die dies tut). Wie bei den meisten unreinen Funktionen kann der Rückgabewert jedoch auch während der Ausführung eines einzelnen Programms variieren (z. B. wenn es über Nacht ausgeführt wird).
3
@delnan: Ja, das ist der Fluch naiver Datenbankskriptautoren! : P "Aber wie konnte es 300 Datensätze verfehlen? Das Skript hat gut funktioniert, als ich es gestern Morgen getestet habe!"
FrustratedWithFormsDesigner
@delnan das ist sicher. Ich habe nur darauf hingewiesen, dass die Verwendung immer im ursprünglichen Wortlaut (korrigiert in der aktuellen Version Antwort auf könnte ) etwas ungenau war
gnat
13

Today () ist eine unreine Funktion, weil ihr Ergebnis von etwas abhängt, das Sie ihm nicht geben. Insbesondere die aktuelle Systemzeit. Daher ist das Ergebnis nicht deterministisch, wenn es nur auf den beim Aufruf bereitgestellten Eingaben basiert.

Eine reine Funktion wäre int Add(int a, int b) {return a + b;}. Die Funktion arbeitet ausschließlich mit dem, was sie enthält, und verwendet keine anderen externen Zustandsdaten. Das natürliche Ergebnis davon ist, dass Sie Add(2,2)von jetzt an bis zum Ende der Zeit 4 bekommen können. Da die Funktion keinen externen Status ändert (es gibt keine "Nebenwirkungen"), ändert das Hinzufügen von 2 und 2 von jetzt an bis zum Ende der Zeit nichts anderes im System, es sei denn, Sie ändern dies Weisen Sie das Ergebnis der Funktion einer Variablen zu, oder verwenden Sie den Wert auf andere Weise, um den Status zu aktualisieren (was keine von der Funktion selbst ausgeführte Operation ist). Praktisch alle klassischen mathematischen Operationen sind reine Funktionen und können als solche implementiert werden.

Auf der anderen Seite kann Today () denselben Wert erzeugen, wenn es zweimal hintereinander aufgerufen wird, aber nicht, wenn es mehrere Tage lang wiederholt aufgerufen wird. Dies liegt daran, dass es von externen Statusdaten abhängt, die Sie nicht als Parameter für die Funktion angegeben haben. Infolgedessen ist es innerhalb der Programmgrenzen unmöglich, das Ergebnis der Today () - Funktion zu steuern. Es wird an einem bestimmten Tag einen bestimmten Wert und an keinem anderen Tag einen bestimmten Wert erzeugen, es sei denn, Sie ändern die Systemuhr des Computers, auf dem es ausgeführt wird (eine Änderung, die im Allgemeinen außerhalb der Programmgrenzen auftritt).

Eine unreine Funktion ist nicht unbedingt eine schlechte Sache; Selbst in funktionalen Sprachen sind unreine Funktionen erforderlich, um mit etwas außerhalb der Programmgrenzen zu interagieren, z. B. mit Datenspeichern, Kommunikations-Pipelines, Benutzeroberflächenanzeigen, Peripheriegeräten usw. Ein Programm, das keine dieser Funktionen ausführt, ist ein Programm das ist in seiner Nützlichkeit scharf begrenzt; Ich würde sogar so weit gehen, ein solches Programm als trivial zu bezeichnen, da es, ohne irgendwelche Mittel, um Eingaben zu akzeptieren oder um Sie über seine Ausgabe zu informieren, genauso gut nichts tun könnte. In funktionalen Sprachen geschriebene Programme können nur die von der Laufzeit bereitgestellten Eingaben haben und eine Ausgabe erzeugen, die der Laufzeit ohne explizit definierte unreine Methoden gemeldet wird. Dies liegt jedoch daran, dass die Laufzeit all diese unreinen Details der Arbeit in einem unvollkommenen Computersystem abstrahiert.

Es ist einfach eine sehr gute Sache zu wissen, welche der von Ihnen verwendeten Funktionen rein sind und welche nicht, damit Sie gute Entscheidungen darüber treffen können, wie sie verwendet werden. Unreine Funktionen können sich nur bei Kenntnis der Verwendung unvorhersehbar verhalten, weil sie Dinge tun oder von Dingen abhängig sind, die aus ihrer Verwendung nicht ersichtlich sind. Weitere Kenntnisse über den Zweck der Funktion und damit darüber, was sie von einem externen Zustand benötigt oder für einen externen Zustand tut, sind erforderlich, um ein System, das sie verwendet, in einen konsistenten Zustand zu versetzen und damit ein deterministisches Ergebnis zu erwarten.

KeithS
quelle
8

Es scheint ziemlich offensichtlich, dass diese Funktion den ersten Reinheitstest, der zu Beginn dieser Seite angegeben wurde, nicht besteht:

  1. Die Funktion wertet bei gleichen Argumentwerten immer den gleichen Ergebniswert aus. Der Funktionsergebniswert kann weder von verborgenen Informationen oder Zuständen abhängen, die sich während der Programmausführung oder zwischen verschiedenen Programmausführungen ändern, noch von externen Eingaben von E / A-Geräten.

Beachten Sie, dass es nur eine mögliche Menge von Argumentwerten gibt - die leere Menge, da keine Argumente akzeptiert werden. Und diese Funktion kann und kann unterschiedliche Ergebnisse für den gleichen 'Argumentwert ( die gleichen Argumentwerte)' zurückgeben.

Darüber hinaus ist die Funktion Ergebniswert ist , hängt von „versteckt ... Zustand, wie geht die Programmausführung ändern können“. Also noch ein Misserfolg.

AakashM
quelle
@ JörgWMittag Ich bin mir nicht sicher, wo ich behaupte, dass eine Funktion ohne Argumente keinen Wert zurückgeben kann.
AakashM
Gehirnfurz. Ich las "es gibt nur einen möglichen Satz von Rückgabewerten ".
Jörg W Mittag
8

() => 1wäre eine reine Funktion, da sie immer 1. Today()"Montag" oder "Dienstag" oder fast jeden anderen Wert zurückgeben kann.

Eine andere Sichtweise ist, dass reine Funktionen nicht vom Zustand abhängen. Die Welt wird typischerweise als Staat betrachtet. Sie müssen den Zustand der Realität kennen, um zu wissen, welcher Tag heute ist.

Sie müssen jedoch nichts Besonderes über den Zustand der Welt wissen, um zu wissen, was sin(x)ist. Und jeder Aufruf an sin(x)für eine gegebene xwird den gleichen Wert zurückgeben.

Guvante
quelle
Wikipedia sagt : „Gibt den aktuellen Tag der Woche“, was bedeutet , es Montag zurückkehren kann, Dienstag usw. , aber nicht „2013.01.23“ noch „2013.01.24“
gnat
7
@gnat: Aktualisiert, aber der Unterschied war nicht wirklich wesentlich.
Guvante
2

Date(timestamp)wäre eine reine funktion. Wegen seiner Idempotenz. Und weil es keine Nebenwirkungen geben würde.

Today()Das Ergebnis kann variieren, je nachdem, wann Sie es aufrufen. Das macht es unrein. Es ist nicht idempotent. Es hat zwar keine Nebenwirkungen, aber das macht es nicht rein.

Florian Margaine
quelle
2

Hier ist ein kleiner Pseudocode, an den ich denke, wenn ich über reine Funktionen spreche

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

Wenn das auf unbestimmte Zeit läuft und das Assert niemals auslösen kann, ist es eine reine Funktion. Mehr so, wenn Sie eine Funktion haben, die Argumente verwendet, dann eine kleine Änderung ....

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

Wenn Sie dies nach jeder Variablenzuweisung in Ihrer App verwenden können und die Ergebnisse in Ihrer App nicht geändert werden und die Behauptung niemals fehlschlagen kann, ist dies eine reine Funktion.

Drake Clarris
quelle
2

Erstens gibt es keine Funktion ohne Argument (oder ein Array ohne Indizes oder eine Map ohne Schlüssel). Es ist das definierende Merkmal einer Funktion, einen oder mehrere Argumentwerte einem anderen Wert zuzuordnen.

Also todayist entweder gar keine Funktion, also keine reine Funktion. Oder wir interpretieren die Syntax

today()

ein bisschen so, dass es bedeutet

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

In Haskell wäre dies beispielsweise gültig:

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

weil es einen Typ () mit einem einzelnen Wert () gibt.

Die Frage ist nur, wie todayman den Wochentag berechnen kann , wenn es nur () hat. Es ist einfach nicht möglich, ohne den Systemtimer direkt oder über unreine Helferfunktionen auszulesen.

Der Systemtimer ist ein hervorragendes Beispiel für den globalen Zustand.

Ingo
quelle
1

Das Problem dabei today()ist, dass es zu einem anderen Ergebnis kommen kann, wenn es in einer Funktion zweimal oder öfter aufgerufen wird.

Hier ist ein Codebeispiel, das einen Fehler verursachen könnte.

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

Dies ist im obigen Beispiel möglich. Dass die zweite ifAnweisung nicht ausgeführt wird. Auch wenn es der erste tat. Eine Ressource in einem schlechten Zustand belassen.

Reactgular
quelle
1

Um eine reine Funktion zu sein, müssen dieselben Parameter jedes Mal dasselbe Ergebnis liefern.

Jedes Mal Today(), wenn wir anrufen , geben wir die gleichen Parameter an (keine) und erhalten dennoch nicht unbedingt das gleiche Ergebnis (Montag, Dienstag usw.).

Zantier
quelle
4
Dies scheint lediglich den Punkt zu wiederholen, der in einer Top-Antwort , die vor ungefähr zwei Jahren veröffentlicht wurde, gemacht und erklärt wurde. Es lohnt sich kaum, eine zwei Jahre alte Frage mit
solchen
1
Ich bin mit der Funktionsweise des Stapelaustauschs nicht allzu vertraut, aber ich stellte fest, dass er bereits gestoßen wurde, da dies häufig gestritten wurde. Was das Wiederholen angeht, erinnere ich mich, dass ich in Meta gelesen habe, dass es hilfreich sein kann, mehrere ähnliche Antworten zu haben. Meiner Meinung nach ist meiner prägnant und potenziell hilfreich.
Zantier