Dari dokumen untuk GHC 7.6:
[Y] ou sering kali bahkan tidak membutuhkan pragma SPESIALISASI. Saat menyusun modul M, pengoptimal GHC (dengan -O) secara otomatis mempertimbangkan setiap fungsi tingkat-atas yang dideklarasikan dalam M, dan mengkhususkannya untuk jenis yang berbeda di mana ia disebut dalam M. Pengoptimal juga mempertimbangkan setiap fungsi kelebihan beban yang tidak dapat diimpor yang diimpor, dan mengkhususkannya untuk berbagai jenis yang disebut dalam M.
dan
Selain itu, diberikan pragma SPECIALIZE untuk fungsi f, GHC akan secara otomatis membuat spesialisasi untuk semua fungsi tipe-kelas-kelebihan yang disebut oleh f, jika mereka berada dalam modul yang sama dengan pragma SPECIALIZE, atau jika mereka tidak dapat DILINCARKAN; dan seterusnya, secara transitif.
Jadi GHC secara otomatis harus mengkhususkan beberapa / kebanyakan / semua (?) Fungsi yang ditandai INLINABLE
tanpa pragma, dan jika saya menggunakan pragma eksplisit, spesialisasi adalah transitif. Pertanyaan saya adalah: apakah auto -specialization transitive?
Secara khusus, inilah contoh kecil:
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 mengkhususkan panggilan untuk plus
, tetapi tidak mengkhususkan diri (+)
dalamQux
Num
contoh yang membunuh kinerja.
Namun, pragma eksplisit
{-# SPECIALIZE plus :: Foo (Qux Int) -> Foo (Qux Int) -> Foo (Qux Int) #-}
menghasilkan spesialisasi transitif seperti yang ditunjukkan dokumen, sehingga (+)
terspesialisasi dan kodenya 30x lebih cepat (keduanya dikompilasi dengan -O2
). Apakah ini perilaku yang diharapkan? Haruskah saya hanya berharap (+)
untuk mengkhususkan secara transitif dengan pragma eksplisit?
MEMPERBARUI
Dokumen untuk 7.8.2 belum berubah, dan perilakunya sama, jadi pertanyaan ini masih relevan.
plus
itu tidak ditandai sebagai INLINABLE dan 2) simonpj menunjukkan bahwa ada beberapa inlining terjadi dengan kode tiket, tapi inti dari contoh saya menunjukkan bahwa tidak ada fungsi yang digarisbawahi (khususnya, saya tidak bisa menyingkirkan Foo
konstruktor kedua , jika tidak, GHC inline stuff).
plus (Bar v1) = \(Bar v2)-> Bar $ v1 + v2
, sehingga LHS diterapkan sepenuhnya di situs panggilan? Apakah itu masuk sebaris dan kemudian spesialisasi masuk?
plus
diterapkan sepenuhnya secara khusus karena tautan-tautan itu, tetapi pada kenyataannya saya mendapat spesialisasi yang kurang : panggilan ke plus
juga tidak terspesialisasi. Saya tidak punya penjelasan untuk itu, tetapi berniat meninggalkannya untuk pertanyaan lain, atau berharap itu akan diselesaikan dalam jawaban untuk yang ini.