2016-01-31 18 views
10

Pełna lenistwo został repeatedly demonstrated do cause space leaks.Dlaczego pełne lenistwo jest domyślną optymalizacją?

Dlaczego pełne lenistwo zaczyna się od -O? Nie przekonuje mnie rozumowanie w SPJ's The Implementation of Functional Programming Languages. Twierdzenie, że w

f = \y -> y + sqrt 4 

sqrt 4 niepotrzebnie powtarza się za każdym razem f jest wpisany więc powinniśmy unosić go poza lambda. Zgadzam się w małych, ale ponieważ widzieliśmy, jakie problemy powoduje ta transformacja w dużych nie sądzę, że warto. Wydaje mi się, że korzyści płynące z tej transformacji można uzyskać jednostronnie ** tylko z lokalnymi zmianami kodu i programiści, którzy chcą ją wdrożyć ręcznie.

Czy możesz mnie przekonać inaczej? Czy naprawdę jest przydatna full-laziness? Będę szczególnie przekonany, jeśli potrafisz podać przykłady, które ręcznie wdrażać wymagają wielostronnej współpracy lub nielokalnych transformacji.

** przeciwieństwie optymalizacje jak inline i fusion strumień, który do realizacji przez strony wymaga wielostronnej współpracy między modułami i kodu nielokalnego zmienia

+1

Transformacja typu "full-laziness" w rzeczywistości nie ma nic wspólnego z porządkiem oceny. –

Odpowiedz

7

Istnieje przynajmniej jeden wspólny przypadku, gdy pełna lenistwo jest „bezpieczny” i optymalizacja .

g :: Int -> Int 
g z = f (z+1) 
    where f 0 = 0 
     f y = 1 + f (y-1) 

naprawdę to oznacza g = \z -> let {f = ...} in f (z+1) i skompilowany w ten sposób, będzie przeznaczyć zamknięcie do f przed nazywając ją. Oczywiście, że to głupie, a kompilator powinien przekształcić program w

g_f 0 = 0 
g_f y = 1 + g_f (y-1) 
g z = g_f (z+1) 

gdzie nie jest potrzebny przydział zadzwonić g_f. Na szczęście pełna transformacja lenistwa właśnie to robi.

Oczywiście programiści mogli powstrzymać się od podejmowania tych lokalnych definicji, które nie zależą od argumentów funkcji najwyższego poziomu, ale takie definicje są ogólnie uważane za dobry styl ...

Inny przykład:

h :: [Int] -> [Int] 
h xs = map (+1) xs 

W tym przypadku można po prostu zmniejszyć eta, ale zwykle nie można zmniejszyć wartości. A nazwanie funkcji jest bardzo brzydkie.

+0

Dzięki za przykład. To samo miałoby zastosowanie, gdyby "f" było "Int", zwłaszcza jeśli obliczenie jest kosztowne. Jednak myślałem o mniej gwałtownej transformacji: 'g = let {f = ...} in \ z -> f (z + 1)'. Byłoby to nadal uważane za dobry styl, nawet jeśli nie pasuje on syntaktycznie tak dobrze do "miejsca" Haskella. –

+0

Twój drugi przykład, 'h', jest bardziej przekonujący, ponieważ podanie nazwy" (+1) "jest rzeczywiście dość brzydkie. Oceniłbym to jako równoważnik przykładu SPJ z 'sqrt 4'. Myślę, że mój wniosek jest taki, że "pełne lenistwo" ratuje cię od śmierci tysiącem cięć. Zasadniczo można było zoptymalizować wersje ręcznie, ale byłoby to nieskuteczne wszędzie. –