Ich habe Probleme, GHC dazu zu bringen, eine Funktion mit einer Klassenbeschränkung zu spezialisieren. Ich habe ein minimales Beispiel für mein Problem hier: Foo.hs und Main.hs . Die beiden Dateien werden kompiliert (GHC 7.6.2 ghc -O3 Main) und ausgeführt.
HINWEIS:
Foo.hs ist wirklich reduziert. Wenn Sie sehen möchten, warum die Einschränkung benötigt wird, können Sie hier etwas mehr Code sehen . Wenn ich den Code in eine einzelne Datei einfüge oder viele andere kleinere Änderungen vornehme, leitet GHC den Aufruf einfach an plusFastCyc. Dies wird im realen Code nicht passieren, da plusFastCycGHC zu groß ist, um inline zu sein, selbst wenn es markiert ist INLINE. Es geht darum , den Anruf zu spezialisieren plusFastCycund nicht zu inline. plusFastCycwird an vielen Stellen im realen Code aufgerufen, so dass das Duplizieren einer so großen Funktion nicht wünschenswert wäre, selbst wenn ich GHC dazu zwingen könnte.
Der Code von Interesse ist der plusFastCycin Foo.hs, hier wiedergegebene:
{-# 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
Die Main.hsDatei hat zwei Treiber: vtTestdie in ~ 3 Sekunden ausgeführt werden und fcTestdie in ~ 83 Sekunden ausgeführt werden, wenn sie mit -O3 unter Verwendung der forallSpezialisierung 'd kompiliert werden .
Der Kern zeigt, dass für den vtTestTest der Additionscode auf UnboxedVektoren über Ints usw. spezialisiert ist, während für generischen Vektorcode verwendet wird fcTest. In Zeile 10 können Sie sehen , dass GHC eine spezielle Version von schreibt plusFastCyc, im Vergleich zu der generischen Version auf Linie 167. Die Regel für die Spezialisierung auf der Leitung 225. ich diese Regel glaube , auf der Linie 270. (Feuer soll main6Anrufe iterate main8 y, so main8ist wo plusFastCycsollte spezialisiert werden.)
Mein Ziel ist es, fcTestso schnell wie möglich zu vtTestspezialisieren plusFastCyc. Ich habe zwei Möglichkeiten gefunden, dies zu tun:
- Explicity Call
inlinevonGHC.ExtsinfcTest. - Entfernen Sie die
Factored m IntEinschränkung aufplusFastCyc.
Option 1 ist unbefriedigend, da es sich bei der eigentlichen Codebasis plusFastCycum eine häufig verwendete Operation und eine sehr große Funktion handelt, sodass sie nicht bei jeder Verwendung eingefügt werden sollte. Vielmehr sollte GHC eine spezielle Version von aufrufen plusFastCyc. Option 2 ist nicht wirklich eine Option, da ich die Einschränkung im realen Code benötige.
Ich habe eine Vielzahl von Optionen versucht , mit (und nicht mit ) INLINE, INLINABLEund SPECIALIZE, aber nichts scheint zu funktionieren. ( BEARBEITEN : Ich habe möglicherweise zu viel entfernt plusFastCyc, um mein Beispiel klein zu machen, sodass INLINEdie Funktion möglicherweise inline ist. Dies geschieht in meinem realen Code nicht, weil er plusFastCycso groß ist.) In diesem speziellen Beispiel bin ich es nicht Erhalten von match_co: needs more casesoder RULE: LHS too complicated to desugar(und hier ) Warnungen, obwohl ich viele match_coWarnungen erhalten habe, bevor ich das Beispiel minimiert habe. Vermutlich ist das "Problem" die Factored m IntEinschränkung in der Regel; Wenn ich Änderungen an dieser Einschränkung vornehme, fcTestläuft sie so schnell wie vtTest.
Mache ich etwas, das GHC einfach nicht mag? Warum wird GHC das nicht spezialisieren plusFastCycund wie kann ich es machen?
AKTUALISIEREN
Das Problem besteht weiterhin in GHC 7.8.2, daher ist diese Frage immer noch relevant.
m, nämlichM. Dies hat die Arbeit erledigt, aber ich kann mich nicht auf bestimmte Phantomtypen im realen Programm spezialisieren, da diese bestätigt werden.