2016-01-31 11 views
10

pigrizia completo è stato repeatedly demonstrated a cause space leaks.Perché la piena pigrizia è un'ottimizzazione predefinita?

Perché è piena la pigrizia da -O in poi? Non sono convinto dal ragionamento in SP2 The Implementation of Functional Programming Languages. L'affermazione è che in

f = \y -> y + sqrt 4 

sqrt 4 è inutilmente ripetuto ogni volta f viene immesso quindi dovremmo galleggiare fuori lambda. Sono d'accordo nel piccolo, ma poiché abbiamo visto quali problemi questa trasformazione causa nel grande non credo che ne valga la pena. Mi sembra che i vantaggi di questa trasformazione siano ottenibili unilateralmente ** con solo modifiche al codice locale e i programmatori che lo desiderano dovrebbero implementarlo a mano.

Mi puoi convincere del contrario? full-laziness è davvero utile? Sarò particolarmente convinto se riuscirai a fornire esempi che per attuare a mano richiedono una cooperazione multilaterale o trasformazioni non locali.

** a differenza di ottimizzazioni come inline e la fusione torrente che implementare manualmente richiederebbe la cooperazione multilaterale tra i moduli e il codice non-locale cambia

+1

La trasformazione della "pigrizia totale" in realtà non ha nulla a che fare con l'ordine di valutazione. –

risposta

7

C'è almeno un caso comune in cui completa la pigrizia è "sicuro" e un'ottimizzazione .

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

significa questo veramente g = \z -> let {f = ...} in f (z+1) e, compilato in questo modo, assegnerà una chiusura per f prima di chiamare. Ovviamente questo è stupido, e il compilatore dovrebbe trasformare il programma in

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

in cui non è necessaria alcuna allocazione di chiamare g_f. Fortunatamente la trasformazione della pigrizia completa fa esattamente questo.

Ovviamente i programmatori potevano astenersi dal fare queste definizioni locali che non dipendono gli argomenti della funzione di primo livello, ma tali definizioni sono generalmente considerato buono stile ...

Un altro esempio:

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

In questo caso si può semplicemente ridurre, ma normalmente non si può ridurre. E nominare la funzione (+1) è abbastanza brutto.

+0

Grazie per l'esempio. Lo stesso si applicherebbe se 'f' fosse un' Int ', specialmente se il calcolo fosse costoso. Tuttavia, stavo pensando a una trasformazione meno violenta: 'g = let {f = ...} in \ z -> f (z + 1)'. Questo sarebbe comunque considerato un buon stile, anche se non si adatta sintatticamente a quello di Haskell "Dove". –

+0

Il tuo secondo esempio, 'h', è più convincente perché dare un nome a' (+1) 'è davvero piuttosto brutto. Lo valuterei come equivalente all'esempio di SPJ con 'sqrt 4'. Immagino che la mia conclusione sia che la "pigrizia totale" ti salva dalla morte di mille tagli. In teoria, si potrebbero produrre versioni ottimizzate a mano, ma sarebbe inefficiente farlo ovunque. –