З документів для GHC 7.6:
[Y] часто навіть не потрібна СПЕЦІАЛІЗАЦІЯ в першу чергу. Під час компіляції модуля M оптимізатор GHC (з -O) автоматично враховує кожну функцію перевантаженого верхнього рівня, заявлену в M, і спеціалізує її для різних типів, при яких вона викликається в М. Оптимізатор також враховує кожну імпортовану НЕМАГНУЮ функцію перевантаження, і спеціалізує його для різних типів, при яких він називається в М.
і
Більше того, даючи прагму СПЕЦІАЛІЗАЦІЇ для функції f, GHC автоматично створить спеціалізацію для будь-яких функцій, перевантажених типом класу, викликаних f, якщо вони є в тому ж модулі, що і прагма SPECIALIZE, або якщо вони НЕВІДОМНІ; і так далі, перехідно.
Таким чином, GHC повинен автоматично спеціалізувати деякі / більшість / всі (?) Функції, позначені INLINABLE
без прагми, і якщо я використовую явну прагму, спеціалізація є транзитивною. Моє питання: це авто -specialization транзитивним?
Зокрема, ось невеликий приклад:
Основні.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 спеціалізується на виклику plus
, але не спеціалізується (+)
на Qux
Num
екземплярі, який вбиває продуктивність.
Однак явна прагма
{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}
призводить до транзитивної спеціалізації, як вказують документи, настільки (+)
спеціалізована і код на 30 разів швидший (обидва компільовані з -O2
). Це очікувана поведінка? Чи варто лише сподіватися (+)
на те, що я буду спеціалізована транзитивно з явною прагмою?
ОНОВЛЕННЯ
Документи для 7.8.2 не змінилися, і поведінка однакова, тому це питання все ще актуальне.
plus
був НЕ відзначений як INLINABLE і 2) simonpj показав , що існує деякий вбудовування відбувається з кодом квитка, але ядро з мій приклад показує, що жодна з функцій не була вбудована (зокрема, я не міг позбутися другого Foo
конструктора, інакше GHC вбудований матеріал).
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
, щоб LHS повністю застосовувався на сайті виклику? Це стає впорядкованим, а потім починається спеціалізація?
plus
повністю застосуватись саме через ці посилання, але насправді я отримав меншу спеціалізацію: дзвінок також plus
не був спеціалізованим. Я не маю цього пояснення, але мав намір залишити його для іншого питання, або сподіваюся, що це буде вирішено у відповіді на це.