2014-12-31 2 views
9

year.hs:Warum nicht Jahr = Jahr + 1 mit Stack-Überlauf fehlschlagen?

year = year + 1 

main = print year 

Dieser rekursive Aufruf kein Schwanz ist:

year = year + 1 
year = (year + 1) + 1 
year = ((year + 1) + 1) + 1 
... 

jedoch runhaskell year.hs nichts ausgibt, die, dass es in Endlosschleife laufen anzeigt.

Macht der Haskell-Compiler Optimierungen auch für nicht-tail-rekursive Aufrufe?

+2

Beobachten Sie Ihre Speichernutzung. Es hängt von den Optimierungen ab, aber das ist eine Sache, die passieren kann. – luqui

+0

Was ist die Ausgabe? –

+0

Ich würde davon ausgehen, dass das Ergebnis nicht definiert ist. –

Antwort

18

Wegen der Faulheit (plus die Monomorphie Einschränkung & Dolch;). Grundsätzlich, wenn Sie sagen,

year = year + 1 

und dann bewerten year, spart Haskell Platz für das Ergebnis, und dann, wenn es year sieht versucht es das gleiche Ergebnis wiederverwenden. Wenn year + 1 versucht, auszuwerten, wird der Code für nicht tatsächlich eingegeben.

In GHC zum Implementieren von Multi-Threading & ddagger; blockiert der aktuelle Thread den aktuellen Thread, wenn er versucht, den Wert einer Variablen zu erhalten, die bereits ausgewertet wird. Wenn die Auswertung beendet ist, wird die Ausführung des blockierten Threads fortgesetzt. In diesem Fall wird der Thread bei einer von ihm selbst durchgeführten Auswertung blockiert, weshalb Sie einen Deadlock erhalten.

Wenn Sie stattdessen sagen

year() = year() + 1 

dann year() läuft einen Stapelüberlauf für mich nicht geben.


& dolch; Die Monomorphie Einschränkung kommt ins Spiel, denn wenn man eine Art Signatur hinzufügen

year :: Num a => a 
year = year + 1 

die Compiler vollkommen frei ist, das Num a Wörterbuch wie die () Parameter zu behandeln, einen Stapelüberlauf führt. In diesem Fall ist das nicht wirklich ein Problem, aber Zwischenergebnisse nicht zu cachen ist ein großes Problem in realen Berechnungen. In diesem Fall sieht es aus wie GHC tatsächlich die Rekursion innerhalb die Abstraktion über das Wörterbuch setzen, die Herstellung von Code mehr wie

year() = let y = y + 1 in y 

die auch nicht einen Stapelüberlauf erzeugt.


& ddagger; Kompilieren des Codes (mit GHC) im Single-Thread-Modus ergibt

<<loop>> 

was bedeutet, GHC die unendliche Schleife erfaßt und entschieden, darüber zu beschweren.

+0

Zur Verdeutlichung: Der Typ von' '' '' '' '' '' Default, oder irre ich mich? – ThreeFx

+0

@ThreeFx das klingt vernünftig, aber ich kann jetzt nicht überprüfen. Es ist jedoch egal, weil Sie Jahr eine monomorphe Typ-Signatur geben können (zB Jahr :: Int, Jahr :: Ganzzahl, Jahr :: Float, usw.) (solange der Typ hat eine 'Num'-Instanz, ohne das Verhalten zu ändern (solange' + 'für diesen Typ strikt ist) –

+1

@ThreeFx Sie können den Typ für Ganzzahl- und Dezimalzahlenliterale ändern, aber der Standardwert ist (Ganzzahl, doppelt). – AndrewC