2014-12-31 17 views
9

year.hs:Perché l'anno = anno + 1 non riesce con l'overflow dello stack?

year = year + 1 

main = print year 

Questa non è una chiamata ricorsiva coda:

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

Tuttavia runhaskell year.hs non visualizzerà nulla, che indica che eseguito in loop infinito.

Il compilatore Haskell effettua ottimizzazioni anche per chiamate ricorsive non tail?

+2

Guarda l'utilizzo della memoria. Dipende dalle ottimizzazioni, ma questa è una cosa che può accadere. – luqui

+0

Qual è l'output presunto? –

+0

Immagino che il risultato di questo non sia definito. –

risposta

18

A causa della pigrizia (più la limitazione del monomorfismo e del pugnale;). Fondamentalmente, quando si dice

year = year + 1 

e poi valutare year, Haskell consente di risparmiare spazio per il risultato, e poi quando si vede year si cerca di riutilizzare lo stesso risultato. Pertanto, quando year + 1 prova a valutare year, il codice per year non viene effettivamente inserito.

In GHC, per implementare multi-threading & ddagger;, ciò che effettivamente fa è bloccare il thread corrente quando tenta di ottenere il valore di una variabile che è già in fase di valutazione. Quindi, al termine della valutazione, riprende l'esecuzione del thread bloccato. In questo caso, il thread viene bloccato su una valutazione che sta eseguendo, motivo per cui si ottiene un deadlock.

Se invece dici

year() = year() + 1 

poi correre year() dà un overflow dello stack per me.


e pugnale; La restrizione monomorfismo entra in gioco, perché se si aggiunge una firma di tipo

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

il compilatore è perfettamente libero di trattare il Num a dizionario come il parametro (), ottenendo un overflow dello stack. In questo caso non è un problema, ma non memorizzare i risultati intermedi nella cache è un grosso problema nei calcoli reali. In questo caso, sembra che GHC è in realtà mettendo la ricorsione all'interno l'astrazione sopra il dizionario, produrre codice più come

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

che pure non produce un overflow dello stack.


& ddagger; compilazione del codice (con GHC) in modalità single-threaded cede

<<loop>> 

che significa GHC rilevato il ciclo infinito e deciso di lamentarsi.

+0

Per chiarimenti: il tipo di' 'year'' è impostato su' 'Int'', o mi sbaglio? – ThreeFx

+0

@ThreeFx che sembra ragionevole, ma non posso controllare ora. Non importa, però, dato che puoi dare 'year' qualsiasi firma di tipo monomorfico (es. 'Year :: Int',' year :: Integer', 'year :: Float', ecc.) (Purché il tipo ha un'istanza 'Num') senza modificare il comportamento (a patto che' + 'su quel tipo sia rigoroso) –

+1

@ThreeFx È possibile modificare il tipo predefinito di numeri interi e numeri decimali predefiniti, ma il valore predefinito predefinito è (Integer, Double). – AndrewC