Z dokumentacji GHC 7.6:
[T] często często nie potrzebujesz pragmy SPECJALIZACJI. Podczas kompilacji modułu M optymalizator GHC (z -O) automatycznie uwzględnia każdą przeciążoną funkcję najwyższego poziomu zadeklarowaną w M i specjalizuje ją dla różnych typów, w których jest wywoływany w M. Optymalizator bierze również pod uwagę każdą importowaną funkcję przeciążenia INLINABLE, i specjalizuje się w różnych typach nazwanych w M.
i
Co więcej, biorąc pod uwagę pragmat SPECIALIZE dla funkcji f, GHC automatycznie utworzy specjalizacje dla funkcji przeciążonych klasą typu wywoływanych przez f, jeśli są one w tym samym module co pragma SPECIALIZE, lub jeśli są NIEZŁĄCZNE; i tak dalej, tranzytowo.
Więc GHC powinien automatycznie specjalizować niektóre / większość / wszystkie (?) Funkcje oznaczone INLINABLE
bez pragmy, a jeśli użyję wyraźnej pragmy, specjalizacja jest przechodnia. Moje pytanie brzmi: czy przechodzenie na automatyczną specyfikację jest przechodnie?
Oto mały przykład:
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 specjalizuje się w wywołaniu plus
, ale nie specjalizuje się (+)
w Qux
Num
instancji, która zabija wydajność.
Jednak wyraźna pragma
{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}
skutkuje specjalizacją przechodnią, jak wskazują dokumenty, więc (+)
jest wyspecjalizowany, a kod jest 30 razy szybszy (oba kompilowane -O2
). Czy to oczekiwane zachowanie? Czy powinienem oczekiwać, (+)
że będę specjalizował się wyłącznie w transporcie z wyraźną pragmą?
AKTUALIZACJA
Dokumenty dla wersji 7.8.2 nie uległy zmianie, a zachowanie jest takie samo, więc to pytanie jest nadal aktualne.
plus
został oznaczony jako INLINABLE i 2) simonpj wskazał, że było trochę inlinizacji z kodem biletu, ale rdzeń z mój przykład pokazuje, że żadna z funkcji nie została wstawiona (w szczególności nie mogłem pozbyć się drugiego konstruktora, w przeciwnym razie wstawiono GHC). Foo
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
, aby LHS został w pełni zastosowany na stronie wywoławczej? Czy zaczyna się inline, a potem zaczyna specjalizacja?
plus
pełnego zastosowania specjalnie z powodu tych linków, ale w rzeczywistości uzyskałem mniej specjalizacji: wezwanie do plus
nie było również specjalizowane. Nie mam na to wytłumaczenia, ale zamierzałem zostawić to na inne pytanie lub mam nadzieję, że zostanie rozwiązane w odpowiedzi na to pytanie.