यह एक साल हो गया है जब से मैंने यह प्रश्न पोस्ट किया था। इसे पोस्ट करने के बाद, मैं कुछ महीनों के लिए हास्केल में पहुंचा। मैंने इसे बहुत मज़ा आया, लेकिन मैंने इसे अलग रखा क्योंकि मैं मोनाड्स में जाने के लिए तैयार था।मैं काम पर वापस गया और मेरी परियोजना की आवश्यक प्रौद्योगिकियों पर ध्यान केंद्रित किया।
और कल रात, मैं आया और इन प्रतिक्रियाओं को फिर से पढ़ा। सबसे महत्वपूर्ण, मैं the Brian Beckman video किसी mentions above की टेक्स्ट टिप्पणियों में the specific C# example दोबारा पढ़ता हूं। यह इतना स्पष्ट और रोशनी था कि मैंने इसे सीधे यहां पोस्ट करने का निर्णय लिया है।
इस टिप्पणी की वजह से
, न केवल मुझे लगता है कि मैं ठीक से समझ क्या monads रहे हैं ... मुझे लगता है मैं वास्तव में सी # में कुछ बातें लिखा है कि monads ... या कम से कम बहुत करीब है, और करने के लिए प्रयास एक ही समस्या को हल करें।
तो, यहाँ टिप्पणी है - इस sylvan द्वारा the comment here से सभी एक सीधा उद्धरण है:
यह बहुत अच्छा है। हालांकि यह थोड़ा सा सार है। मैं उन लोगों की कल्पना कर सकता हूं जो असली उदाहरणों की कमी के कारण पहले से ही मोनैड उलझन में नहीं आते हैं।
तो मुझे अनुपालन करने की कोशिश करें, और वास्तव में स्पष्ट होने के लिए मैं सी # में एक उदाहरण करूंगा, भले ही यह बदसूरत लगेगा। मैं अंत में समकक्ष हास्केल जोड़ूंगा और आपको ठंडा हास्केल सिंटैक्टिक चीनी दिखाऊंगा, जहां आईएमओ, मोनैड वास्तव में उपयोगी हो जाना शुरू कर देते हैं।
ठीक है, तो सबसे आसान मोनाड्स में से एक को हास्केल में "शायद मोनैड" कहा जाता है। सी # में शायद Nullable<T>
कहा जाता है। यह मूल रूप से एक छोटी कक्षा है जो केवल उस मान की अवधारणा को समाहित करती है जो वैध है और उसके पास मूल्य है, या "शून्य" है और इसका कोई मूल्य नहीं है।
इस प्रकार के मूल्यों के संयोजन के लिए एक मोनैड के अंदर चिपकने के लिए एक उपयोगी चीज विफलता की धारणा है। अर्थात। हम कई शून्य मूल्यों को देखने में सक्षम होना चाहते हैं और जैसे ही उनमें से कोई भी शून्य है, null
लौटाएं। यह उपयोगी हो सकता है यदि आप, उदाहरण के लिए, किसी शब्दकोश या कुछ में बहुत सी कुंजी देखते हैं, और अंत में आप सभी परिणामों को संसाधित करना चाहते हैं और उन्हें किसी भी तरह गठबंधन करना चाहते हैं, लेकिन यदि कोई भी कुंजी शब्दकोश में नहीं है, आप पूरी चीज के लिए null
वापस करना चाहते हैं। null
के लिए प्रत्येक लुकअप को मैन्युअल रूप से जांचना और वापस लौटना मुश्किल होगा, इसलिए हम इस जांच को बाइंड ऑपरेटर के अंदर छिपा सकते हैं (जो मोनैड के बिंदु की तरह है, हम बांध ऑपरेटर में पुस्तक-रख-रखाव को छिपाते हैं जो कोड को आसान बनाता है उपयोग करने के लिए हम विवरण के बारे में भूल सकते हैं)।
यहां वह प्रोग्राम है जो पूरी चीज को प्रेरित करता है (मैं Bind
बाद में परिभाषित करूंगा, यह सिर्फ आपको यह दिखाने के लिए है कि यह अच्छा क्यों है)।
class Program
{
static Nullable<int> f(){ return 4; }
static Nullable<int> g(){ return 7; }
static Nullable<int> h(){ return 9; }
static void Main(string[] args)
{
Nullable<int> z =
f().Bind(fval =>
g().Bind(gval =>
h().Bind(hval =>
new Nullable<int>(fval + gval + hval))));
Console.WriteLine(
"z = {0}", z.HasValue ? z.Value.ToString() : "null");
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
अब, एक पल है कि वहाँ पहले से ही सी # में Nullable
के लिए यह कर (आप नल ints एक साथ जोड़ सकते हैं और आप अशक्त प्राप्त करता है, तो या तो शून्य है) के लिए समर्थन है के लिए ध्यान न दें। आइए दिखाएं कि ऐसी कोई सुविधा नहीं है, और यह केवल एक उपयोगकर्ता द्वारा परिभाषित कक्षा है जिसमें कोई विशेष जादू नहीं है। मुद्दा यह है कि हम Bind
फ़ंक्शन का उपयोग हमारे Nullable
मान की सामग्री में एक चर को बाध्य करने के लिए कर सकते हैं और फिर दिखा सकते हैं कि कुछ भी अजीब नहीं चल रहा है, और सामान्य इनट्स की तरह उनका उपयोग करें और उन्हें एक साथ जोड़ें। हम परिणाम को अंत में एक नाली में लपेटते हैं, और यह शून्य या तो शून्य हो जाएगा (f
, g
या h
शून्य लौटाता है) या यह f
, g
, और h
को एक साथ जोड़ने का परिणाम होगा। (यह समान है कि हम LINQ में एक चर के लिए डेटाबेस में एक पंक्ति को कैसे बांध सकते हैं, और इसके साथ सामान करते हैं, इस ज्ञान में सुरक्षित है कि Bind
ऑपरेटर यह सुनिश्चित करेगा कि चर केवल वैध पंक्ति मानों को पारित किया जाएगा)।
आप इसके साथ खेल सकते हैं और f
, g
, और h
में से कोई भी वापस लौटने के लिए बदल सकते हैं और आप देखेंगे कि पूरी चीज शून्य हो जाएगी।
तो स्पष्ट रूप से बाइंड ऑपरेटर को हमारे लिए यह जांच करना पड़ता है, और अगर यह शून्य मूल्य का सामना करता है तो वापस लौटता है, और अन्यथा Nullable
संरचना के अंदर लैम्ब्डा में मूल्य के साथ गुजरता है।
यहाँ Bind
ऑपरेटर है:
public static Nullable<B> Bind<A,B>(this Nullable<A> a, Func<A,Nullable<B>> f)
where B : struct
where A : struct
{
return a.HasValue ? f(a.Value) : null;
}
यहाँ प्रकार सिर्फ वीडियो में की तरह हैं। यह एक M a
(इस मामले के लिए Nullable<A>
सी में # वाक्य रचना), और (सी # वाक्य रचना में Func<A, Nullable<B>>
) M b
को a
से एक समारोह लेता है, और यह देता है एक M b
(Nullable<B>
)।
कोड बस जांचता है कि क्या शून्य में कोई मान होता है और यदि ऐसा होता है तो इसे निष्पादित करता है और इसे फ़ंक्शन पर पास करता है, अन्यथा यह शून्य हो जाता है। इसका मतलब है कि Bind
ऑपरेटर हमारे लिए सभी शून्य-जांच तर्क को संभालेगा। अगर और केवल तभी मूल्य जिसे हम Bind
पर कॉल करते हैं, तो गैर-शून्य है तो वह मान लैम्ब्डा फ़ंक्शन में "साथ में" जाएगा, अन्यथा हम जल्दी से जमानत कर लेंगे और पूरी अभिव्यक्ति शून्य होगी। यह कोड को हम इस नल-जांच व्यवहार से पूरी तरह मुक्त होने के लिए मोनैड का उपयोग करके लिखते हैं, हम केवल Bind
का उपयोग करते हैं और उदाहरण कोड में मोनैडिक मान (fval
, gval
और hval
) के अंदर मान को एक चर से प्राप्त करते हैं। हम उन्हें ज्ञान में सुरक्षित उपयोग कर सकते हैं कि Bind
उन्हें पास करने से पहले उन्हें शून्य के लिए जांचने का ख्याल रखेगा।
चीजों के अन्य उदाहरण हैं जो आप एक मोनड के साथ कर सकते हैं। उदाहरण के लिए आप Bind
ऑपरेटर को वर्णों की इनपुट स्ट्रीम का ख्याल रख सकते हैं, और पार्सर संयोजक लिखने के लिए इसका उपयोग कर सकते हैं। प्रत्येक पार्सर संयोजक बैक-ट्रैकिंग, पार्सर विफलताओं इत्यादि जैसी चीजों से पूरी तरह से अनजान हो सकता है, और केवल छोटे पार्सर्स को एक साथ जोड़ता है जैसे कि चीजें कभी गलत नहीं होतीं, ज्ञान में सुरक्षित है कि Bind
का एक चालाक कार्यान्वयन पीछे सभी तर्कों को दिखाता है मुश्किल बिट्स। फिर बाद में शायद कोई मोनैड पर लॉगिंग जोड़ता है, लेकिन मोनैड का उपयोग करने वाला कोड बदलता नहीं है, क्योंकि सभी जादू Bind
ऑपरेटर की परिभाषा में होता है, शेष कोड अपरिवर्तित होता है।
अंत में, यहां हास्केल (--
) में एक ही कोड का कार्यान्वयन एक टिप्पणी पंक्ति शुरू होता है)।
-- Here's the data type, it's either nothing, or "Just" a value
-- this is in the standard library
data Maybe a = Nothing | Just a
-- The bind operator for Nothing
Nothing >>= f = Nothing
-- The bind operator for Just x
Just x >>= f = f x
-- the "unit", called "return"
return = Just
-- The sample code using the lambda syntax
-- that Brian showed
z = f >>= (\fval ->
g >>= (\gval ->
h >>= (\hval -> return (fval+gval+hval))))
-- The following is exactly the same as the three lines above
z2 = do
fval <- f
gval <- g
hval <- h
return (fval+gval+hval)
आप देख सकते हैं अंत में अच्छा do
अंकन यह सीधे जरूरी कोड की तरह लग रहे बनाता है। और वास्तव में यह डिजाइन द्वारा है। मोनैड का उपयोग अनिवार्य प्रोग्रामिंग (म्यूटेबल स्टेटस, आईओ इत्यादि) में सभी उपयोगी चीजों को समाहित करने के लिए किया जा सकता है और इस अच्छे अनिवार्य सिंटैक्स का उपयोग करके किया जाता है, लेकिन पर्दे के पीछे, यह सिर्फ मोनैड और बाइंड ऑपरेटर का चालाक कार्यान्वयन है! अच्छी बात यह है कि आप >>=
और return
को लागू करके अपने स्वयं के मोनैड को कार्यान्वित कर सकते हैं। और यदि आप ऐसा करते हैं तो वे monads भी do
नोटेशन का उपयोग करने में सक्षम होंगे, जिसका अर्थ है कि आप मूल रूप से दो कार्यों को परिभाषित करके अपनी छोटी भाषाएं लिख सकते हैं!
कृपया ध्यान दें कि यह वास्तव में एक सी # 3.0 डेवलपर है। इसे .NET 3.5 के साथ गलती मत करो। इसके अलावा, अच्छा सवाल है। – Razzie
यह इंगित करने लायक है कि LINQ क्वेरी एक्सप्रेशन सी # 3. –
में मैनाडिक व्यवहार का एक उदाहरण है, मुझे अभी भी लगता है कि यह एक डुप्लिकेट प्रश्न है। Http://stackoverflow.com/questions/2366/can-anyone-explain-monads में जवाबों में से एक http://channel9vip.orcsweb.com/shows/Going+Deep/Brian-Beckman-Dont-fear- द मोनाड्स /, जहां टिप्पणियों में से एक बहुत अच्छा सी # उदाहरण है। :) – jalf