Auswertung der Nullfunktionen in Haskell

7

Angenommen, Sie haben eine nullary-Funktion in haskell, die mehrmals im Code verwendet wird. Wird es immer nur einmal ausgewertet? Ich habe den folgenden Code bereits getestet:

%Vor%

Wenn ich Test 10 anrufe, schreibt er einmal "Hallo", so dass das Ergebnis der Funktion nach der ersten Auswertung gespeichert wird. Meine Frage ist, ist es garantiert? Bekomme ich das gleiche Ergebnis über verschiedene Compiler hinweg?

Bearbeiten Der Grund für die Verwendung von unsafePerformIO besteht darin, zu überprüfen, ob sayHello mehr als einmal ausgewertet wird. Ich benutze das nicht in meinem Programm. Normalerweise erwarte ich, dass sayHello bei jeder Auswertung genau das gleiche Ergebnis hat. Aber es ist eine zeitaufwendige Operation, also wollte ich wissen, ob auf diese Weise zugegriffen werden kann, oder ob es als Argument übergeben werden soll, wo immer es benötigt wird, um sicherzustellen, dass es nicht mehrfach ausgewertet wird, zB:

%Vor%

Laut den Antworten sollte dies verwendet werden.

    
Firielentul 13.06.2013, 03:13
quelle

3 Antworten

17

Es gibt keine so genannte Nullfunktion. Eine Funktion in Haskell hat genau ein Argument und hat immer den Typ ... -> ... . sayHello ist ein Wert - ein Int - aber keine Funktion. Weitere Informationen finden Sie in diesem Artikel .

On Garantien: Nein, Sie bekommen wirklich keine Garantien. Der Haskell-Bericht gibt an, dass Haskell nicht strikt ist - Sie wissen also, auf welchen Wert sich die Dinge letztendlich reduzieren werden - aber keine bestimmte Bewertungsstrategie. Die Evaluierungsstrategie, die GHC im Allgemeinen verwendet, ist Lazy Evaluation , dh nicht-strikte Bewertung mit Teilen, aber es gibt keine starken Garantien darüber hinaus - der Optimierer könnte Ihren Code herum mischen, so dass Dinge mehr als einmal ausgewertet werden.

Es gibt auch verschiedene Ausnahmen - zum Beispiel ist foo :: Num a => a polymorph, also wird es wahrscheinlich nicht geteilt (es wird zu einer tatsächlichen Funktion kompiliert). Manchmal wird ein reiner Wert von mehr als einem Thread gleichzeitig ausgewertet (was in diesem Fall nicht der Fall ist, weil unsafePerformIO explizit noDuplicate verwendet, um dies zu vermeiden). Also, wenn Sie programmieren, können Sie im Allgemeinen Faulheit erwarten, aber wenn Sie irgendeine Art von Garantien wollen, müssen Sie sehr vorsichtig sein. Der Bericht selbst gibt Ihnen nicht wirklich Auskunft über wie Ihr Programm bewertet wird.

unsafePerformIO gibt Ihnen selbstverständlich noch weniger Garantien. Es gibt einen Grund, warum es "unsicher" heißt.

    
shachaf 13.06.2013, 03:37
quelle
5

Top-Level-Funktionen ohne Argumente wie sayHello heißen Constant Applicative Forms und sind immer Memoisiert (zumindest in GHC - siehe Ссылка ). Sie müssten auf Tricks wie das Übergeben von Dummy-Argumenten und das Deaktivieren von Optimierungen auf nicht zugreifen, um eine CAF global zu teilen.

Bearbeiten : Zitat aus dem obigen Link -

  

Haskell ist eine faule Sprache, und bestimmte Ausdrücke sind immer nur   einmal bewertet. Zum Beispiel, wenn wir schreiben:    x = nfib 25 then x wird nur einmal ausgewertet (wenn überhaupt), und   Nachfolgende Anforderungen für x sehen sofort das zwischengespeicherte Ergebnis.   Die Definition x wird CAF (Constant Applicative Form) genannt, weil   Es hat keine Argumente.

    
Anupam Jain 13.06.2013 04:31
quelle
1

Wenn Sie möchten, dass "Hallo" n mal gedruckt wird, müssen Sie unsafePermformIO entfernen, damit die Laufzeitumgebung weiß, dass wiederholte Aufrufe von putStr nicht optimiert werden können. Ich bin nicht klar, ob Sie die Liste von int zurückgeben wollen, also habe ich zwei Testversionen geschrieben, von denen eine zurückgibt (), eine [Int].

%Vor%     
ja. 13.06.2013 05:48
quelle