In breve, non tutte le volte che si potrebbe pensare. La ragione è che le "tecniche di fantasia" come la fusione del flusso vengono impiegate quando le librerie sono implementate e gli utenti delle librerie non devono preoccuparsi di esse.
Considerare Data.List.map
. Il pacchetto di base definisce map
come
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
Questo map
è auto-ricorsivo, quindi GHC non inline esso.
Tuttavia, base
definisce anche le seguenti regole di riscrittura:
{-# RULES
"map" [~1] forall f xs. map f xs = build (\c n -> foldr (mapFB c f) n xs)
"mapList" [1] forall f. foldr (mapFB (:) f) [] = map f
"mapFB" forall c f g. mapFB (mapFB c f) g = mapFB c (f.g)
#-}
Questo sostituisce usi di map
via foldr/build fusion, quindi, se la funzione non può essere fuso, lo sostituisce con l'originale map
. Poiché la fusione avviene automaticamente, non dipende dall'essere a conoscenza dell'utente.
A dimostrazione che tutto funziona, è possibile esaminare ciò che GHC produce per specifici input. Per questa funzione:
proc1 = sum . take 10 . map (+1) . map (*2)
eval1 = proc1 [1..5]
eval2 = proc1 [1..]
se compilato con -O2, GHC fonde tutti proc1
in un'unica forma ricorsiva (come visto nell'output core con -ddump-simpl
).
Ovviamente ci sono dei limiti a ciò che queste tecniche possono realizzare.Ad esempio, la funzione media ingenua, mean xs = sum xs/length xs
, può essere trasformata manualmente in una singola piega e frameworks exist that can do so automatically, tuttavia al momento non esiste un modo noto per tradurre automaticamente tra le funzioni standard e il framework di fusione. Quindi, in questo caso, l'utente deve essere consapevole delle limitazioni del codice prodotto dal compilatore.
Quindi in molti casi i compilatori sono sufficientemente avanzati per creare codice rapido ed elegante. Sapendo quando lo faranno, e quando il compilatore rischia di cadere, IMHO è una grande parte dell'apprendimento su come scrivere codice Haskell efficiente.
Ho modificato i collegamenti per te e ho messo a vendere. Bella risposta! – ehird
Ahh, meraviglioso, questo dipinge un'immagine molto più chiara, grazie! –
Intendevi 'g (x: xs) = 2 * x: g xs'? – pat