Ho problemi a far sì che GHC specializzi una funzione con un vincolo di classe. Ho un esempio minimo del mio problema qui: Foo.hs e Main.hs . I due file vengono compilati (GHC 7.6.2, ghc -O3 Main) ed eseguiti.
NOTA:
Foo.hs è davvero ridotto. Se vuoi vedere perché è necessario il vincolo, puoi vedere un po 'più di codice qui . Se inserisco il codice in un singolo file o apporto molte altre modifiche minori, GHC semplifica semplicemente la chiamata a plusFastCyc. Ciò non accadrà nel codice reale perché plusFastCycè troppo grande per essere integrato in GHC, anche se contrassegnato INLINE. Il punto è specializzare la chiamata a plusFastCyc, non incorporarla. plusFastCycviene chiamato in molti punti del codice reale, quindi duplicare una funzione così grande non sarebbe desiderabile anche se potessi forzare GHC a farlo.
Il codice di interesse è il plusFastCycin Foo.hs, riprodotto qui:
{-# INLINEABLE plusFastCyc #-}
{-# SPECIALIZE plusFastCyc ::
forall m . (Factored m Int) =>
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) ->
(FastCyc (VT U.Vector m) Int) #-}
-- Although the next specialization makes `fcTest` fast,
-- it isn't useful to me in my real program because the phantom type M is reified
-- {-# SPECIALIZE plusFastCyc ::
-- FastCyc (VT U.Vector M) Int ->
-- FastCyc (VT U.Vector M) Int ->
-- FastCyc (VT U.Vector M) Int #-}
plusFastCyc :: (Num (t r)) => (FastCyc t r) -> (FastCyc t r) -> (FastCyc t r)
plusFastCyc (PowBasis v1) (PowBasis v2) = PowBasis $ v1 + v2
Il Main.hsfile ha due driver :, vtTestche viene eseguito in ~ 3 secondi, e fcTest, che viene eseguito in ~ 83 secondi se compilato con -O3 usando la forallspecializzazione d.
Il nucleo mostra che per il vtTesttest, il codice addizionale è specializzato in Unboxedvettori su Ints, ecc., Mentre per il codice vettoriale generico viene utilizzato fcTest. Sulla riga 10, puoi vedere che GHC scrive una versione specializzata della versione plusFastCycgenerica sulla riga 167. La regola per la specializzazione è sulla riga 225. Credo che questa regola dovrebbe attivarsi sulla riga 270. ( main6chiama iterate main8 y, così main8è dove plusFastCycdovrebbe essere specializzato.)
Il mio obiettivo è fcTestvelocizzare quanto vtTestspecializzandomi plusFastCyc. Ho trovato due modi per farlo:
- Chiamata esplicita
inlinedaGHC.ExtsdentrofcTest. - Rimuovere il
Factored m Intvincolo attivoplusFastCyc.
L'opzione 1 non è soddisfacente perché nella base di codice attuale plusFastCycè un'operazione utilizzata di frequente e una funzione molto grande, quindi non dovrebbe essere incorporata ad ogni utilizzo. Piuttosto, GHC dovrebbe chiamare una versione specializzata di plusFastCyc. L'opzione 2 non è in realtà un'opzione perché ho bisogno del vincolo nel codice reale.
Ho provato una varietà di opzioni di utilizzo (e non usando) INLINE, INLINABLEe SPECIALIZE, ma nulla sembra funzionare. ( EDIT : potrei essermi spogliato troppo plusFastCycper rendere piccolo il mio esempio, quindi INLINEpotrebbe essere inline la funzione. Questo non accade nel mio codice reale perché plusFastCycè così grande.) In questo esempio particolare, non lo sono ricevere eventuali match_co: needs more caseso RULE: LHS too complicated to desugar(e qui ) avvisi, anche se stavo ricevendo molti match_coavvisi prima di minimizzare l'esempio. Presumibilmente, il "problema" è il Factored m Intvincolo della regola; se apporto modifiche a quel vincolo, fcTestcorre veloce quanto vtTest.
Sto facendo qualcosa che a GHC non piace? Perché GHC non è specializzato in plusFastCyc, e come posso farlo?
AGGIORNARE
Il problema persiste in GHC 7.8.2, quindi questa domanda è ancora rilevante.
m, vale a direM. Questo ha portato a termine il lavoro, ma non posso specializzarmi per specifici tipi di fantasmi nel programma reale in quanto sono reificati.