इस प्रश्न को पोस्ट किए एक साल हो गया है। इसे पोस्ट करने के बाद, मैंने कुछ महीनों के लिए हास्केल में विलम्ब किया। मुझे बहुत मज़ा आया, लेकिन मैंने इसे एक तरफ रख दिया जैसे मैं मोनाड्स में तल्लीन करने के लिए तैयार था। मैं काम पर वापस चला गया और उन तकनीकों पर ध्यान केंद्रित किया जो मेरी परियोजना के लिए आवश्यक थीं।
यह बहुत अच्छा है। यह थोड़ा सार है। मैं ऐसे लोगों की कल्पना कर सकता हूं जो यह नहीं जानते कि वास्तविक उदाहरणों की कमी के कारण भिक्षु पहले से ही भ्रमित हैं।
इसलिए मुझे अनुपालन करने की कोशिश करें, और बस स्पष्ट रूप से स्पष्ट होने के लिए मैं C # में एक उदाहरण दूंगा, हालांकि यह बदसूरत दिखाई देगा। मैं अंत में समतुल्य हास्केल जोड़ूंगा और आपको शांत हास्केल सिंटैक्टिक चीनी दिखाऊंगा, जहां, आईएमओ, मोनड्स वास्तव में उपयोगी होने लगते हैं।
ठीक है, इसलिए सबसे आसान मोनड्स में से एक को हास्केल में "शायद मोनड" कहा जाता है। C # में शायद प्रकार को कहा जाता है 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
C # के लिए ऐसा करने के लिए पहले से ही समर्थन है (आप एक साथ अशक्त ints जोड़ सकते हैं और यदि आप अशक्त हैं तो आप अशक्त हो जाते हैं)। आइए दिखाते हैं कि ऐसी कोई विशेषता नहीं है, और यह केवल एक उपयोगकर्ता-परिभाषित वर्ग है जिसमें कोई विशेष जादू नहीं है। मुद्दा यह है कि हम Bind
किसी वैरिएबल को हमारे Nullable
मान की सामग्री से बाँधने के लिए फ़ंक्शन का उपयोग कर सकते हैं और फिर दिखावा कर सकते हैं कि कुछ अजीब नहीं चल रहा है, और उन्हें सामान्य ints की तरह उपयोग करें और बस उन्हें एक साथ जोड़ें। हम अंत में एक नल में परिणाम लपेट, और कहा कि नल या तो (यदि कोई अशक्त हो जाएगा 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>
इस केस के लिए C # सिंटैक्स में) और ( C # सिंटैक्स में) से एक फंक्शन होता a
है
, और यह एक
( ) रिटर्न देता है ।M b
Func<A, Nullable<B>>
M b
Nullable<B>
कोड बस जाँच करता है कि क्या अशक्त का कोई मान है और यदि वह इसे निकालता है और इसे फ़ंक्शन पर पास करता है, तो यह केवल शून्य देता है। इसका मतलब यह है कि Bind
ऑपरेटर हमारे लिए सभी शून्य-जाँच तर्क को संभाल लेगा। यदि और केवल अगर हम जिस मूल्य Bind
पर कॉल
करते हैं वह गैर-अशक्त है, तो वह मान लंबोदा फ़ंक्शन के साथ "पास" किया जाएगा, अन्यथा हम जल्दी बाहर निकलते हैं और पूरी अभिव्यक्ति शून्य है। इस कोड है कि हम इकाई का उपयोग कर लिखने के इस अशक्त की जाँच व्यवहार की पूरी तरह से मुक्त होने के लिए, हम बस का उपयोग की अनुमति देता है Bind
और एक चर monadic मूल्य के अंदर मूल्य के लिए बाध्य मिल ( 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
। और यदि आप ऐसा करते हैं, तो वे लोग भी do
संकेतन का उपयोग करने में सक्षम होंगे , जिसका अर्थ है कि आप मूल रूप से केवल दो कार्यों को परिभाषित करके अपनी छोटी भाषाएं लिख सकते हैं!