तो, आप ई IO
के अंदर फंस गया, और आप बिना घोंसले if
एस के बिना परिस्थितियों का एक गुच्छा देखना चाहते हैं। मुझे उम्मीद है कि आप मुझे जवाब देने के तरीके से हास्केल में हल करने वाली अधिक सामान्य समस्या पर एक अवसाद को माफ कर देंगे।
इस बात पर विचार करें कि इसे कैसे व्यवहार करने की आवश्यकता है।
- सफलता, जिस स्थिति में कार्यक्रम समारोह
- विफलता, जिस स्थिति में कार्यक्रम समारोह के बाकी को छोड़ देता है और त्रुटि संदेश देता है के बाकी चलाता है: एक शर्त जाँच हो रही है दो परिणामों में से एक है।
कई स्थितियों की जांच बार-बार देखी जा सकती है; प्रत्येक बार जब यह "शेष कार्य" चलाता है, तो यह अंतिम स्थिति तक पहुंचने तक, अगली स्थिति तक पहुंच जाता है, जो परिणाम देता है। अब, समस्या को हल करने के पहले चरण के रूप में, चलो उस संरचना का उपयोग करके चीजों को अलग कर दें - इसलिए मूल रूप से, हम अनियंत्रित स्थितियों का एक गुच्छा टुकड़ों में बदलना चाहते हैं जिन्हें हम एक बहु-सशर्त कार्य में एक साथ लिख सकते हैं। इन टुकड़ों की प्रकृति के बारे में हम क्या निष्कर्ष निकाल सकते हैं?
1) प्रत्येक टुकड़ा दो अलग-अलग प्रकारों में से एक को वापस कर सकता है; एक त्रुटि संदेश, या अगले चरण का परिणाम।
2) प्रत्येक टुकड़े को यह तय करना होगा कि अगले चरण को चलाने के लिए, तो चरणों को संयोजित करते समय हमें इसे अगले चरण को तर्क के रूप में प्रस्तुत करने की आवश्यकता होती है।
3) चूंकि प्रत्येक टुकड़ा को समान संरचना को संरक्षित करने के लिए अगला कदम दिया जाने की उम्मीद है, इसलिए हमें अंतिम, बिना शर्त कदम को एक सशर्त चरण के समान दिखने के लिए एक तरीका चाहिए।
पहली आवश्यकता स्पष्ट रूप से सुझाव देती है कि हम अपने परिणामों के लिए Either String a
जैसे प्रकार चाहते हैं। अब हमें दूसरी आवश्यकता फिट करने के लिए एक संयोजन समारोह की आवश्यकता है, और तीसरे फिट करने के लिए एक रैपिंग फ़ंक्शन की आवश्यकता है। इसके अतिरिक्त, चरणों को संयोजित करते समय, हम पिछले चरण से डेटा तक पहुंच सकते हैं (कहें, दो अलग-अलग इनपुट मान्य करना, फिर जांच कर रहे हैं कि वे बराबर हैं), इसलिए प्रत्येक चरण को पिछले चरण के परिणाम को तर्क के रूप में लेने की आवश्यकता होगी।
तो, प्रत्येक चरण err a
के प्रकार को एक शॉर्टेंड के रूप में कॉल करना, अन्य कार्यों के किस प्रकार के हो सकते हैं?
combineSteps :: err a -> (a -> err b) -> err b
wrapFinalStep :: a -> err a
ठीक है, उन प्रकार के हस्ताक्षर अजीब परिचित लगते हैं, है ना?
"एक गणना चलाने के लिए जो एक त्रुटि संदेश के साथ जल्दी विफल हो सकता है" की यह सामान्य रणनीति वास्तव में एक monadic कार्यान्वयन के लिए खुद को उधार देता है; और वास्तव में mtl package में पहले से ही एक है। अधिक महत्वपूर्ण बात यह है कि इस मामले के लिए, इसमें एक मोनड ट्रांसफॉर्मर है, जिसका अर्थ है कि आप त्रुटि मोनैड संरचना को अन्य मोनैड पर जोड़ सकते हैं - जैसे कि IO
।
तो, हम सिर्फ मॉड्यूल आयात कर सकते हैं, एक गर्म फजी ErrorT
में IO
लपेट के लिए एक प्रकार का पर्याय है, और दूर तुम जाओ:
import Control.Monad.Error
type EIO a = ErrorT String IO a
assert pred err = if pred then return() else throwError err
askUser prompt = do
liftIO $ putStr prompt
liftIO getLine
main :: IO (Either String())
main = runErrorT test
test :: EIO()
test = do
x1 <- askUser "Please enter anything but the number 5: "
assert (x1 /= "5") "Entered 5"
x2 <- askUser "Please enter a capital letter Z: "
assert (x2 == "Z") "Didn't enter Z"
x3 <- askUser "Please enter the same thing you entered for the first question: "
assert (x3 == x1) $ "Didn't enter " ++ x1
return() -- superfluous, here to make the final result more explicit
test
चल रहा है, जैसा कि आप उम्मीद करेंगे के परिणाम, सफलता के लिए Right()
या विफलता के लिए Left String
है, जहां String
उचित संदेश है; और यदि assert
विफलता लौटाता है, तो निम्न में से कोई भी कार्य नहीं किया जाएगा।
IO
कार्यों के परिणाम के परीक्षण के लिए आप assert
के लिए इसी तरह एक सहायक समारोह है कि बजाय IO Bool
का एक तर्क, या कुछ अन्य दृष्टिकोण लेता है लिखने के लिए यह सबसे आसान मिल सकता है।
इसके अलावा liftIO
के उपयोग EIO
में मूल्यों में IO
कार्यों कन्वर्ट करने के लिए, और runErrorT
एक EIO
कार्रवाई चलाने के लिए और कुल परिणाम के साथ Either String a
मान देने के लिए ध्यान दें। यदि आप अधिक जानकारी चाहते हैं तो आप monad transformers पर पढ़ सकते हैं।
बहुत अच्छा जवाब! –
मुझे त्रुटि monad प्यार करता हूँ! कंपाइलर्स में नकली त्रुटि संदेशों को घुमाने के लिए भी बहुत अच्छा .... +1 –
@ नॉर्मन रैमसे: काफी! हास्केल के साथ अपने शुरुआती रोमांच में, त्रुटियों के लिए 'या तो' का उपयोग करके पुस्तकालयों को पूरा करने पर, मैं जल्दी से 'राइट' से निकालने के लिए मूल्यों को पार करने की कठोरता से नाराज हो गया; इसलिए मैंने उन कार्यों को लिखा जो (हिंडसाइट में) लगभग 'fmap' और '(>> =)' के बराबर थे। लगभग उसी समय जब मैंने मोनैडिक संरचना को पहचानने के लिए समझ हासिल की, मैंने पाया कि 'मोनाड इरर' सभी के साथ अस्तित्व में था, और मेरे कच्चे पुनर्विचारों के लिए कुछ मूर्खतापूर्ण महसूस किया।"फैंसी" monads पर सभी झगड़े में, ऐसा लगता है कि monadic 'या तो 'और' शायद' भूल गया है ... –