2014-12-31 16 views
9

year.hs:Dlaczego rok = rok + 1 nie działa z przepełnieniem stosu?

year = year + 1 

main = print year 

nie jest ogon wywołanie rekurencyjne:

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

Jednakże runhaskell year.hs nie emituje nic, co oznacza, że ​​jest prowadzony w nieskończonej pętli.

Czy kompilator Haskell dokonuje optymalizacji nawet dla nierekultywujących wywołań rekurencyjnych?

+2

Obserwuj użycie pamięci. To zależy od optymalizacji, ale to jedna rzecz, która może się zdarzyć. – luqui

+0

Jakie są rzekome wyniki? –

+0

Zakładam, że wynik tego jest nieokreślony. –

Odpowiedz

18

Z powodu lenistwa (plus ograniczenie monomorfizmu & sztylet;). Zasadniczo, gdy mówisz

year = year + 1 

a następnie ocenić year, Haskell oszczędność miejsca dla wyniku, a następnie, gdy widzi year próbuje ponownie wykorzystać ten sam rezultat. Więc kiedy year + 1 próbuje ocenić year, kod dla year nie jest faktycznie wprowadzany.

W GHC, do implementacji wielowątkowości & ddagger;, to, co faktycznie robi, blokuje bieżący wątek, gdy próbuje uzyskać wartość zmiennej, która jest już oceniana. Następnie, po zakończeniu oceny, wznawia wykonywanie zablokowanego wątku. W tym przypadku wątek jest blokowany podczas oceny, którą sam wykonuje, dlatego pojawia się zakleszczenie.

Jeśli zamiast powiedzieć

year() = year() + 1 

następnie uruchomiony year() daje przepełnienie stosu dla mnie.


& sztylet; Ograniczenie monomorfizm wchodzi w grę, ponieważ jeśli dodać podpis TYP

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

kompilator jest całkowicie wolny w leczeniu słownika takiego parametru ()Num a, otrzymując przepełnienie stosu. W tym przypadku nie stanowi to problemu, ale nie buforowanie wyników pośrednich jest dużym problemem w rzeczywistych obliczeniach. W tym przypadku wygląda na to GHC jest faktycznie oddanie rekursji wewnątrz abstrakcję nad słowniku, produkując kod bardziej jak

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

który również nie powoduje przepełnienie stosu.


& ddagger; kompilacji kodu (z GHC) w trybie jednowątkowy daje

<<loop>> 

co oznacza GHC wykryte nieskończoną pętlę, i postanowił skarżą się na niego.

+0

Dla wyjaśnienia: Typ' 'year'' domyślnie jest ustawiony na' 'Int'', czy też się mylę? – ThreeFx

+0

@ ThreeFx, który brzmi rozsądnie, ale nie mogę teraz sprawdzić. Nie ma to jednak znaczenia, ponieważ możesz nadać 'roku' dowolnemu podpisowi typu monomorficznego (np.' Year :: Int', 'year :: Integer',' year :: Float', itd.) (Tak długo jak typ ma instancję 'Num') bez zmiany zachowania (o ile typ' + 'jest ścisły) –

+1

@ThreeFx Możesz zmienić typ domyślny dla liczb całkowitych i dziesiętnych, ale domyślnym ustawieniem domyślnym jest (Integer, Double). – AndrewC