Ich habe Probleme, GHC auf eine Funktion mit einer Klassenbeschränkung zu spezialisieren. Ich habe hier ein minimales Beispiel für mein Problem: Foo.hs und Main.hs. Die beiden Dateien kompilieren (GHC 7.6.2, ghc -O3 Main
) und ausführen.Spezialisierung mit Einschränkungen
HINWEIS: Foo.hs
ist wirklich abgespeckt. Wenn Sie sehen möchten, warum die Einschränkung benötigt wird, können Sie ein wenig mehr Code here sehen. Wenn ich den Code in eine einzige Datei schreibe oder viele andere geringfügige Änderungen vornehme, leitet GHC den Anruf einfach an plusFastCyc
. Dies wird im echten Code nicht vorkommen, weil plusFastCyc
zu groß für GHC ist, um inline zu sein, selbst wenn es INLINE
markiert wird. Der Punkt ist spezialisieren der Anruf an plusFastCyc
, nicht inline es. plusFastCyc
wird an vielen Stellen im echten Code aufgerufen, daher wäre das Duplizieren einer so großen Funktion nicht wünschenswert, selbst wenn ich GHC zwingen könnte, dies zu tun.
Der Code von Interesse ist die plusFastCyc
in Foo.hs
, hier wiedergegeben:
{-# 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.hs
Datei hat zwei Treiber: vtTest
, die in ~ 3 Sekunden läuft, und fcTest
, die läuft ~ 83 Sekunden, wenn kompiliert mit -O3 unter Verwendung der forall
'd Spezialisierung.
Die core shows, die für den vtTest
Test wird der Additionscode, um Unboxed
Vektoren über Int
s spezialisiert zu werden usw., während generic Vektorcode für fcTest
verwendet. In Zeile 10 können Sie sehen, dass GHC eine spezielle Version von plusFastCyc
im Vergleich zur generischen Version in Zeile 167 schreibt. Die Regel für die Spezialisierung ist in Zeile 225. Ich glaube, dass diese Regel in Zeile 270 ausgelöst werden sollte. (main6
ruft iterate main8 y
, so main8
ist, wo plusFastCyc
spezialisiert sein sollte.)
Mein Ziel ist es fcTest
so schnell wie vtTest
durch die Spezialisierung plusFastCyc
zu machen. Ich habe zwei Wege gefunden, dies zu tun:
- explicity Anruf
inline
vonGHC.Exts
infcTest
. - Entfernen Sie die
Factored m Int
Einschränkung aufplusFastCyc
.
Option 1 ist unbefriedigend, weil in der eigentlichen Code-Basis plusFastCyc
ein häufig verwendeter Betrieb ist und eine sehr große Funktion, so sollte es nicht bei jeder Benutzung inlined werden. Stattdessen sollte GHC eine spezielle Version von plusFastCyc
aufrufen. Option 2 ist nicht wirklich eine Option, weil ich die Einschränkung im echten Code brauche.
Ich habe versucht eine Vielzahl von Optionen mit (und nicht mit) INLINE
, INLINABLE
und SPECIALIZE
, aber nichts scheint zu funktionieren. (EDIT: Ich habe vielleicht zu viel von plusFastCyc
abgestreift, um mein Beispiel klein zu machen, so INLINE
könnte dazu führen, dass die Funktion inline. Dies passiert nicht in meinem echten Code, weil plusFastCyc
so groß ist.) In diesem speziellen Beispiel bekomme ich keine match_co: needs more cases
oder RULE: LHS too complicated to desugar
(und here) Warnungen, obwohl ich viele match_co
Warnungen erhielt, bevor ich das Beispiel minimierte. Vermutlich ist das "Problem" die Factored m Int
Einschränkung in der Regel; Wenn ich Änderungen an dieser Nebenbedingung vornehme, läuft fcTest
so schnell wie vtTest
.
Mache ich etwas, das GHC einfach nicht mag? Warum wird GHC nicht die plusFastCyc
spezialisieren, und wie kann ich es machen?
UPDATE
Das Problem in GHC bleibt 7.8.2, so ist diese Frage nach wie vor relevant.
Ich habe gerade versucht, spezialisiert für ein * specific * 'm', nämlich' M'. Das hat den Job erledigt, aber ich kann mich nicht auf bestimmte Phantomtypen im realen Programm spezialisieren, da sie verdinglicht sind. – crockeea
Ich habe auch einen GHC-Fehlerbericht https://ghc.haskell.org/trac/ghc/ticket/8668 eingereicht, aber das Problem ist noch offen. Der Fehlerberichterstattungsprozess hat mir geholfen, die Frage ein wenig aufzulockern, also wird es hoffentlich leichter sein, herauszufinden, was vor sich geht. – crockeea
@monojohnny Sorry das zu hören, ich glaube du kannst es als solches kennzeichnen. Ich denke, ich fordere GHC auf, etwas Vernünftiges zu tun, und das wird es nicht tun. Ich bin mir nicht sicher, ob ich es falsch mache, oder ob dies eine Idiosynkrasie mit dem Compiler ist, die einen Workaround haben könnte. Ich habe Workarounds für Spezialisierung und Regeln in einer speziellen Bibliothek auf Hacker-Basis gesehen, die mir im Moment entgehen, also hoffe ich, dass jemand in der Community mit mehr GHC-Erfahrung als ich selbst wissen kann, wie man Spezialisierung erreicht. – crockeea