Saya mengalami masalah dalam mendapatkan GHC untuk mengkhususkan fungsi dengan batasan kelas. Saya punya contoh minimal masalah saya di sini: Foo.hs dan Main.hs . Dua file dikompilasi (GHC 7.6.2, ghc -O3 Main) dan jalankan.
CATATAN:
Foo.hs benar-benar dilucuti. Jika Anda ingin melihat mengapa kendala diperlukan, Anda dapat melihat lebih banyak kode di sini . Jika saya memasukkan kode dalam satu file atau membuat banyak perubahan kecil lainnya, GHC hanya akan mengikutsertakan panggilan masuk plusFastCyc. Ini tidak akan terjadi dalam kode nyata karena plusFastCycterlalu besar untuk GHC untuk di-inline, bahkan ketika ditandai INLINE. Intinya adalah untuk mengkhususkan panggilan plusFastCyc, bukan inline itu. plusFastCycdisebut di banyak tempat dalam kode nyata, jadi menduplikasi fungsi besar seperti itu tidak diinginkan bahkan jika saya bisa memaksa GHC untuk melakukannya.
Kode minat adalah plusFastCycdi Foo.hs, direproduksi di sini:
{-# 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
The Main.hsberkas memiliki dua driver: vtTest, yang berjalan di ~ 3 detik, dan fcTest, yang berjalan di ~ 83 detik ketika dikompilasi dengan O3 menggunakan forall'spesialisasi d.
The inti menunjukkan bahwa untuk vtTesttes, kode Selain sedang khusus untuk Unboxedvektor lebih Ints, dll, sementara kode vektor generik digunakan untuk fcTest. Pada baris 10, Anda dapat melihat bahwa GHC memang menulis versi khusus plusFastCyc, dibandingkan dengan versi generik pada baris 167. Aturan untuk spesialisasi adalah pada baris 225. Saya percaya aturan ini harus diaktifkan pada saluran 270. ( main6panggilan iterate main8 y, begitu main8juga di mana plusFastCycharus dikhususkan.)
Tujuan saya adalah membuat fcTestsecepat vtTestdengan spesialisasi plusFastCyc. Saya telah menemukan dua cara untuk melakukan ini:
- Panggilan eksplisit
inlinedariGHC.ExtsdalamfcTest. - Hapus
Factored m Intkendala padaplusFastCyc.
Opsi 1 tidak memuaskan karena dalam basis kode yang sebenarnya plusFastCycadalah operasi yang sering digunakan dan fungsi yang sangat besar, sehingga tidak boleh diuraikan pada setiap penggunaan. Sebaliknya, GHC harus memanggil versi khusus plusFastCyc. Opsi 2 sebenarnya bukan opsi karena saya perlu kendala dalam kode nyata.
Saya sudah mencoba berbagai pilihan menggunakan (dan tidak menggunakan) INLINE, INLINABLEdan SPECIALIZE, tapi sepertinya tidak ada pekerjaan. ( EDIT : Saya mungkin telah menelanjangi terlalu banyak plusFastCycuntuk membuat contoh saya kecil, jadi INLINEmungkin menyebabkan fungsi menjadi inline. Ini tidak terjadi dalam kode asli saya karena plusFastCycsangat besar.) Dalam contoh khusus ini, saya tidak mendapatkan peringatan apa pun match_co: needs more casesatau RULE: LHS too complicated to desugar(dan di sini ), meskipun saya mendapatkan banyak match_coperingatan sebelum memperkecil contoh. Agaknya, "masalah" adalah Factored m Intkendala dalam aturan; jika saya membuat perubahan pada batasan itu, fcTestjalankan secepat vtTest.
Apakah saya melakukan sesuatu yang tidak disukai GHC? Mengapa GHC tidak akan mengkhususkan plusFastCyc, dan bagaimana saya bisa membuatnya?
MEMPERBARUI
Masalahnya tetap ada di GHC 7.8.2, jadi pertanyaan ini masih relevan.
m, yaituM. Ini menyelesaikan pekerjaan, tetapi saya tidak dapat mengkhususkan untuk jenis hantu tertentu dalam program nyata karena mereka diverifikasi.