Dai documenti per GHC 7.6:
[Y] spesso non hai nemmeno bisogno del pragma SPECIALIZE in primo luogo. Durante la compilazione di un modulo M, l'ottimizzatore di GHC (con -O) considera automaticamente ogni funzione di sovraccarico di livello superiore dichiarata in M e lo specializza per i diversi tipi in cui viene chiamato in M. L'ottimizzatore considera anche ogni funzione di sovraccarico INLINABLE importata, e lo specializza per i diversi tipi in cui viene chiamato in M.
e
Inoltre, dato un pragma SPECIALIZE per una funzione f, GHC creerà automaticamente specializzazioni per tutte le funzioni di tipo sovraccarico di classe chiamate da f, se si trovano nello stesso modulo del pragma SPECIALIZE o se sono INLINABILI; e così via, in modo transitorio.
Quindi GHC dovrebbe specializzare automaticamente alcune / quasi / tutte (?) Funzioni contrassegnate INLINABLE
senza un pragma, e se uso un pragma esplicito, la specializzazione è transitiva. La mia domanda è: l' auto- specializzazione è transitiva?
Nello specifico, ecco un piccolo esempio:
Main.hs:
import Data.Vector.Unboxed as U
import Foo
main =
let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
(Bar (Qux ans)) = iterate (plus y) y !! 100
in putStr $ show $ foldl1' (*) ans
Foo.hs:
module Foo (Qux(..), Foo(..), plus) where
import Data.Vector.Unboxed as U
newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
| Baz !t
instance (Num r, Unbox r) => Num (Qux r) where
{-# INLINABLE (+) #-}
(Qux x) + (Qux y) = Qux $ U.zipWith (+) x y
{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2
GHC è specializzata la chiamata a plus
, ma non senza specializzarsi (+)
nel Qux
Num
caso che uccide le prestazioni.
Tuttavia, un pragma esplicito
{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}
si traduce in specializzazione transitiva come indicano i documenti, quindi (+)
è specializzata e il codice è 30 volte più veloce (entrambi compilati -O2
). Questo comportamento è previsto? Dovrei aspettarmi (+)
di essere specializzato solo in modo transitivo con un pragma esplicito?
AGGIORNARE
I documenti per 7.8.2 non sono cambiati e il comportamento è lo stesso, quindi questa domanda è ancora rilevante.
plus
era contrassegnato come INLINABILE e 2) simonpj indicava che c'era qualche allineamento in corso con il codice del biglietto, ma il nucleo di il mio esempio mostra che nessuna delle funzioni era incorporata (in particolare, non potevo liberarmi del secondo costruttore, altrimenti roba incorporata in GHC). Foo
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
, in modo che l'LHS sia pienamente applicato nel sito di chiamata? Viene incorporato e quindi inizia la specializzazione?
plus
pienamente applicata in modo specifico a causa di quei collegamenti, ma in realtà avevo meno specializzazione: la chiamata a plus
non era nemmeno specializzata. Non ho spiegazioni per questo, ma intendevo lasciarlo per un'altra domanda, o spero che si sarebbe risolto in una risposta a questa.