2017-07-11 10 views
14

GHC.Prim में, हम एक जादुई समारोह dataToTag# नामित पाते हैं। इसका उपयोग Eq, Ord, और Enum के व्युत्पन्न कार्यान्वयन को तेज़ करने के लिए किया जाता है। GHC स्रोत में, docs for dataToTag# समझाने कि तर्क पहले से ही द्वारा मूल्यांकन करना चाहिए:dataToTag तर्क की सख़्ती

dataToTag # primop हमेशा एक से मूल्यांकन तर्क करने के लिए लागू की जानी चाहिए। तरीका यह सुनिश्चित करने के लिए GHC.Base में 'getTag' आवरण के माध्यम से यह आह्वान करने के लिए है:

getTag :: a -> Int# 
getTag !x = dataToTag# x 

यह मेरे लिए कुल समझ में आता है कि हमें पहले dataToTag# कहा जाता है x के मूल्यांकन के लिए मजबूर करने की जरूरत है। मुझे क्या नहीं मिलता है कि बैंग पैटर्न पर्याप्त क्यों है। getTag की परिभाषा के लिए बस वाक्यात्मक चीनी है:

getTag :: a -> Int# 
getTag x = x `seq` dataToTag# x 

लेकिन docs for seq पर गौर करें:

एक नोट मूल्यांकन आदेश पर: अभिव्यक्ति seq a b गारंटी नहीं है कि एक ख से पहले मूल्यांकन किया जाएगा। सीईसी द्वारा दी गई एकमात्र गारंटी यह है कि सीईसी एक मूल्य लौटने से पहले ए और बी दोनों का मूल्यांकन किया जाएगा। विशेष रूप से, इसका मतलब है कि बी से पहले मूल्यांकन किया जा सकता है। यदि आपको मूल्यांकन के एक विशिष्ट आदेश की गारंटी देने की आवश्यकता है, तो आपको "समानांतर" पैकेज से फ़ंक्शन पीएसईसी का उपयोग करना होगा।

parallel पैकेज से Control.Parallel मॉड्यूल में, डॉक्स elaborate further:

... seq, दोनों अपने तर्कों में सख्त है तो संकलक सकता है, उदाहरण के लिए, a `seq` bb `seq` a `seq` b में पुन: व्यवस्थित .. ।

कैसे यह है कि getTag काम व्यवहार करने के लिए गारंटी, यह देखते हुए कि seq मूल्यांकन आदेश को नियंत्रित करने के लिए अपर्याप्त है है?

+0

क्या आप निश्चित हैं कि BangPatterns बस 'seq' के उपयोग में अनुवाद करते हैं? दस्तावेज़ दिखाते हैं कि एक अतिरिक्त 'केस' अभिव्यक्ति भी जोड़ा जाता है। –

+1

@ElliotCameron, वहां कुछ मजेदार जादू है कि मैं वास्तव में समझ में नहीं आता। वे दोनों कोर 'केस' अभिव्यक्तियों को संकलित करते हैं, लेकिन कुछ बंदर व्यवसाय हैं जो उन्हें पुनः लिखने के नियम के बाईं ओर 'seq' से मिलान करने की अनुमति देते हैं। – dfeuer

उत्तर

16

जीएचसी प्रत्येक प्राइमॉप के बारे में कुछ जानकारी ट्रैक करता है। एक महत्वपूर्ण डाटाम यह है कि प्राइमॉप "can_fail" है या नहीं। इस ध्वज का मूल अर्थ यह है कि यदि कोई कठोर गलती हो सकती है तो एक प्राइमप विफल हो सकता है। उदाहरण के लिए, अगर इंडेक्स रेंज से बाहर है तो सरणी इंडेक्सिंग सेगमेंटेशन गलती हो सकती है, इसलिए इंडेक्सिंग ऑपरेशन विफल हो सकते हैं।

यदि कोई प्राइमप विफल हो सकता है, तो जीएचसी इसके आसपास कुछ परिवर्तनों को प्रतिबंधित कर देगा, और विशेष रूप से इसे किसी भी case अभिव्यक्तियों से बाहर नहीं निकाल देगा। यह, बल्कि बुरा होगा उदाहरण के लिए यदि

if n < bound 
then unsafeIndex c n 
else error "out of range" 

case unsafeIndex v n of 
    !x -> if n < bound 
     then x 
     else error "out of range" 

इन नीचे में से एक का संकलन किया गया एक अपवाद है; दूसरा एक segfault है।

dataToTag# can_fail चिह्नित किया गया है।तो GHC देखता है (कोर में) की तरह

getTag = \x -> case x of 
      y -> dataToTag# y 

कुछ (ध्यान दें कि case कोर में सख्त है।) क्योंकि dataToTag# can_fail चिह्नित है, यह किसी भी case भाव से बाहर जारी नहीं किया जाएगा।

संबंधित मुद्दे