2012-01-29 10 views
45

मुझे एक समस्या है जो आईओ पर एमटी (या यहां तक ​​कि एक मीट्रिक टन) के ढेर का उपयोग करके बहुत अच्छी तरह से फिट बैठता है। सब कुछ अच्छा है सिवाय इसके कि प्रत्येक कार्रवाई से पहले लिफ्ट का उपयोग करना बहुत परेशान है! मुझे संदेह है कि इसके बारे में वास्तव में कुछ भी नहीं है, लेकिन मैंने सोचा कि मैं वैसे भी पूछूंगा।मोनाड ट्रांसफॉर्मर्स के साथ लिफ्ट से बचें

मुझे पूरे ब्लॉक उठाने के बारे में पता है, लेकिन क्या होगा यदि कोड वास्तव में मिश्रित प्रकारों का है? क्या यह अच्छा नहीं होगा अगर जीएचसी कुछ वाक्य रचनात्मक चीनी में फेंक दे (उदाहरण के लिए, <-$ = <- lift)?

उत्तर

51

सभी मानक mtl monads के लिए, आपको lift की आवश्यकता नहीं है। get, put, ask, tell - वे सभी स्टैक में कहीं भी सही ट्रांसफार्मर के साथ किसी भी मोनैड में काम करते हैं। गायब टुकड़ा IO है, और यहां तक ​​कि liftIO परतों की मनमानी संख्या के नीचे एक मनमानी आईओ कार्रवाई को लिफ्ट करता है।

यह प्रस्ताव पर प्रत्येक "प्रभाव" के लिए टाइपक्लास के साथ किया जाता है: उदाहरण के लिए, MonadStateget और put प्रदान करता है। आप एक ट्रांसफॉर्मर ढेर चारों ओर अपने स्वयं के newtype आवरण का निर्माण करना चाहते हैं, तो आप GeneralizedNewtypeDeriving विस्तार के साथ deriving (..., MonadState MyState, ...) कर सकते हैं, या अपने स्वयं के उदाहरण रोल:

instance MonadState MyState MyMonad where 
    get = MyMonad get 
    put s = MyMonad (put s) 

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

(आप अपने स्वयं के टाइपक्लास को परिभाषित करके और मानक ट्रांसफार्मर के लिए बॉयलरप्लेट उदाहरण प्रदान करके स्वयं को परिभाषित करने वाले सभी नए मोनैडिक प्रभावों के लिए इस दृष्टिकोण को आसानी से बढ़ा सकते हैं, लेकिन सभी नए मोनड दुर्लभ हैं; अधिकांश समय, आप ' एमटीएल द्वारा पेश किए गए मानक सेट को बस लिखकर प्राप्त होगा।)

+0

ओह मुझे लगता है कि मैं बेवकूफ महसूस करता हूं, आपने उल्लेख किया है कि आपके पिछले उत्तरों में से एक में, मैं उस समय इसे समझ नहीं पाया। अब, मैं धन्यवाद! – aelguindy

43

आप कंक्रीट मोनैड स्टैक्स के बजाय टाइपक्लास का उपयोग करके अपने कार्यों को मोनाड-अज्ञेयवादी बना सकते हैं।

bangMe :: State String() 
bangMe = do 
    str <- get 
    put $ str ++ "!" 
    -- or just modify (++"!") 
बेशक

, आपको लगता है कि यह भी एक ट्रांसफॉर्मर के रूप में काम करता है, इसलिए एक लिख सकते हैं::

मान लीजिए कि आप उदाहरण के लिए इस समारोह है, कि चलो

bangMe :: Monad m => StateT String m() 

हालांकि, यदि आपके पास एक ऐसा फ़ंक्शन है जो एक अलग स्टैक का उपयोग करता है, तो मान लें कि ReaderT [String] (StateT String IO)() या जो भी हो, आपको ड्रेडेड lift फ़ंक्शन का उपयोग करना होगा! तो यह कैसे टाला जाता है?

चाल फ़ंक्शन हस्ताक्षर को और अधिक सामान्य बनाने के लिए है, ताकि यह कह सके कि State मोनड मोनैड स्टैक में कहीं भी दिखाई दे सकता है। यह इस तरह से किया जाता है:

bangMe :: MonadState String m => m() 

यह बलों m एक इकाई है कि राज्य (लगभग) का समर्थन करता है इकाई ढेर में कहीं भी हो सकता है, और समारोह इस प्रकार किसी भी तरह के ढेर के लिए बिना किसी मेहनत के काम करेंगे।

हालांकि, एक समस्या है; चूंकि IOmtl का हिस्सा नहीं है, इसमें ट्रांसफार्मर नहीं है (उदा। IOT) न ही प्रति डिफ़ॉल्ट प्रकार की एक आसान श्रेणी। तो जब आप आईओ कार्यों को मनमाने ढंग से उठाना चाहते हैं तो आपको क्या करना चाहिए?

बचाव के लिए MonadIO आता है!यह MonadState, MonadReader आदि के लगभग समान रूप से व्यवहार करता है, केवल अंतर यह है कि इसमें थोड़ा अलग उठाने की व्यवस्था है। यह इस प्रकार काम करता है: आप IO एक्शन ले सकते हैं, और इसे liftIO का उपयोग एक मोनड अज्ञेय संस्करण में बदलने के लिए करें। तो:

action :: IO() 
liftIO action :: MonadIO m => m() 

monadic कार्रवाई आप इस तरह से उपयोग करना चाहते हैं के सभी बदलने करके, आप किसी कठिन उठाने के बिना जितना आप चाहते हैं के रूप में monads बटना कर सकते हैं।

+0

विस्तृत उत्तर के लिए धन्यवाद! हालांकि एहर्ड द्वारा समय में बीटन;) – aelguindy

+4

मी और एहर्ड इस समस्या के कुछ अलग समाधान प्रदान करते हैं। आपके पास विकल्पों को समझने के लिए दोनों प्रतिक्रियाओं को पढ़ने योग्य हो सकता है :) – dflemstr

+1

यह दुर्भाग्यपूर्ण है कि बॉयलरप्लेट की आवश्यकता है। – rightfold

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