मुझे जीएचसी होने में समस्या हो रही है ताकि एक वर्ग बाधा के साथ एक फ़ंक्शन को विशेषज्ञ किया जा सके। मैं यहाँ मेरी समस्या का एक न्यूनतम उदाहरण है: 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। यह काम मिल गया, लेकिन मैं वास्तविक कार्यक्रम में विशिष्ट प्रेत प्रकारों के लिए विशेषज्ञ नहीं हो सकता, क्योंकि वे पुनरीक्षित हैं।