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. plusFastCyc
viene 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 plusFastCyc
in 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.hs
file ha due driver :, vtTest
che viene eseguito in ~ 3 secondi, e fcTest
, che viene eseguito in ~ 83 secondi se compilato con -O3 usando la forall
specializzazione d.
Il nucleo mostra che per il vtTest
test, il codice addizionale è specializzato in Unboxed
vettori su Int
s, ecc., Mentre per il codice vettoriale generico viene utilizzato fcTest
. Sulla riga 10, puoi vedere che GHC scrive una versione specializzata della versione plusFastCyc
generica sulla riga 167. La regola per la specializzazione è sulla riga 225. Credo che questa regola dovrebbe attivarsi sulla riga 270. ( main6
chiama iterate main8 y
, così main8
è dove plusFastCyc
dovrebbe essere specializzato.)
Il mio obiettivo è fcTest
velocizzare quanto vtTest
specializzandomi plusFastCyc
. Ho trovato due modi per farlo:
- Chiamata esplicita
inline
daGHC.Exts
dentrofcTest
. - Rimuovere il
Factored m Int
vincolo 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
, INLINABLE
e SPECIALIZE
, ma nulla sembra funzionare. ( EDIT : potrei essermi spogliato troppo plusFastCyc
per rendere piccolo il mio esempio, quindi INLINE
potrebbe 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 cases
o RULE: LHS too complicated to desugar
(e qui ) avvisi, anche se stavo ricevendo molti match_co
avvisi prima di minimizzare l'esempio. Presumibilmente, il "problema" è il Factored m Int
vincolo della regola; se apporto modifiche a quel vincolo, fcTest
corre 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.