2017-07-21 5 views
6

मैं मोनड ट्रांसफार्मर सीख रहा हूं और लिफ्ट का उपयोग करते समय मैं उलझन में हूं। मान लें कि मेरे पास निम्न कोड है (यह कुछ भी दिलचस्प नहीं कर रहा है, केवल इतना आसान है कि मैं प्रदर्शन के लिए आ सकता हूं)।जब मोनाड ट्रांसफार्मर में वास्तव में जरूरी उठाना आवश्यक है?

foo :: Int -> State Int Int 
foo x = do 
    (`runContT` pure) $ do 
    callCC $ \exit -> do 
     when (odd x) $ do 
     -- lift unnecessary 
     a <- get 
     put $ 2*a 
     when (x >= 5) $ do 
     -- lift unnecessary, but there is exit 
     a <- get 
     exit a 
     when (x < 0) $ do 
     -- lift necessary 
     a <- lift $ foo (x + 10) 
     lift $ put a 

     lift get 

तो वहाँ एक इकाई ढेर, जहां मुख्य करते ब्लॉक टाइप ContT Int (StateT Int Identity) Int है।

अब, तीसरे when में रिकर्सन के साथ ब्लॉक करें प्रोग्राम को संकलित करने के लिए एक लिफ्ट की आवश्यकता है। दूसरे ब्लॉक में, कोई लिफ्ट की आवश्यकता नहीं है, लेकिन मुझे लगता है कि यह exit की उपस्थिति के कारण है, जो किसी भी तरह से ऊपर की रेखा को ContT पर ले जाने के लिए मजबूर करता है। लेकिन पहले ब्लॉक में, कोई लिफ्ट की आवश्यकता नहीं है। (लेकिन अगर यह स्पष्ट रूप से जोड़ा गया है, तो कोई समस्या नहीं है।) यह वास्तव में मुझे भ्रमित कर रहा है। मुझे लगता है कि सभी when ब्लॉक बराबर हैं और या तो लिफ्ट को हर जगह या कहीं भी आवश्यक नहीं होना चाहिए। लेकिन यह स्पष्ट रूप से सच नहीं है। लिफ्ट को आवश्यक/आवश्यक नहीं होने वाला महत्वपूर्ण अंतर कहां है?

उत्तर

11

यहां भ्रम उत्पन्न हो रहा है क्योंकि आप जिस मोनैड ट्रांसफॉर्मर लाइब्रेरी का उपयोग कर रहे हैं वह थोड़ा चालाक है। विशेष रूप से, get और put का प्रकार स्पष्ट रूप से State या StateT का उल्लेख नहीं करता है। बल्कि, वे इसलिए जब तक हम एक MonadState को लागू इकाई के साथ एक संदर्भ में इस का उपयोग स्पष्ट lift s के लिए कोई जरूरत नहीं है लाइनों

get :: MonadState s m => m s 
put :: MonadState s m => s -> m() 

साथ कर रहे हैं। यह सभी मामलों में जहां आप get/put

के बाद से
instance MonadState s (StateT s m) 
instance MonadState s m => ContT k m 

दोनों पकड़ का उपयोग में मामला है। दूसरे शब्दों में, टाइप क्लास रिज़ॉल्यूशन स्वचालित रूप से आपके लिए उचित उठाने को संभालने में सक्षम होगा। बदले में यह तात्पर्य है कि आप अपने प्रोग्राम के अंत में get/put पर lift एस को बढ़ा सकते हैं।

यह आपके रिकर्सिव कॉल के साथ नहीं हो सकता है क्योंकि इसका प्रकार स्पष्ट रूप से State Int Int है। यदि आपने इसे MonadState Int m => m Int पर सामान्यीकृत किया है तो आप इस अंतिम लिफ्ट को भी बढ़ा सकते हैं।

6

मैं एक वैकल्पिक उत्तर प्रदान करना चाहता हूं जो दोनों सतही है और साथ ही साथ सबकुछ महत्वपूर्ण है।

आपको lift का उपयोग करने की आवश्यकता है जब lift चीज़ों की जांच करता है जो अन्यथा नहीं करते हैं।

हां, यह सतही लगता है और इसमें किसी भी गहरे अर्थ की कमी दिखाई देती है। लेकिन यह काफी सच नहीं है। MonadTrans उन चीजों के लिए एक वर्ग है जो एक तटस्थ तरीके से एक बड़े संदर्भ में monadic कार्यों को उठा सकते हैं। यदि आप एक तकनीकी विवरण चाहते हैं, तो वर्ग कानून "तटस्थ" के बारे में अधिक स्पष्ट नियम प्रदान करते हैं। लेकिन उपरोक्त यह है कि lift प्रदान की गई कार्रवाई को किसी अन्य प्रकार के साथ संगत बनाने के लिए आवश्यक कुछ भी नहीं है।

तो - lift क्या करता है? यह एक बड़े पैमाने पर एक monadic कार्रवाई उठाने के लिए आवश्यक तर्क प्रदान करता है। आपको इसका उपयोग करने की आवश्यकता कब होती है? जब आपके पास एक मोनैडिक कार्रवाई होती है जिसे आपको एक बड़े प्रकार में उठाने की आवश्यकता होती है। आपके पास एक मोनैडिक कार्रवाई कब होती है जिसे आपको एक बड़े प्रकार में उठाने की आवश्यकता होती है? जब यह आपको बताता है।

यह हास्केल का उपयोग करने का एक महत्वपूर्ण हिस्सा है।आप कोड की अपनी समझ को मॉड्यूलर कर सकते हैं। टाइप सिस्टम आपके लिए बड़ी संख्या में बहीखाता का ट्रैक रखता है। बहीखाता सही करने के लिए इस पर भरोसा करें, इसलिए आपको केवल अपने सिर में तर्क रखना होगा। संकलक और प्रकार प्रणाली मानसिक एम्पलीफायर के रूप में काम करने के लिए हैं। जितना अधिक वे ख्याल रखते हैं, सॉफ़्टवेयर लिखते समय आपको अपने सिर में रखने की आवश्यकता होती है।

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