Estou tendo problemas para que o GHC especialize uma função com uma restrição de classe. Eu tenho um exemplo mínimo do meu problema aqui: Foo.hs e Main.hs . Os dois arquivos são compilados (GHC 7.6.2 ghc -O3 Main) e executados.
NOTA:
Foo.hs está realmente despojado. Se você quiser ver por que a restrição é necessária, poderá ver um pouco mais de código aqui . Se eu colocar o código em um único arquivo ou fazer muitas outras pequenas alterações, o GHC simplesmente encaminha a chamada para plusFastCyc. Isso não acontecerá no código real, porque plusFastCycé muito grande para o GHC se alinhar, mesmo quando marcado INLINE. O objetivo é especializar a chamada plusFastCyc, e não incorporá-la. plusFastCycé chamado em muitos lugares no código real, portanto, duplicar uma função tão grande não seria desejável, mesmo se eu pudesse forçar o GHC a fazê-lo.
O código de interesse é o plusFastCycin Foo.hs, reproduzido aqui:
{-# 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
O Main.hsarquivo possui dois drivers vtTest:, que é executado em ~ 3 segundos e fcTest, que é executado em ~ 83 segundos quando compilado com -O3 usando a forallespecialização 'd.
O núcleo mostra que, para o vtTestteste, o código de adição está sendo especializado em Unboxedvetores sobre Ints, etc., enquanto o código vetorial genérico é usado fcTest. Na linha 10, você pode ver que o GHC escreve uma versão especializada plusFastCyc, em comparação com a versão genérica na linha 167. A regra para a especialização está na linha 225. Acredito que essa regra deve ser acionada na linha 270. ( main6chama iterate main8 y, assim main8é onde plusFastCycdeve ser especializado.)
Meu objetivo é fazer o fcTestmais rápido possível, vtTestespecializando-me plusFastCyc. Eu encontrei duas maneiras de fazer isso:
- Chamada de explícita
inlinedeGHC.ExtsdentrofcTest. - Remova a
Factored m Intrestrição ativadaplusFastCyc.
A opção 1 não é satisfatória porque, na base de código real, plusFastCycé uma operação frequentemente usada e uma função muito grande, portanto, não deve ser incorporada a cada uso. Em vez disso, o GHC deve chamar uma versão especializada do plusFastCyc. A opção 2 não é realmente uma opção, porque eu preciso da restrição no código real.
Eu tentei uma variedade de opções usando (e não usando) INLINE, INLINABLEe SPECIALIZE, mas nada parece funcionar. ( EDIT : eu posso ter despojado demais plusFastCycpara tornar meu exemplo pequeno, portanto, INLINEpode fazer com que a função seja incorporada. Isso não acontece no meu código real porque plusFastCycé muito grande.) Neste exemplo em particular, não sou recebendo algum match_co: needs more casesou RULE: LHS too complicated to desugar(e aqui ) avisos, embora eu estivesse recebendo muitos match_coavisos antes de minimizar o exemplo. Presumivelmente, o "problema" é a Factored m Intrestrição na regra; se eu fizer alterações nessa restrição, será fcTestexecutado o mais rápido possível vtTest.
Estou fazendo algo que o GHC simplesmente não gosta? Por que o GHC não se especializou plusFastCyce como posso fazê-lo?
ATUALIZAR
O problema persiste no GHC 7.8.2, então essa questão ainda é relevante.
m, a saberM. Isso fez o trabalho, mas não posso me especializar para tipos fantasmas específicos no programa real, pois eles são reificados.