मुझे जीएचसी होने में समस्या हो रही है ताकि एक वर्ग बाधा के साथ एक फ़ंक्शन को विशेषज्ञ किया जा सके। मैं यहाँ मेरी समस्या का एक न्यूनतम उदाहरण है: Foo.hs और Main.hs । दो फ़ाइलें संकलित (जीएचसी 7.6.2 ghc -O3 Main
) , और चलाते हैं।
नोट:
Foo.hs
वास्तव में नीचे छीन लिया है। यदि आप यह देखना चाहते हैं कि बाधा की आवश्यकता क्यों है, तो आप यहां थोड़ा और कोड देख सकते हैं । अगर मैं किसी एकल फ़ाइल में कोड डालता हूं या कई अन्य छोटे बदलाव करता हूं, तो जीएचसी केवल कॉल को बताता है plusFastCyc
। यह वास्तविक कोड में नहीं होगा क्योंकि plusFastCyc
चिह्नित होने पर भी जीएचसी इनलाइन के लिए बहुत बड़ा है 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
का उपयोग करते समय -O3 साथ संकलित जो ~ 83 सेकंड में चलता है, forall
'घ विशेषज्ञता।
कोर शो है कि के लिए vtTest
परीक्षण, इसके कोड को विशेष की जा रही है Unboxed
पर सदिशों Int
, रों, आदि, जबकि सामान्य वेक्टर कोड के लिए प्रयोग किया जाता है fcTest
। लाइन 10 पर, आप देख सकते हैं कि जीएचसी plusFastCyc
लाइन 167 पर जेनेरिक संस्करण की तुलना में , का एक विशेष संस्करण लिखता है। विशेषज्ञता के लिए नियम लाइन 225 पर है। मेरा मानना है कि इस नियम को लाइन 270 पर आग लगनी चाहिए। ( main6
कॉल iterate main8 y
, ऐसा main8
है) जहां plusFastCyc
विशेष होना चाहिए।)
मेरा लक्ष्य विशेषज्ञता fcTest
से उतनी ही तेजी vtTest
से आगे बढ़ना है plusFastCyc
। मुझे ऐसा करने के दो तरीके मिले हैं:
- स्पष्ट रूप से कॉल
inline
सेGHC.Exts
मेंfcTest
। - निकालें
Factored m Int
पर बाधाplusFastCyc
।
विकल्प 1 असंतोषजनक है क्योंकि वास्तविक कोड बेस plusFastCyc
में अक्सर उपयोग किया जाने वाला ऑपरेशन और एक बहुत बड़ा कार्य होता है, इसलिए इसे हर उपयोग में इनलाइन नहीं किया जाना चाहिए। बल्कि, जीएचसी को विशेष संस्करण का आह्वान करना चाहिए plusFastCyc
। विकल्प 2 वास्तव में एक विकल्प नहीं है क्योंकि मुझे वास्तविक कोड में बाधा की आवश्यकता है।
मैं का उपयोग कर (और का उपयोग नहीं) विकल्प की एक किस्म की कोशिश की है INLINE
, INLINABLE
और SPECIALIZE
, लेकिन कुछ भी काम करने लगता है। ( EDIT : मैंने plusFastCyc
अपने उदाहरण को छोटा बनाने के लिए बहुत अधिक छीन लिया है , इसलिए INLINE
फ़ंक्शन के इनलाइन होने का कारण हो सकता है। यह मेरे वास्तविक कोड में नहीं होता है क्योंकि plusFastCyc
यह बहुत बड़ा है।) इस विशेष उदाहरण में, मैं नहीं हूं। किसी भी match_co: needs more cases
या RULE: LHS too complicated to desugar
(और यहां ) चेतावनी प्राप्त करना, हालांकि match_co
उदाहरण को छोटा करने से पहले मुझे कई चेतावनी मिल रही थी । वर्तमान में, "समस्या" Factored m Int
नियम में बाधा है; अगर मैं उस बाधा में बदलाव करता हूं, तो fcTest
उतनी ही तेजी से चलता है vtTest
।
मैं कुछ कर रहा हूँ GHC पसंद नहीं है? जीएचसी विशेषज्ञ क्यों नहीं होगा plusFastCyc
, और मैं इसे कैसे बना सकता हूं?
अपडेट करें
यह समस्या GHC 7.8.2 में बनी हुई है, इसलिए यह प्रश्न अभी भी प्रासंगिक है।
m
, अर्थात्M
। यह काम मिल गया, लेकिन मैं वास्तविक कार्यक्रम में विशिष्ट प्रेत प्रकारों के लिए विशेषज्ञ नहीं हो सकता, क्योंकि वे पुनरीक्षित हैं।