Dipende da cosa intendi per generatore. L'elenco viene generato pigramente e, poiché nient'altro lo fa riferimento, le parti consumate vengono raccolte automaticamente quasi immediatamente. Poiché il risultato del calcolo sopra non aumenta, l'intero calcolo viene eseguito in uno spazio costante. Questo non è richiesto dallo standard, ma poiché è più difficile implementare una semantica non-strittiva con un comportamento spaziale diverso per quell'esempio (e molto vagamente simile), in pratica si può fare affidamento su di esso.
Ma normalmente, l'elenco viene comunque generato come elenco, quindi sono presenti molti rifiuti. In circostanze favorevoli, ghc elimina l'elenco [1 .. ]
e produce un ciclo non ripartisce:
result :: [Int]
result = filter odd . filter even $ [1 .. ]
(utilizzando le funzioni Prelude pigrizia), compilati con -O2
genera il nucleo
List.result_go =
\ (x_ayH :: GHC.Prim.Int#) ->
case GHC.Prim.remInt# x_ayH 2 of _ {
__DEFAULT ->
case x_ayH of wild_Xa {
__DEFAULT -> List.result_go (GHC.Prim.+# wild_Xa 1);
9223372036854775807 -> GHC.Types.[] @ GHC.Types.Int
};
0 ->
case x_ayH of wild_Xa {
__DEFAULT -> List.result_go (GHC.Prim.+# wild_Xa 1);
9223372036854775807 -> GHC.Types.[] @ GHC.Types.Int
}
}
Un ciclo normale , in esecuzione da 1 a maxBound :: Int
, non producendo nulla sulla strada e []
alla fine. È quasi abbastanza intelligente da restituire semplicemente []
. Nota che c'è solo una divisione per 2, GHC sa che se uno Int
è pari, non può essere dispari, così che il controllo è stato eliminato, e in nessun ramo viene creata una lista non vuota (cioè, i rami non raggiungibili hanno stato eliminato dal compilatore).
fonte
2011-11-26 12:21:10
Ti rendi conto che stai utilizzando un interprete per verificare le ottimizzazioni? – delnan
buon punto, compilato, le stesse cose accadono –
'filtro dispari. filtra anche $ [1 ..] ' – is7s