ฉันมีปัญหาในการทำให้ GHC เชี่ยวชาญฟังก์ชั่นที่มีข้อ จำกัด ด้านชั้นเรียน ผมมีตัวอย่างที่น้อยที่สุดของปัญหาของฉันที่นี่: Foo.hsและ Main.hs รวบรวมไฟล์สองไฟล์ (GHC 7.6.2, ghc -O3 Main) และเรียกใช้
หมายเหตุ:
Foo.hsถูกปล้นจริง ๆ ถ้าคุณต้องการที่จะเห็นว่าทำไมข้อ จำกัด เป็นสิ่งจำเป็นที่คุณสามารถดูรหัสเล็ก ๆ น้อย ๆที่นี่ ถ้าฉันใส่รหัสในไฟล์เดียวหรือทำการเปลี่ยนแปลงเล็ก ๆ น้อย ๆ อื่น ๆ อีกมากมายเพียงแค่ GHC inlines plusFastCycการเรียกร้องให้ สิ่งนี้จะไม่เกิดขึ้นในรหัสจริงเนื่องจากplusFastCycมีขนาดใหญ่เกินไปที่ GHC จะอินไลน์แม้ว่าจะถูกทำเครื่องหมายไว้INLINEก็ตาม ประเด็นก็คือจะต้องชำนาญการโทรplusFastCycไม่ใช่แบบอินไลน์ plusFastCycถูกเรียกในหลาย ๆ ที่ในรหัสจริงดังนั้นการทำซ้ำฟังก์ชันที่มีขนาดใหญ่จะไม่เป็นที่ต้องการแม้ว่าฉันจะบังคับให้ GHC ทำเช่นนั้น
รหัสที่น่าสนใจคือplusFastCycในFoo.hsทำซ้ำที่นี่:
{-# 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
Main.hsไฟล์มีสองไดรเวอร์: vtTestซึ่งทำงานใน ~ 3 วินาทีและfcTestที่ทำงานใน ~ 83 วินาทีเมื่อรวบรวมกับ -O3 ใช้forall'd เชี่ยวชาญ
แสดงหลักว่าสำหรับvtTestการทดสอบรหัสนอกจากจะถูกผู้เชี่ยวชาญเพื่อUnboxedเวกเตอร์บนInts ฯลฯ fcTestในขณะที่รหัสเวกเตอร์ทั่วไปที่ใช้สำหรับ ในบรรทัดที่ 10 คุณจะเห็นว่า GHC เขียนรุ่นพิเศษของplusFastCycเมื่อเทียบกับรุ่นทั่วไปในบรรทัดที่ 167 กฎสำหรับความเชี่ยวชาญนั้นอยู่ที่บรรทัด 225 ฉันเชื่อว่ากฎนี้ควรเริ่มทำงานในสาย 270 (การmain6โทรiterate main8 yดังนั้นmain8ก็คือ ที่plusFastCycควรได้รับความเชี่ยวชาญ.)
เป้าหมายของผมคือการทำให้fcTestเร็วที่สุดเท่าโดยมีความเชี่ยวชาญvtTest plusFastCycฉันพบสองวิธีในการทำสิ่งนี้:
- โทรอย่างชัดเจน
inlineจากในGHC.ExtsfcTest - ลบ
Factored m Intข้อ จำกัดplusFastCycใน
ตัวเลือกที่ 1 ไม่เป็นที่น่าพอใจเนื่องจากในส่วนของรหัสที่แท้จริงplusFastCycนั้นเป็นการดำเนินการที่ใช้บ่อยและฟังก์ชั่นที่มีขนาดใหญ่มากดังนั้นจึงไม่ควรมีการ inline ทุกครั้งที่ใช้งาน แต่ GHC plusFastCycควรจะเรียกรุ่นเฉพาะของ ตัวเลือกที่ 2 ไม่ใช่ตัวเลือกจริงๆเพราะฉันต้องการข้อ จำกัด ในรหัสจริง
ฉันได้พยายามหลากหลายของตัวเลือกใช้ (และไม่ได้ใช้) INLINE, INLINABLEและSPECIALIZEแต่ไม่มีอะไรดูเหมือนว่าจะทำงาน ( แก้ไข : ฉันอาจจะลอกออกมากเกินไปที่plusFastCycจะทำให้ตัวอย่างของฉันเล็กดังนั้นINLINEอาจทำให้ฟังก์ชั่นที่จะ inline นี้ไม่ได้เกิดขึ้นในรหัสที่แท้จริงของฉันเพราะplusFastCycมีขนาดใหญ่มาก) ในตัวอย่างนี้ฉันไม่รับคำเตือนใด ๆmatch_co: needs more casesหรือRULE: LHS too complicated to desugar(และที่นี่ ) แม้ว่าฉันจะได้match_coรับคำเตือนมากมายก่อนที่จะย่อขนาดตัวอย่าง สันนิษฐานว่า "ปัญหา" เป็นFactored m Intข้อ จำกัด ในกฎ; ถ้าฉันเป็นผู้เปลี่ยนแปลงข้อ จำกัด ที่วิ่งเร็วที่สุดเท่าที่fcTestvtTest
ฉันกำลังทำสิ่งที่ GHC ไม่ชอบหรือไม่ เหตุใด GHC จึงไม่เชี่ยวชาญplusFastCycและฉันจะสร้างมันได้อย่างไร
UPDATE
ปัญหายังคงอยู่ใน GHC 7.8.2 ดังนั้นคำถามนี้ยังเกี่ยวข้อง
mMนี่เป็นงานที่ทำเสร็จแล้ว แต่ฉันไม่สามารถชำนาญสำหรับประเภท phantom ที่เฉพาะเจาะจงในโปรแกรมจริงตามที่ได้รับการแก้ไข