Aus den Dokumenten für GHC 7.6:
[Y] Oft brauchen Sie gar nicht erst das Pragma SPEZIALISIEREN. Beim Kompilieren eines Moduls M berücksichtigt der Optimierer von GHC (mit -O) automatisch jede in M deklarierte überladene Funktion der obersten Ebene und ist auf die verschiedenen Typen spezialisiert, bei denen es in M aufgerufen wird. Der Optimierer berücksichtigt auch jede importierte INLINABLE überladene Funktion. und spezialisiert es auf die verschiedenen Typen, bei denen es in M genannt wird.
und
Darüber hinaus erstellt GHC bei einem SPECIALIZE-Pragma für eine Funktion f automatisch Spezialisierungen für alle von f aufgerufenen Funktionen, die von Typklassen überladen sind, wenn sie sich im selben Modul wie das SPECIALIZE-Pragma befinden oder INLINABLE sind. und so weiter, transitiv.
Daher sollte GHC einige / die meisten / alle (?) Funktionen, die INLINABLE
ohne Pragma markiert sind, automatisch spezialisieren. Wenn ich ein explizites Pragma verwende, ist die Spezialisierung transitiv. Meine Frage ist: Ist die Auto- Spezialisierung transitiv?
Hier ist ein kleines Beispiel:
Main.hs:
import Data.Vector.Unboxed as U
import Foo
main =
let y = Bar $ Qux $ U.replicate 11221184 0 :: Foo (Qux Int)
(Bar (Qux ans)) = iterate (plus y) y !! 100
in putStr $ show $ foldl1' (*) ans
Foo.hs:
module Foo (Qux(..), Foo(..), plus) where
import Data.Vector.Unboxed as U
newtype Qux r = Qux (Vector r)
-- GHC inlines `plus` if I remove the bangs or the Baz constructor
data Foo t = Bar !t
| Baz !t
instance (Num r, Unbox r) => Num (Qux r) where
{-# INLINABLE (+) #-}
(Qux x) + (Qux y) = Qux $ U.zipWith (+) x y
{-# INLINABLE plus #-}
plus :: (Num t) => (Foo t) -> (Foo t) -> (Foo t)
plus (Bar v1) (Bar v2) = Bar $ v1 + v2
GHC ist auf den Aufruf von spezialisiert plus
, jedoch nicht auf (+)
die Qux
Num
Instanz, die die Leistung beeinträchtigt.
Ein explizites Pragma
{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}
führt zu einer transitiven Spezialisierung, wie in den Dokumenten angegeben, (+)
ist also spezialisiert und der Code ist 30x schneller (beide kompiliert mit -O2
). Ist das erwartetes Verhalten? Sollte ich nur erwarten (+)
, mich transitiv mit einem expliziten Pragma zu spezialisieren?
AKTUALISIEREN
Die Dokumente für 7.8.2 haben sich nicht geändert, und das Verhalten ist dasselbe, sodass diese Frage weiterhin relevant ist.
plus
wurde nicht als INLINABLE markiert und 2) simonpj angegeben , dass es einige inlining los mit dem Ticket - Code, aber der Kern aus Mein Beispiel zeigt, dass keine der Funktionen inline war (insbesondere konnte ich den zweiten Foo
Konstruktor nicht loswerden , sonst GHC inlined).
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
, dass die LHS am Anrufort vollständig angewendet wird? Wird es inline und setzt dann die Spezialisierung ein?
plus
, mich aufgrund dieser Links vollständig zu bewerben, aber tatsächlich wurde ich weniger spezialisiert: Der Anruf an plus
war auch nicht spezialisiert. Ich habe keine Erklärung dafür, wollte es aber für eine andere Frage belassen oder hoffe, dass es in einer Antwort auf diese Frage gelöst wird.