दृश्य # 1 और # 2 सामान्य रूप से गलत हैं।
- किसी भी प्रकार का डेटा-
* -> *लेबल लेबल के रूप में काम कर सकता है, मोनैड्स इससे कहीं अधिक हैं।
- (
IOमोनाड के अपवाद के साथ ) एक सन्यासी के भीतर गणना अशुद्ध नहीं है। वे केवल उन संगणनाओं का प्रतिनिधित्व करते हैं जिन्हें हम साइड इफेक्ट्स के रूप में देखते हैं, लेकिन वे शुद्ध हैं।
ये दोनों गलतफहमी IOमोनाड पर ध्यान केंद्रित करने से आती हैं , जो वास्तव में थोड़ा खास है।
यदि संभव हो तो श्रेणी सिद्धांत में शामिल किए बिना, मैं # 3 पर थोड़ा विस्तार करने की कोशिश करूंगा।
मानक अभिकलन
एक कार्यात्मक प्रोग्रामिंग भाषा में सभी संगणना को स्रोत प्रकार और लक्ष्य प्रकार के साथ कार्यों के रूप में देखा जा सकता है f :: a -> b:। यदि किसी फ़ंक्शन में एक से अधिक तर्क हैं, तो हम इसे करीने से एक-तर्क फ़ंक्शन में बदल सकते हैं ( हास्केल विकी भी देखें )। और अगर हम सिर्फ एक मूल्य है x :: a(0 तर्क के साथ एक समारोह), हम इसे एक समारोह है कि का एक तर्क लेता है में बदल सकते हैं इकाई प्रकार : (\_ -> x) :: () -> a।
हम .ऑपरेटर का उपयोग करके इस तरह के कार्यों की रचना करके अधिक जटिल कार्यक्रमों को सरल बना सकते हैं । उदाहरण के लिए, यदि हमारे पास है f :: a -> bऔर g :: b -> cहम प्राप्त करते हैं g . f :: a -> c। ध्यान दें कि यह हमारे रूपांतरित मूल्यों के लिए भी काम करता है: यदि हमारे पास है x :: aऔर इसे हमारे प्रतिनिधित्व में बदल देता है, तो हम प्राप्त करते हैं f . ((\_ -> x) :: () -> a) :: () -> b।
इस प्रतिनिधित्व के कुछ बहुत महत्वपूर्ण गुण हैं, अर्थात्:
- हमारे पास एक विशेष कार्य है - प्रत्येक प्रकार के लिए पहचान समारोह । यह सम्मान के साथ एक पहचान तत्व है : दोनों के लिए और बराबर है ।
id :: a -> aa.ff . idid . f
- समारोह रचना ऑपरेटर
.है साहचर्य ।
मोनडिक संगणनाएँ
मान लीजिए कि हम कुछ विशेष श्रेणी की संगणनाओं के साथ चयन और काम करना चाहते हैं, जिनके परिणाम में केवल एकल रिटर्न मान से अधिक कुछ है। हम निर्दिष्ट नहीं करना चाहते हैं कि "कुछ और" का क्या मतलब है, हम चीजों को यथासंभव सामान्य रखना चाहते हैं। "कुछ और" का प्रतिनिधित्व करने का सबसे सामान्य तरीका एक प्रकार के फ़ंक्शन के रूप में प्रतिनिधित्व कर रहा है - एक प्रकार mका * -> *(यानी यह एक प्रकार को दूसरे में परिवर्तित करता है)। इसलिए प्रत्येक श्रेणी की संगणना के लिए, जिसके साथ हम काम करना चाहते हैं, हमारे पास कुछ प्रकार के कार्य होंगे m :: * -> *। (में हास्केल, mहै [], IO, Maybe, आदि) और श्रेणी इच्छा प्रकार के सभी कार्यों में शामिल है a -> m b।
अब हम इस तरह की श्रेणी में कार्यों के साथ उसी तरह काम करना चाहेंगे जैसे कि मूल मामले में। हम इन कार्यों की रचना करने में सक्षम होना चाहते हैं, हम चाहते हैं कि रचना सहयोगी हो, और हम एक पहचान बनाना चाहते हैं। ज़रुरत है:
- एक ऑपरेटर के लिए (चलो इसे कॉल करें
<=<) जो फ़ंक्शन f :: a -> m bऔर g :: b -> m cकुछ के रूप में रचना करता है g <=< f :: a -> m c। और, यह सहयोगी होना चाहिए।
- प्रत्येक प्रकार के लिए कुछ पहचान कार्य करने के लिए, आइए इसे कॉल करें
return। हम भी चाहते हैं कि f <=< returnजैसा fऔर जैसा है, वैसा ही हो return <=< f।
कोई भी m :: * -> *जिसके लिए हमारे पास ऐसे कार्य हैं returnऔर <=<उसे एक मोनाड कहा जाता है । यह हमें सरल मामलों से जटिल गणनाएँ बनाने की अनुमति देता है, जैसे कि मूल मामले में, लेकिन अब रिटर्न वैल्यूज़ के प्रकारों को बदल दिया जाता है m।
(वास्तव में, मैंने यहां शब्द श्रेणी का थोड़ा दुरुपयोग किया है। श्रेणी-सिद्धांत अर्थ में हम अपने निर्माण को एक श्रेणी कह सकते हैं, जब हम जानते हैं कि यह इन कानूनों का पालन करता है।)
हास्केल में मठ
हास्केल (और अन्य कार्यात्मक भाषाओं) में हम ज्यादातर मूल्यों के साथ काम करते हैं, न कि प्रकारों के कार्यों के साथ () -> a। इसलिए <=<प्रत्येक मोनाड को परिभाषित करने के बजाय , हम एक फ़ंक्शन को परिभाषित करते हैं (>>=) :: m a -> (a -> m b) -> m b। ऐसी वैकल्पिक परिभाषा समतुल्य है, हम इसका >>=उपयोग <=<और इसके विपरीत व्यक्त कर सकते हैं (एक अभ्यास के रूप में प्रयास करें, या स्रोतों को देखें )। सिद्धांत अब कम स्पष्ट है, लेकिन यह समान है: हमारे परिणाम हमेशा प्रकार के होते हैं m aऔर हम प्रकारों के कार्यों की रचना करते हैं a -> m b।
हमारे द्वारा बनाए गए प्रत्येक मोनाड के लिए, हमें यह जांचना नहीं भूलना चाहिए returnऔर हमारे <=<पास आवश्यक गुण हैं: सहानुभूति और बाएं / दाएं पहचान। का उपयोग करके व्यक्त किया गया returnऔर >>=उन्हें मोनाड कानून कहा जाता है ।
एक उदाहरण - सूचियाँ
यदि हम mहोना चुनते हैं [], तो हमें प्रकार के कार्यों की एक श्रेणी मिलती है a -> [b]। ऐसे कार्य गैर-नियतात्मक संगणनाओं का प्रतिनिधित्व करते हैं, जिनके परिणाम एक या अधिक मूल्य हो सकते हैं, लेकिन यह भी कोई मूल्य नहीं है। यह तथाकथित सूची मोनाद को जन्म देता है । की संरचना f :: a -> [b]और g :: b -> [c]निम्नानुसार काम करती है: प्रकार के g <=< f :: a -> [c]सभी संभावित परिणामों की गणना करने का मतलब है [b], gउनमें से प्रत्येक पर लागू होता है, और सभी परिणामों को एक सूची में इकट्ठा करता है। हास्केल में व्यक्त किया
return :: a -> [a]
return x = [x]
(<=<) :: (b -> [c]) -> (a -> [b]) -> (a -> [c])
g (<=<) f = concat . map g . f
या उपयोग कर रहा है >>=
(>>=) :: [a] -> (a -> [b]) -> [b]
x >>= f = concat (map f x)
ध्यान दें कि इस उदाहरण में रिटर्न प्रकार इस प्रकार थे [a]कि यह संभव था कि उनके पास किसी प्रकार का मूल्य न हो a। वास्तव में, एक सन्यासी के लिए ऐसी कोई आवश्यकता नहीं होती है कि रिटर्न प्रकार में ऐसे मान होने चाहिए। कुछ साधुओं के पास हमेशा (जैसे IOया State) होते हैं, लेकिन कुछ पसंद नहीं करते हैं []या जैसे होते हैं Maybe।
आईओ मोनद
जैसा कि मैंने उल्लेख किया है, IOसन्यासी कुछ विशेष है। प्रकार के मूल्य का IO aअर्थ है aकार्यक्रम के वातावरण के साथ बातचीत करके निर्मित प्रकार का मूल्य । इसलिए (सभी अन्य साधुओं के विपरीत), हम IO aकुछ शुद्ध निर्माण का उपयोग करके प्रकार के मूल्य का वर्णन नहीं कर सकते हैं । यहां IOकेवल एक टैग या एक लेबल है जो पर्यावरण के साथ बातचीत करने वाले कम्प्यूटेशंस को अलग करता है। यह (एकमात्र मामला) है जहां विचार # 1 और # 2 सही हैं।
के लिए IOइकाई:
- संरचना
f :: a -> IO bऔर g :: b -> IO cसाधन: गणना fजो पर्यावरण के साथ सहभागिता करता है, और फिर गणना gकरता है जो मूल्य का उपयोग करता है और पर्यावरण के साथ बातचीत करने वाले परिणाम की गणना करता है।
returnबस IO"टैग" को मूल्य में जोड़ता है (हम पर्यावरण को बरकरार रखते हुए परिणाम को "गणना" करते हैं)।
- संन्यासी द्वारा मोनाड कानूनों (संघात्मकता, पहचान) की गारंटी दी जाती है।
कुछ नोट:
- चूंकि मोनाडिक अभिकलन में हमेशा परिणाम प्रकार होता है
m a, इसलिए कोई तरीका नहीं है कि कैसे IOमोनाड से "बच" जाए । अर्थ यह है: एक बार एक संगणना पर्यावरण के साथ सहभागिता करती है, आप उससे एक अभिकलन का निर्माण नहीं कर सकते।
- जब एक कार्यात्मक प्रोग्रामर कुछ नहीं जानता कि कैसे शुद्ध तरीके से कुछ बनाना है, तो वह ( अंतिम उपाय के रूप में )
IOमोनाड के भीतर कुछ स्टेटफुल कम्प्यूटेशन द्वारा कार्य को कर सकता है । यही कारण है कि IOअक्सर एक प्रोग्रामर के पाप बिन कहा जाता है ।
- ध्यान दें कि एक अशुद्ध दुनिया में (कार्यात्मक प्रोग्रामिंग के अर्थ में) एक मान पढ़ने से पर्यावरण भी बदल सकता है (जैसे उपयोगकर्ता के इनपुट का उपभोग करना)। इसीलिए जैसे कार्यों
getCharका एक परिणाम प्रकार होना चाहिए IO something।