सादे अंग्रेजी में मोनाद? (बिना FP पृष्ठभूमि वाले OOP प्रोग्रामर के लिए)


743

इस संदर्भ में कि एक OOP प्रोग्रामर (किसी भी कार्यात्मक प्रोग्रामिंग पृष्ठभूमि के बिना) को समझेगा, एक सन्यासी क्या है?

यह किस समस्या को हल करता है और इसका उपयोग करने वाले सबसे आम स्थान क्या हैं?

संपादित करें:

यह समझने के लिए कि मैं किस प्रकार की समझ की तलाश कर रहा था, मान लीजिए कि आप एक एफपी एप्लिकेशन को परिवर्तित कर रहे थे जिसमें एक ओओपी एप्लिकेशन में मोनड था। आप भिक्षुओं की जिम्मेदारियों को OOP ऐप में पोर्ट करने के लिए क्या करेंगे?


10
यह ब्लॉग पोस्ट बहुत अच्छी है: blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html
पास्कल क्यूक


10
@Pavel: इस सवाल का जवाब हम एरिक से नीचे मिल गया है है बहुत उन अन्य में लोगों को सुझाव दिया क्यू के एक OO पृष्ठभूमि के साथ लोगों के लिए (के रूप में एक एफपी पृष्ठभूमि के खिलाफ) के लिए की तुलना में बेहतर।
डोनल फैलो

5
@Donal: इस तो है एक शिकार (जिसके बारे में मैं कोई राय नहीं है), अच्छा जवाब मूल में जोड़ा जाना चाहिए। यह है: एक अच्छा जवाब एक डुप्लिकेट के रूप में समापन को रोकता नहीं है। यदि यह एक करीबी पर्याप्त डुप्लिकेट है, तो यह एक मध्यस्थ द्वारा एक मध्यस्थ द्वारा पूरा किया जा सकता है।
dmckee --- पूर्व-मध्यस्थ ने बिल्ली का बच्चा

3
इन्हें भी देखें: stackoverflow.com/questions/674855/…
sth

जवाबों:


732

अद्यतन: यह सवाल एक बहुत लंबे ब्लॉग श्रृंखला का विषय था, जिसे आप मोनाड्स में पढ़ सकते हैं - महान प्रश्न के लिए धन्यवाद!

इस संदर्भ में कि एक OOP प्रोग्रामर (किसी भी कार्यात्मक प्रोग्रामिंग पृष्ठभूमि के बिना) को समझेगा, एक सन्यासी क्या है?

एक इकाई के एक है प्रकार के "एम्पलीफायर" कि कुछ नियमों का अनुसरण करता है और जो उपलब्ध कराए गए कुछ कार्य किया है

पहला, "प्रकारों का प्रवर्धक" क्या है? उसके द्वारा मेरा मतलब है कुछ सिस्टम जो आपको एक प्रकार लेने देता है और इसे और अधिक विशेष प्रकार में बदल देता है। उदाहरण के लिए, C # पर विचार करें Nullable<T>। यह एक प्रकार का एम्पलीफायर है। यह आपको एक प्रकार लेने, कहने int, और उस प्रकार की एक नई क्षमता जोड़ने की अनुमति देता है , अर्थात्, अब यह शून्य हो सकता है जब यह पहले नहीं कर सकता था।

दूसरे उदाहरण के रूप में, विचार करें IEnumerable<T>। यह एक प्रकार का एम्पलीफायर है। यह आपको एक प्रकार लेने, कहने stringऔर उस प्रकार की एक नई क्षमता जोड़ने देता है, अर्थात्, अब आप किसी भी संख्या में एकल स्ट्रिंग्स से एक क्रम बना सकते हैं।

"कुछ नियम" क्या हैं? संक्षेप में, कि प्रवर्धित प्रकार पर काम करने के लिए अंतर्निहित प्रकार के कार्यों के लिए एक समझदार तरीका है जैसे कि वे कार्यात्मक रचना के सामान्य नियमों का पालन करते हैं। उदाहरण के लिए, यदि आपके पास पूर्णांकों पर एक फ़ंक्शन है, तो कहें

int M(int x) { return x + N(x * 2); }

तब संबंधित कार्य Nullable<int>सभी ऑपरेटर और कॉल को एक साथ "उसी तरह से" काम कर सकते हैं जो उन्होंने पहले किया था।

(यह अविश्वसनीय रूप से अस्पष्ट और अभेद्य है; आपने एक स्पष्टीकरण के लिए कहा जो कार्यात्मक रचना के ज्ञान के बारे में कुछ भी नहीं मानता है।)

"ऑपरेशन" क्या हैं?

  1. एक "यूनिट" ऑपरेशन है (भ्रामक रूप से कभी-कभी "रिटर्न" ऑपरेशन कहा जाता है) जो एक सादे प्रकार से एक मूल्य लेता है और समतुल्य मानद मूल्य बनाता है। यह, संक्षेप में, एक असंबद्ध प्रकार के मूल्य को लेने और प्रवर्धित प्रकार के मूल्य में बदलने का एक तरीका प्रदान करता है। इसे एक ओओ भाषा में एक निर्माता के रूप में लागू किया जा सकता है।

  2. एक "बाइंड" ऑपरेशन है जो एक मानदंड और एक फ़ंक्शन लेता है जो मान को बदल सकता है, और एक नया मानदंड लौटा सकता है। बिंद एक महत्वपूर्ण ऑपरेशन है जो मोनाड के शब्दार्थ को परिभाषित करता है। यह हमें प्रवर्धित प्रकार के संचालन में असंबद्ध प्रकार पर परिचालनों को बदलने देता है, जो पहले बताई गई कार्यात्मक रचना के नियमों का पालन करता है।

  3. अघोषित प्रकार को वापस प्रवर्धित प्रकार से प्राप्त करने का एक तरीका है। कड़ाई से इस ऑपरेशन को बोलने के लिए एक साधु की आवश्यकता नहीं है। (हालांकि यह आवश्यक है यदि आप एक कोमोनॉड करना चाहते हैं । हम इस लेख में आगे उन पर विचार नहीं करेंगे।)

फिर से, Nullable<T>एक उदाहरण के रूप में लेते हैं । आप कंस्ट्रक्टर के साथ intएक मोड़ सकते हैं Nullable<int>। सी # कंपाइलर आपके लिए सबसे अधिक अशक्त "उठाने" का ख्याल रखता है, लेकिन अगर ऐसा नहीं हुआ, तो उठाने वाला परिवर्तन सीधा है: एक ऑपरेशन, कहते हैं,

int M(int x) { whatever }

में तब्दील हो गया है

Nullable<int> M(Nullable<int> x) 
{ 
    if (x == null) 
        return null; 
    else 
        return new Nullable<int>(whatever);
}

और एक में Nullable<int>वापस मुड़कर संपत्ति के intसाथ किया जाता है Value

यह फ़ंक्शन परिवर्तन है जो कुंजी बिट है। ध्यान दें कि कैसे अशक्त ऑपरेशन के वास्तविक शब्दार्थ - कि nullप्रचार पर एक ऑपरेशन null- परिवर्तन में कैप्चर किया गया है। हम इसे सामान्य कर सकते हैं।

मान लीजिए आप से एक समारोह है intकरने के लिए int, हमारे मूल की तरह M। आप इसे आसानी से एक फंक्शन में बना सकते हैं जो एक लेता है intऔर एक रिटर्न देता है Nullable<int>क्योंकि आप परिणाम को केवल अशक्त कंस्ट्रक्टर के माध्यम से चला सकते हैं। अब मान लें कि आपके पास यह उच्च-क्रम विधि है:

static Nullable<T> Bind<T>(Nullable<T> amplified, Func<T, Nullable<T>> func)
{
    if (amplified == null) 
        return null;
    else
        return func(amplified.Value);
}

देखें कि आप इसके साथ क्या कर सकते हैं? कोई भी विधि जो एक लेती है intऔर एक रिटर्न देती है int, या एक लेती है intऔर Nullable<int>कर सकती है अब उस पर लागू होने योग्य अशक्त शब्दार्थ हो सकती है

इसके अलावा: मान लीजिए कि आपके पास दो तरीके हैं

Nullable<int> X(int q) { ... }
Nullable<int> Y(int r) { ... }

और आप उनकी रचना करना चाहते हैं:

Nullable<int> Z(int s) { return X(Y(s)); }

वह है, Zकी रचना है Xऔर Y। लेकिन आप ऐसा नहीं कर सकते , क्योंकि ए और रिटर्न Xलेता है । लेकिन चूंकि आपके पास "बाइंड" ऑपरेशन है, इसलिए आप यह काम कर सकते हैं:intYNullable<int>

Nullable<int> Z(int s) { return Bind(Y(s), X); }

एक मोनाड पर बाँध संचालन वह है जो प्रवर्धित प्रकार के कार्यों पर रचना करता है। उपरोक्त नियमों के बारे में मैंने जो "नियम" बताए हैं वे यह हैं कि सनक सामान्य रचना के नियमों को बनाए रखती है; पहचान फ़ंक्शन के साथ रचना करने के परिणामस्वरूप मूल फ़ंक्शन होता है, यह रचना सहयोगी होती है, और इसी तरह।

C # में, "Bind" को "SelectMany" कहा जाता है। एक नज़र डालें कि यह अनुक्रम मोनाड पर कैसे काम करता है। हमें दो चीजें करने की जरूरत है: एक मूल्य को एक अनुक्रम में बदल दें और अनुक्रमों पर परिचालन को बांधें। एक बोनस के रूप में, हमारे पास "एक अनुक्रम को वापस एक मूल्य में बदलना" है। वे ऑपरेशन हैं:

static IEnumerable<T> MakeSequence<T>(T item)
{
    yield return item;
}
// Extract a value
static T First<T>(IEnumerable<T> sequence)
{
    // let's just take the first one
    foreach(T item in sequence) return item; 
    throw new Exception("No first item");
}
// "Bind" is called "SelectMany"
static IEnumerable<T> SelectMany<T>(IEnumerable<T> seq, Func<T, IEnumerable<T>> func)
{
    foreach(T item in seq)
        foreach(T result in func(item))
            yield return result;            
}

अशक्त मोनड नियम था "दो कार्यों को संयोजित करने के लिए जो एक साथ अशक्त उत्पन्न करते हैं, यह देखने के लिए जांचें कि क्या अशक्त में आंतरिक एक है; यदि यह करता है, अशक्त उत्पन्न करता है, यदि ऐसा नहीं करता है, तो परिणाम के साथ बाहरी को कॉल करें"। यह अशक्त का वांछित शब्दार्थ है।

अनुक्रम मोनड नियम है "दो कार्यों को संयोजित करने के लिए जो एक साथ दृश्यों का उत्पादन करते हैं, आंतरिक फ़ंक्शन द्वारा उत्पादित प्रत्येक तत्व के लिए बाहरी फ़ंक्शन को लागू करते हैं, और फिर सभी परिणामी अनुक्रमों को एक साथ जोड़ते हैं"। भिक्षुओं के मौलिक शब्दार्थ Bind/ SelectManyतरीकों पर कब्जा कर लिया गया है ; यह वह विधि है जो आपको बताती है कि वास्तव में सन्यासी का क्या अर्थ है

हम और भी बेहतर कर सकते हैं। मान लीजिए कि आपके पास ints का एक क्रम है, और एक तरीका है जो ints लेता है और तार के दृश्यों में परिणाम करता है। हम अलग-अलग प्रवर्धित प्रकारों को लेने और वापस करने वाले कार्यों की संरचना की अनुमति देने के लिए बाध्यकारी संचालन को सामान्य कर सकते हैं, जब तक कि एक के इनपुट दूसरे के आउटपुट से मेल खाते हैं:

static IEnumerable<U> SelectMany<T,U>(IEnumerable<T> seq, Func<T, IEnumerable<U>> func)
{
    foreach(T item in seq)
        foreach(U result in func(item))
            yield return result;            
}

तो अब हम कह सकते हैं "अलग-अलग पूर्णांकों के इस गुच्छा को पूर्णांकों के अनुक्रम में बढ़ाएँ। इस विशेष पूर्णांक को तारों के एक समूह में परिवर्तित करें। इसे तारों के अनुक्रम में प्रवर्धित किया गया है। अब दोनों ऑपरेशनों को एक साथ करें: पूर्णांक के इस गुच्छा को पूर्णांक के आयाम में बदलें। तार के सभी दृश्यों। " मोनाड्स आपको अपने प्रवर्धन की रचना करने की अनुमति देते हैं ।

यह किस समस्या को हल करता है और इसका उपयोग करने वाले सबसे आम स्थान क्या हैं?

इसके बजाय यह पूछना कि "सिंगलटन पैटर्न क्या समस्याएं हल करता है?", लेकिन मैं इसे एक शॉट दूंगा।

आमतौर पर समस्याओं को हल करने के लिए मोनाड्स का उपयोग किया जाता है:

  • मुझे इस प्रकार के लिए नई क्षमताएं बनाने की आवश्यकता है और फिर भी नई क्षमताओं का उपयोग करने के लिए इस प्रकार के पुराने कार्यों को संयोजित करें।
  • मुझे प्रकारों पर संचालन का एक गुच्छा कैप्चर करना होगा और उन परिचालनों को संयोजनीय वस्तुओं के रूप में प्रस्तुत करना होगा, बड़ी और बड़ी रचनाओं का निर्माण करना जब तक कि मेरे पास केवल सही श्रृंखलाओं का प्रतिनिधित्व नहीं है, और फिर मुझे उस चीज़ से परिणाम प्राप्त करना शुरू करना होगा।
  • मुझे साइड इफ़ेक्ट संचालन को एक ऐसी भाषा में साफ-सुथरे ढंग से प्रस्तुत करने की आवश्यकता है जो साइड इफेक्ट्स से नफरत करती है

C # अपने डिज़ाइन में मोनड्स का उपयोग करता है। जैसा कि पहले ही उल्लेख किया गया है, अशक्त पैटर्न "शायद सनक" के समान है। LINQ पूरी तरह से मठों से बाहर बनाया गया है; SelectManyविधि संचालन की संरचना का अर्थ काम करता है क्या है। (एरिक मीजर यह संकेत देने का पक्षधर है कि हर LINQ फ़ंक्शन वास्तव में लागू किया जा सकता है SelectMany; बाकी सब सिर्फ एक सुविधा है।)

यह समझने के लिए कि मैं किस प्रकार की समझ की तलाश कर रहा था, मान लीजिए कि आप एक एफपी एप्लिकेशन को परिवर्तित कर रहे थे जिसमें एक ओओपी एप्लिकेशन में मोनड था। आप OOP ऐप में भिक्षुओं की जिम्मेदारियों को पोर्ट करने के लिए क्या करेंगे?

अधिकांश ओओपी भाषाओं में सीधे तौर पर मोनाड पैटर्न का प्रतिनिधित्व करने के लिए एक समृद्ध पर्याप्त प्रकार की व्यवस्था नहीं है; आपको एक प्रकार की प्रणाली की आवश्यकता है जो सामान्य प्रकारों की तुलना में उच्च प्रकारों का समर्थन करती हो। इसलिए मैं ऐसा करने की कोशिश नहीं करूंगा। इसके बजाय, मैं जेनेरिक प्रकारों को लागू करूँगा जो प्रत्येक मोनड का प्रतिनिधित्व करते हैं, और उन तरीकों को लागू करते हैं जो आपको आवश्यक तीन कार्यों का प्रतिनिधित्व करते हैं: एक मान को एक प्रवर्धित मान में बदलना, (हो सकता है) एक प्रवर्धित मान को एक मान में बदलना, और एक फ़ंक्शन को असंबद्ध मानों में बदलना। प्रवर्धित मूल्यों पर एक समारोह।

शुरू करने के लिए एक अच्छी जगह यह है कि हमने C # में LINQ कैसे लागू किया। SelectManyविधि का अध्ययन करें ; यह समझने की कुंजी है कि सीना में सीक्वेंस कैसे काम करता है। यह एक बहुत ही सरल विधि है, लेकिन बहुत शक्तिशाली है!


सुझाव, आगे पढ़ रहे हैं:

  1. सी # में भिक्षुओं के अधिक गहराई और सैद्धांतिक रूप से ध्वनि स्पष्टीकरण के लिए, मैं इस विषय पर अपने ( एरिक लिपर्ट के) सहयोगी वेस डायर के लेख की अत्यधिक अनुशंसा करता हूं । यह लेख मुझे क्या समझाया गया है जब वे अंत में मेरे लिए "क्लिक" करते हैं।
  2. आप के आसपास एक मोनाड क्यों चाहते हैं इसका एक अच्छा उदाहरण (उदाहरणों में हास्केल का उपयोग करता है)
  3. जावास्क्रिप्ट में पिछले लेख के "अनुवाद" की तरह।


17
यह एक महान जवाब है, लेकिन मेरा सिर asplody चला गया। मैं इस सप्ताह के अंत तक इसका अनुसरण कर रहा हूं और आपसे सवाल पूछूंगा कि क्या चीजें व्यवस्थित नहीं होती हैं और मेरे दिमाग में कोई बात नहीं आती है।
पॉल नाथन

5
हमेशा की तरह एरिक की उत्कृष्ट व्याख्या। अधिक सैद्धांतिक (लेकिन अभी भी अत्यधिक दिलचस्प) चर्चा के लिए मैंने कुछ कार्यात्मक प्रोग्रामिंग निर्माणों को C # में भी संबंधित करने में मदद करने के लिए MinLINQ पर बार्ट डी स्मेट का ब्लॉग पोस्ट पाया है। community.bartdesmet.net/blogs/bart/archive/2010/01/01/...
रॉन Warholic

41
यह कहना मेरे लिए अधिक समझ में आता है कि यह उन्हें प्रवर्धित करने के बजाय प्रकार बढ़ाता है।
गाबे

61
@slomojo: और मैंने इसे वापस बदल दिया जो मैंने लिखा था और लिखने का इरादा था। यदि आप और गेबे अपना उत्तर लिखना चाहते हैं, तो आप आगे बढ़ें।
एरिक लिपर्ट

24
@ एरिक, अप टू यू कोर्स, लेकिन एम्पलीफायर का तात्पर्य है कि मौजूदा गुणों को बढ़ावा दिया जाता है, जो भ्रामक है।
ओद्दो

341

हमें भिक्षुओं की आवश्यकता क्यों है?

  1. हम केवल फ़ंक्शन का उपयोग करके प्रोग्राम करना चाहते हैं । ("कार्यात्मक प्रोग्रामिंग" ऑल-एफपी के बाद)।
  2. फिर, हमारे पास पहली बड़ी समस्या है। यह एक कार्यक्रम है:

    f(x) = 2 * x

    g(x,y) = x / y

    हम कैसे कह सकते हैं कि सबसे पहले क्या निष्पादित किया जाना है ? हम फ़ंक्शंस का एक क्रमबद्ध क्रम कैसे बना सकते हैं (यानी एक प्रोग्राम ) जो फ़ंक्शंस से अधिक नहीं है?

    समाधान: कार्यों की रचना । यदि आप पहले gऔर फिर चाहते हैं f, तो बस लिखें f(g(x,y))। ठीक है, पर ...

  3. अधिक समस्याएं: कुछ कार्य विफल हो सकते हैं (यानी g(2,0), 0 से विभाजित करें)। हमारे पास एफपी में कोई "अपवाद" नहीं है । हम इसे कैसे हल करेंगे?

    समाधान: आइए फ़ंक्शंस को दो तरह की चीज़ों को वापस करने की अनुमति दें : होने के बजाय g : Real,Real -> Real(दो रीयल से वास्तविक में फ़ंक्शन), आइए अनुमति दें g : Real,Real -> Real | Nothing(दो रियल से रियल (कुछ भी नहीं) में फ़ंक्शन करें)।

  4. लेकिन फ़ंक्शंस (सरल होने के लिए) केवल एक ही चीज़ वापस करना चाहिए ।

    समाधान: आइए लौटाए जाने के लिए एक नए प्रकार का डेटा बनाते हैं, एक " बॉक्सिंग प्रकार " जो एक वास्तविक को घेरता है या बस कुछ भी नहीं है। इसलिए, हम कर सकते हैं g : Real,Real -> Maybe Real। ठीक है, पर ...

  5. अब क्या होता है f(g(x,y))? fउपभोग करने के लिए तैयार नहीं है Maybe Real। और, हम प्रत्येक फ़ंक्शन को बदलना नहीं चाहते हैं जिसे हम gउपभोग करने के लिए जोड़ सकते हैं Maybe Real

    समाधान: चलो "कनेक्ट" / "रचना" / "लिंक" फ़ंक्शन के लिए एक विशेष फ़ंक्शन है । इस तरह, हम पर्दे के पीछे, निम्नलिखित को खिलाने के लिए एक फ़ंक्शन के आउटपुट को अनुकूलित कर सकते हैं।

    हमारे मामले में: g >>= f(कनेक्ट / लिखें gकरने के लिए f)। हम आउटपुट >>=प्राप्त करना चाहते हैं g, इसका निरीक्षण करते हैं और अगर यह Nothingसिर्फ कॉल fऔर रिटर्न नहीं है Nothing; या इसके विपरीत, बॉक्सिंग निकालें और इसके साथ Realफ़ीड fकरें। (यह एल्गोरिदम केवल प्रकार के >>=लिए कार्यान्वयन है Maybe)।

  6. कई अन्य समस्याएं उत्पन्न होती हैं जिन्हें इसी पैटर्न का उपयोग करके हल किया जा सकता है: 1. विभिन्न अर्थों / मूल्यों को संहिताबद्ध / संग्रहीत करने के लिए "बॉक्स" का उपयोग करें, और ऐसे कार्य होते हैं gजो उन "बॉक्सिंग मूल्यों" को वापस करते हैं। 2. संगीतकार / लिंकर्स g >>= fको इनपुट के gआउटपुट को जोड़ने में मदद करने के लिए है f, इसलिए हमें बिल्कुल भी बदलने की आवश्यकता नहीं है f

  7. इस तकनीक का उपयोग करके हल की जा सकने वाली समस्याएँ हैं:

    • एक वैश्विक स्थिति है कि कार्यों के क्रम में हर कार्य ("कार्यक्रम") साझा कर सकते हैं: समाधान StateMonad

    • हम "अशुद्ध कार्यों" को पसंद नहीं करते हैं: ऐसे कार्य जो एक ही इनपुट के लिए अलग-अलग आउटपुट देते हैं । इसलिए, उन कार्यों को चिह्नित करते हैं, जो उन्हें टैग किए गए / बॉक्स किए गए मान को वापस करने के लिए बनाते हैं: मोनड।IO

कुल सुख !!!!


2
@DmitriZaitsev अपवाद केवल "अशुद्ध कोड" (IO मोनड) में हो सकते हैं जहां तक ​​मुझे पता है।
cibercitizen1

3
@DmitriZaitsev कुछ भी नहीं की भूमिका किसी अन्य प्रकार (अपेक्षित रियल के भिन्न) द्वारा निभाई जा सकती है। यह बात महत्वपूर्ण नहीं है। उदाहरण में, मामला यह है कि श्रृंखला में कार्यों को कैसे अनुकूलित किया जाए, जब पिछले वाले निम्नलिखित को एक अप्रत्याशित मान प्रकार लौटा सकता है, बिना बाद वाले का पीछा किए (केवल एक इनपुट के रूप में एक वास्तविक स्वीकार करते हुए)।
cibercitizen1

3
एक और भ्रम की स्थिति यह है कि "मोनड" शब्द आपके उत्तर में केवल दो बार दिखाई देता है, और केवल अन्य शब्दों के संयोजन में - Stateऔर IO, उनमें से कोई भी और साथ ही "मोनड" का सटीक अर्थ नहीं दिया जा रहा है
दिमित्री जैतसेव

31
मेरे लिए एक OOP पृष्ठभूमि से आने वाले व्यक्ति के रूप में इस उत्तर ने वास्तव में एक सन्यासी होने के पीछे की प्रेरणा को अच्छी तरह से समझाया और यह भी कि वास्तव में सन्यासी क्या है (एक स्वीकृत उत्तर जितना अधिक)। इसलिए, मुझे यह बहुत मददगार लगता है। बहुत बहुत धन्यवाद @ cibercitizen1 और +1
akhilless

3
मैं लगभग एक साल से कार्यात्मक प्रोग्रामिंग के बारे में पढ़ रहा हूं। इस जवाब ने, और विशेष रूप से पहले दो बिंदुओं ने, आखिरकार मुझे यह समझा दिया कि वास्तव में अनिवार्य प्रोग्रामिंग का क्या अर्थ है, और कार्यात्मक प्रोग्रामिंग अलग क्यों है। धन्यवाद!
जहराली

82

मैं कहूंगा कि भिक्षुओं के लिए निकटतम OO सादृश्य " कमांड पैटर्न " है।

कमांड पैटर्न में आप कमांड ऑब्जेक्ट में एक साधारण स्टेटमेंट या एक्सप्रेशन लपेटते हैं । कमांड ऑब्जेक्ट एक निष्पादित विधि को उजागर करता है जो लिपटे स्टेटमेंट को निष्पादित करता है। इसलिए कथन को प्रथम श्रेणी की वस्तुओं में बदल दिया जाता है, जो वसीयत में इधर-उधर हो सकती हैं और निष्पादित हो सकती हैं। कमांड्स की रचना की जा सकती है ताकि आप कमांड -ऑब्जेक्ट्स को चैन और नेस्टिंग करके प्रोग्राम-ऑब्जेक्ट बना सकें।

आदेशों को एक अलग ऑब्जेक्ट, आक्रमणकारी द्वारा निष्पादित किया जाता है । कमांड पैटर्न (साधारण बयानों की एक श्रृंखला को निष्पादित करने के बजाय) का उपयोग करने का लाभ यह है कि अलग-अलग चालान अलग-अलग तर्क लागू कर सकते हैं कि कमांड को कैसे निष्पादित किया जाना चाहिए।

कमांड पैटर्न का उपयोग भाषा सुविधाओं को जोड़ने (या हटाने) के लिए किया जा सकता है जो होस्ट भाषा द्वारा समर्थित नहीं है। उदाहरण के लिए, अपवादों के बिना एक काल्पनिक OO भाषा में, आप "कोशिश" और "फेंक" विधियों को आदेशों को उजागर करके अपवाद शब्दार्थ जोड़ सकते हैं। जब कोई कमांड कॉल फेंकती है, तो अंतिम "कोशिश" कॉल तक कमांडर सूची (या पेड़) के माध्यम से पीछे हट जाता है। इसके विपरीत, आप एक भाषा से अपवाद शब्दार्थ को हटा सकते हैं (यदि आप मानते हैं कि अपवाद बुरे हैं ) प्रत्येक व्यक्तिगत आदेशों द्वारा फेंके गए सभी अपवादों को पकड़कर, और फिर उन्हें त्रुटि कोड में बदल दिया जाता है जो फिर अगले आदेश में पारित हो जाते हैं।

लेन-देन, गैर-नियतात्मक निष्पादन या निरंतरता जैसे अधिक फैंसी निष्पादन शब्दार्थ भी इस तरह से एक भाषा में लागू किए जा सकते हैं जो मूल रूप से समर्थन नहीं करता है। यदि आप इसके बारे में सोचते हैं तो यह एक बहुत शक्तिशाली पैटर्न है।

अब वास्तव में कमांड-पैटर्न का उपयोग इस तरह की सामान्य भाषा सुविधा के रूप में नहीं किया जाता है। प्रत्येक कथन को एक अलग वर्ग में बदल देने से बॉयलरप्लेट कोड की असहनीय मात्रा हो जाएगी। लेकिन सिद्धांत रूप में इसका उपयोग उन्हीं समस्याओं को हल करने के लिए किया जा सकता है जैसे कि एफडी में हल करने के लिए साधुओं का उपयोग किया जाता है।


15
मेरा मानना ​​है कि यह पहला मोनड स्पष्टीकरण है जिसे मैंने देखा है कि कार्यात्मक प्रोग्रामिंग अवधारणाओं पर भरोसा नहीं किया और इसे वास्तविक ओओपी शब्दों में रखा। वास्तव में अच्छा जवाब।
डेविड के। हेस

यह बहुत करीब 2 है जो कि वास्तव में एफपी / हास्केल में मोनड्स हैं, सिवाय इसके कि कमांड ऑब्जेक्ट खुद "जानते हैं" जो कि "इनवोकेशन लॉजिक" वे हैं (और केवल संगत लोगों को एक साथ जंजीर किया जा सकता है); आक्रमणकारी सिर्फ पहले मूल्य की आपूर्ति करता है। यह ऐसा नहीं है कि "प्रिंट" कमांड "गैर-नियतात्मक निष्पादन तर्क" द्वारा निष्पादित किया जा सकता है। नहीं, इसे "I / O लॉजिक" (यानी IO मोनड) होना चाहिए। लेकिन इसके अलावा, यह बहुत करीब है। आप यहां तक ​​कह सकते हैं कि मोनाड्स केवल प्रोग्राम हैं (कोड स्टेटमेंट का निर्माण, बाद में निष्पादित होने के लिए)। शुरुआती दिनों में "बाइंड" को "प्रोग्रामेबल अर्धविराम" के रूप में बात की गई थी ।
विल नेस

1
@ डेविडके। मैं वास्तव में उन उत्तरों के बारे में अविश्वसनीय रूप से संदेह करता हूं जो एफपी का उपयोग बुनियादी एफपी अवधारणाओं को समझाने के लिए करते हैं, और विशेष रूप से ऐसे उत्तर हैं जो स्काला जैसी एफपी भाषा का उपयोग करते हैं। अच्छा किया, जैक्सबी!
मोनिका

62

इस संदर्भ में कि एक OOP प्रोग्रामर (किसी भी कार्यात्मक प्रोग्रामिंग पृष्ठभूमि के बिना) को समझेगा, एक सन्यासी क्या है?

यह किस समस्या को हल करता है और इसका उपयोग करने वाले सबसे आम स्थान क्या हैं?

OO प्रोग्रामिंग के संदर्भ में, एक मोनाड एक इंटरफ़ेस (या अधिक संभावना वाला मिक्सिन) है, जो दो प्रकारों के साथ एक प्रकार से परिचालित होता है, returnऔर bindयह वर्णन करता है:

  • उस इंजेक्टेड वैल्यू टाइप का एक मान मान प्राप्त करने के लिए किसी वैल्यू को इंजेक्ट कैसे करें;
  • ऐसे फ़ंक्शन का उपयोग कैसे करें जो एक गैर-मोनोडिक एक से एक मोनोडिक मान बनाता है।

समस्या यह हल करती है एक ही प्रकार की समस्या है जिसे आप किसी भी इंटरफ़ेस से उम्मीद करेंगे, अर्थात्, "मेरे पास अलग-अलग वर्गों का एक समूह है जो अलग-अलग चीजें करते हैं, लेकिन उन विभिन्न चीजों को एक तरह से करते हैं जो अंतर्निहित समानता है। कैसे क्या मैं उन दोनों के बीच की समानता का वर्णन कर सकता हूं, भले ही कक्षाएं स्वयं वास्तव में 'ऑब्जेक्ट' क्लास की तुलना में किसी भी चीज़ के करीब न हों। "

विशेष रूप से, Monad"इंटरफेस" के समान है IEnumeratorया IIteratorकि यह है कि अपने आप में एक प्रकार लेता है एक प्रकार लेता है। हालांकि मुख्य "बिंदु" Monadआंतरिक प्रकार के आधार पर संचालन को जोड़ने में सक्षम है, यहां तक ​​कि एक नया "आंतरिक प्रकार" होने के बिंदु तक, जबकि - या मुख्य वर्ग की सूचना संरचना - रखते हुए भी।


1
returnवास्तव में मोनाड पर एक विधि नहीं होगी, क्योंकि यह एक तर्क के रूप में एक सनक उदाहरण नहीं लेता है। (अर्थात: यह / स्वयं नहीं है)
लारेंस गोंसाल्वेस

@ लॉरेंसगॉन्स्लेव्स: चूंकि मैं वर्तमान में अपने स्नातक की थीसिस के लिए देख रहा हूं, मुझे लगता है कि ज्यादातर सीमित है जो सी # / जावा में इंटरफेस में स्थिर तरीकों की कमी है। आप पूरी मोनाड कहानी को लागू करने की दिशा में एक लंबा रास्ता तय कर सकते हैं, कम से कम वैधानिक रूप से टाइपकास्ट के आधार पर बाध्य होने के बजाय। दिलचस्प बात यह है कि यह उच्चतर प्रकार की कमी के बावजूद भी काम करेगा।
सेबस्टियन ग्राफ

42

आपके पास क्रिस्टोफर लीग (जुलाई 12, 2010) द्वारा हाल ही में एक प्रस्तुति " मोनाडोलोगी - पेशेवर चिंता प्रकार पर चिंता " है , जो निरंतरता और मोनाड के विषयों पर काफी दिलचस्प है। इस (स्लाइडशेयर) प्रस्तुति के साथ जाने वाला वीडियो वास्तव में वीमियो पर उपलब्ध है । इस एक घंटे के वीडियो पर मोनाड का हिस्सा लगभग 37 मिनट से शुरू होता है, और इसकी 58 स्लाइड प्रस्तुति में से 42 के साथ शुरू होता है।

इसे "कार्यात्मक प्रोग्रामिंग के लिए अग्रणी डिजाइन पैटर्न" के रूप में प्रस्तुत किया गया है, लेकिन उदाहरणों में प्रयुक्त भाषा स्काला है, जो ओओपी और कार्यात्मक दोनों है।
"आप स्काला में ब्लॉग पोस्ट में इकाई के बारे में अधिक पढ़ सकते हैं - स्काला में सार संगणना करने के लिए एक और तरीका है monads , से" देवाशीष घोष (27 मार्च, 2008)।

एक प्रकार का कंस्ट्रक्टर M एक मोनाड है अगर यह इन कार्यों का समर्थन करता है:

# the return function
def unit[A] (x: A): M[A]

# called "bind" in Haskell 
def flatMap[A,B] (m: M[A]) (f: A => M[B]): M[B]

# Other two can be written in term of the first two:

def map[A,B] (m: M[A]) (f: A => B): M[B] =
  flatMap(m){ x => unit(f(x)) }

def andThen[A,B] (ma: M[A]) (mb: M[B]): M[B] =
  flatMap(ma){ x => mb }

उदाहरण के लिए (स्काला में):

  • Option एक सन्यासी है
    def यूनिट [A] (x: A): विकल्प [A] = कुछ (x)

    डीप फ्लैटपाइप [ए, बी] (एम: विकल्प [ए]) (एफ: ए => विकल्प [बी]): विकल्प [बी] =
      मी मैच {
       मामला कोई नहीं>> कोई नहीं
       मामला कुछ (x) => f (x)
      }
  • List मोनाड है
    def यूनिट [A] (x: A): सूची [A] = सूची (x)

    def flatMap [ए, बी] (एम: सूची [ए]) (एफ: ए => सूची [बी]): सूची [बी] =
      मी मैच {
        मामला नील => शून्य
        मामला x :: xs => f (x) ::: flatMap (xs) (f)
      }

मोनाड संरचनाओं का लाभ उठाने के लिए बनाए गए सुविधाजनक सिंटैक्स के कारण मोनाला स्काला में एक बड़ी बात है:

forस्काला में समझ :

for {
  i <- 1 to 4
  j <- 1 to i
  k <- 1 to j
} yield i*j*k

संकलक द्वारा अनुवादित है:

(1 to 4).flatMap { i =>
  (1 to i).flatMap { j =>
    (1 to j).map { k =>
      i*j*k }}}

कुंजी अमूर्तता है flatMap, जो अभिकलन को जंजीर के माध्यम से बांधती है।
प्रत्येक आह्वान flatMapएक ही डेटा संरचना प्रकार (लेकिन अलग-अलग मूल्य) का रिटर्न देता है, जो श्रृंखला में अगले कमांड के इनपुट के रूप में कार्य करता है।

उपरोक्त स्निपेट में, फ्लैटपाइप इनपुट के रूप में बंद हो जाता है (SomeType) => List[AnotherType]और वापस आ जाता है List[AnotherType]। ध्यान देने वाली महत्वपूर्ण बात यह है कि सभी फ्लैटमैप्स इनपुट के समान क्लोजर प्रकार को लेते हैं और आउटपुट के समान प्रकार को वापस करते हैं।

यह वही है जो गणना के धागे को "बांधता है" - अनुक्रम में अनुक्रम के प्रत्येक आइटम को इसी प्रकार की बाधा का सम्मान करना पड़ता है।


यदि आप दो ऑपरेशन लेते हैं (जो विफल हो सकता है) और परिणाम को तीसरे में पास करें, जैसे:

lookupVenue: String => Option[Venue]
getLoggedInUser: SessionID => Option[User]
reserveTable: (Venue, User) => Option[ConfNo]

लेकिन मोनाद का फायदा उठाए बिना, आप जैसे ओओपी-कोड प्राप्त कर लेते हैं:

val user = getLoggedInUser(session)
val confirm =
  if(!user.isDefined) None
  else lookupVenue(name) match {
    case None => None
    case Some(venue) =>
      val confno = reserveTable(venue, user.get)
      if(confno.isDefined)
        mailTo(confno.get, user.get)
      confno
  }

मोनाड के साथ, आप सभी प्रकार के कार्यों की तरह वास्तविक प्रकारों ( Venue, User) के साथ काम कर सकते हैं , और विकल्प सत्यापन सामग्री को छिपा कर रख सकते हैं, सभी क्योंकि सिंटैक्स के फ़्लैटमैप्स के कारण हैं:

val confirm = for {
  venue <- lookupVenue(name)
  user <- getLoggedInUser(session)
  confno <- reserveTable(venue, user)
} yield {
  mailTo(confno, user)
  confno
}

उपज भाग केवल तभी निष्पादित किया जाएगा जब तीनों कार्य होंगे Some[X]; किसी Noneको भी सीधे लौटा दिया जाएगा confirm


इसलिए:

मोनाड्स ने फंक्शनल प्रोग्रामिंग के भीतर गणना करने का आदेश दिया, जो हमें एक अच्छे संरचित रूप में कुछ हद तक डीएसएल की तरह क्रियाओं के मॉडल की अनुमति देता है।

और सबसे बड़ी शक्ति विभिन्न प्रयोजनों की सेवा करने वाले भिक्षुओं की रचना करने की क्षमता के साथ आती है, जो एक अनुप्रयोग के भीतर एक्स्टेंसिबल अमूर्त में होता है।

एक संन्यासी द्वारा क्रियाओं का अनुक्रमण और सूत्रण भाषा संकलक द्वारा किया जाता है जो क्लोजर के जादू के माध्यम से परिवर्तन करता है।


वैसे, मोनाड केवल FP में उपयोग किए जाने वाले संगणना का मॉडल नहीं है:

श्रेणी सिद्धांत गणना के कई मॉडलों का प्रस्ताव करता है। उनमें से

  • गणना के तीर मॉडल
  • कम्प्यूटेशन का मोनाड मॉडल
  • कम्प्यूटेशंस का एप्लाइड मॉडल

2
मुझे यह स्पष्टीकरण पसंद है! आपने जो उदाहरण दिया, वह अवधारणा को खूबसूरती से प्रदर्शित करता है और यह भी जोड़ता है कि एरिक के टीज़र से आईएमएचओ मिसमैड होने के बारे में क्या याद कर रहा था। इसके लिए Thx!
जुआन

1
IMHO यह सबसे सुरुचिपूर्ण जवाब है
पॉलिमरेज़

और सब कुछ से पहले, Functor।
विल नेस

34

तेजी से पाठकों का सम्मान करने के लिए, मैं पहले सटीक परिभाषा के साथ शुरू करता हूं, त्वरित "सादे अंग्रेजी" स्पष्टीकरण के साथ जारी रखता हूं, और फिर उदाहरणों पर जाता हूं।

यहाँ थोड़ा संक्षिप्त रूप में संक्षिप्त और सटीक परिभाषा है:

एक मोनड (कंप्यूटर विज्ञान में) औपचारिक रूप से एक मानचित्र है जो:

  • हर प्रकार Xकी कुछ प्रोग्रामिंग लैंग्वेज को एक नए T(X)प्रकार में Tभेज देता है (जिसे " मानों के साथ -प्रकार के प्रकार" कहा जाता है X);

  • प्रपत्र के दो कार्यों f:X->T(Y)और g:Y->T(Z)एक फ़ंक्शन के लिए एक नियम से लैस g∘f:X->T(Z);

  • एक तरह से जो स्पष्ट अर्थों में साहचर्य है और किसी दिए गए यूनिट फ़ंक्शन के संबंध में एकात्मक है pure_X:X->T(X), जिसे शुद्ध गणना के लिए एक मान लेने के रूप में सोचा जाता है जो बस उस मूल्य को वापस करता है।

तो सरल शब्दों में, एक इकाई एक है किसी भी प्रकार से पारित करने के लिए नियम Xकिसी दूसरे प्रकार मेंT(X) , और एक नियम दो कार्यों से पारित करने के लिए f:X->T(Y)और g:Y->T(Z)एक नया कार्य करने के लिए (है कि आप रचना चाहते हैं लेकिन नहीं कर सकते हैं)h:X->T(Z) । हालांकि, यह सख्त गणितीय अर्थों में रचना नहीं है। हम मूल रूप से "झुका" फ़ंक्शन की रचना या फिर से परिभाषित करते हैं कि फ़ंक्शन कैसे बनाये जाते हैं।

इसके अलावा, हमें "स्पष्ट" गणितीय स्वयंसिद्धों को संतुष्ट करने के लिए मोनाड के नियम की आवश्यकता है:

  • संबद्धता : लिखना fसाथ gऔर फिर साथ h(बाहर से) रचना के रूप में ही किया जाना चाहिए gके साथ hऔर फिर साथ f(अंदर से)।
  • वैवाहिक संपत्ति : दोनों तरफ पहचान समारोह के fसाथ रचना करना चाहिए ।f

फिर, सरल शब्दों में, हम अपनी रचना को फिर से परिभाषित नहीं कर सकते, जैसा कि हम चाहते हैं:

  • हमें सबसे पहले समरूपता की आवश्यकता होती है f(g(h(k(x))), जैसे कि एक पंक्ति में कई कार्यों की रचना करने में सक्षम होना चाहिए , और फ़ंक्शन जोड़े को क्रमबद्ध करने के लिए निर्दिष्ट करने के बारे में चिंता न करें। जैसा कि मोनाद नियम केवल यह बताता है कि एक जोड़ी कार्यों की रचना कैसे की जाती है , उस स्वयंसिद्ध के बिना, हमें यह जानना होगा कि कौन सी जोड़ी पहले और इसी तरह से बनी है। (ध्यान दें कि commutativity संपत्ति से अलग है fके साथ बना gएक ही रूप में थे gके साथ बना fहै, जो आवश्यक नहीं है)।
  • और दूसरा, हमें वैवाहिक संपत्ति की आवश्यकता है, जो केवल यह कहने के लिए है कि पहचान तुच्छ तरीके से रचना करते हैं जिस तरह से हम उनसे उम्मीद करते हैं। इसलिए जब भी उन पहचानों को निकाला जा सकता है, हम सुरक्षित रूप से कार्य कर सकते हैं।

तो फिर से संक्षेप में: एक सनक दो स्वयंसिद्ध - संघात्मकता और वैवाहिक संपत्ति को संतुष्ट करने वाले प्रकार के विस्तार और रचना के कार्यों का नियम है।

व्यावहारिक रूप से, आप चाहते हैं कि भाषा, संकलक या रूपरेखा द्वारा आपके लिए मोनाड लागू किया जाए जो आपके लिए रचनाओं का ध्यान रखे। इसलिए आप अपने कार्य के तर्क को लिखने के बजाय इस बात पर ध्यान केंद्रित कर सकते हैं कि उनका निष्पादन कैसे लागू किया जाता है।

यह अनिवार्य रूप से यह है, संक्षेप में।


पेशेवर गणितज्ञ होने के नाते, मैं h"रचना" fऔर से कॉल करने से बचना पसंद करता हूँ g। क्योंकि गणितीय रूप से, यह नहीं है। इसे "रचना" कहना गलत तरीके hसे सही गणितीय रचना है, जो यह नहीं है। यह विशिष्ट रूप से भी निर्धारित नहीं है fऔर g। इसके बजाय, यह हमारे संन्यासी के नए "कार्यों की रचना करने के नियम" का परिणाम है। जो कि वास्तविक गणितीय संरचना से बिलकुल अलग हो सकता है, भले ही उत्तरार्द्ध मौजूद हो!


इसे कम सूखा बनाने के लिए, मैं इसे उदाहरण के द्वारा समझाने की कोशिश करता हूं कि मैं छोटे वर्गों के साथ एनोटेट कर रहा हूं, इसलिए आप बिंदु पर सही छोड़ सकते हैं।

मोनाद उदाहरण के रूप में फेंकने वाला अपवाद

मान लें कि हम दो कार्य करना चाहते हैं:

f: x -> 1 / x
g: y -> 2 * y

लेकिन f(0)परिभाषित नहीं है, इसलिए एक अपवाद eफेंक दिया गया है। फिर आप संरचनागत मूल्य को कैसे परिभाषित कर सकते हैं g(f(0))? एक अपवाद फिर से फेंको, बिल्कुल! शायद वही e। शायद एक नया अद्यतन अपवाद e1

यहाँ ठीक क्या होता है? सबसे पहले, हमें नए अपवाद मूल्य (अलग-अलग या समान) चाहिए। आप उन्हें nothingया nullजो भी कह सकते हैं, लेकिन सार एक ही रहता है - वे नए मूल्य होने चाहिए, जैसे कि यह numberहमारे उदाहरण में नहीं होना चाहिए । मैं उन्हें किसी विशेष भाषा में nullकैसे nullलागू किया जा सकता है, इस भ्रम से बचने के लिए नहीं बुलाना पसंद करता हूं । समान रूप से मैं इससे बचना पसंद करता हूं nothingक्योंकि यह अक्सर साथ जुड़ा होता है null, जो, सिद्धांत रूप में, क्या nullकरना चाहिए, हालांकि, उस सिद्धांत को अक्सर जो भी व्यावहारिक कारणों के लिए झुकना पड़ता है।

क्या वास्तव में अपवाद है?

किसी भी अनुभवी प्रोग्रामर के लिए यह एक तुच्छ मामला है, लेकिन मैं किसी भी शब्द को भ्रम की स्थिति से बाहर निकालने के लिए कुछ शब्द छोड़ना चाहता हूं:

अपवाद एक ऐसी वस्तु है जो जानकारी के बारे में जानकारी देती है कि निष्पादन का अमान्य परिणाम कैसे हुआ।

यह किसी भी विवरण को फेंकने और एक वैश्विक मूल्य (जैसे NaNया null) को वापस करने या लंबी लॉग सूची बनाने या वास्तव में क्या हुआ, से लेकर डेटाबेस तक भेजने और वितरित डेटा भंडारण परत पर सभी की नकल करने तक हो सकता है;)

अपवाद के इन दो चरम उदाहरणों के बीच महत्वपूर्ण अंतर यह है कि पहले मामले में कोई दुष्प्रभाव नहीं हैं । दूसरे में हैं। जो हमें (हजार-डॉलर) प्रश्न पर लाता है:

क्या शुद्ध कार्यों में अपवादों की अनुमति है?

कम जवाब : हाँ, लेकिन केवल जब वे साइड-इफेक्ट के लिए नेतृत्व नहीं करते।

लंबा जवाब। शुद्ध होने के लिए, आपके फ़ंक्शन के आउटपुट को विशिष्ट रूप से इसके इनपुट द्वारा निर्धारित किया जाना चाहिए। इसलिए हम अपने कार्य को नए अमूर्त मूल्य पर fभेजकर संशोधन करते हैं जिसे हम अपवाद कहते हैं। हम यह सुनिश्चित करते हैं कि मूल्य में कोई बाहरी जानकारी नहीं है जो हमारे इनपुट द्वारा विशिष्ट रूप से निर्धारित नहीं है, जो है । तो यहाँ साइड इफेक्ट के बिना अपवाद का एक उदाहरण है:0eex

e = {
  type: error, 
  message: 'I got error trying to divide 1 by 0'
}

और यहाँ एक पक्ष प्रभाव के साथ है:

e = {
  type: error, 
  message: 'Our committee to decide what is 1/0 is currently away'
}

वास्तव में, इसका केवल साइड-इफ़ेक्ट है अगर वह संदेश भविष्य में संभवतः बदल सकता है। लेकिन अगर इसे कभी नहीं बदलने की गारंटी दी जाती है, तो यह मूल्य विशिष्ट रूप से अनुमानित हो जाता है, और इसलिए इसका कोई दुष्प्रभाव नहीं है।

इसे भी सिलियर बनाने के लिए। 42कभी लौट रहा एक समारोह स्पष्ट रूप से शुद्ध है। लेकिन अगर कोई पागल 42ऐसा वैरिएबल बनाने का फैसला करता है जो मूल्य बदल सकता है, तो बहुत ही फ़ंक्शन नई शर्तों के तहत शुद्ध होना बंद कर देता है।

ध्यान दें कि मैं सार को प्रदर्शित करने के लिए सरलता के लिए वस्तु शाब्दिक अंकन का उपयोग कर रहा हूं। दुर्भाग्य से चीजों को जावास्क्रिप्ट की तरह भाषाओं में गड़बड़ कर दिया जाता है, जहां errorएक प्रकार नहीं है जो कार्य रचना के संबंध में हम यहां चाहते हैं जिस तरह से व्यवहार करते हैं, जबकि वास्तविक प्रकार इस तरह से व्यवहार करते हैं nullया NaNनहीं करते हैं, बल्कि कुछ कृत्रिम के माध्यम से जाते हैं और हमेशा सहज नहीं होते हैं रूपांतरण लिखें।

एक्सटेंशन टाइप करें

जैसा कि हम अपने अपवाद के अंदर संदेश को अलग करना चाहते हैं, हम वास्तव Eमें पूरे अपवाद ऑब्जेक्ट के लिए एक नए प्रकार की घोषणा कर रहे हैं और फिर वही होता है maybe number, जो इसके भ्रामक नाम के अलावा होता है, जो या तो numberनए अपवाद प्रकार का होना चाहिए E, तो यह वास्तव में संघ है number | Eकी numberऔर E। विशेष रूप से, यह इस बात पर निर्भर करता है कि हम कैसे निर्माण करना चाहते हैं E, जिसका नाम में न तो सुझाव दिया गया है और न ही प्रतिबिंबित किया गया है maybe number

कार्यात्मक रचना क्या है?

यह फ़ंक्शन लेने f: X -> Yऔर g: Y -> Zफ़ंक्शन को h: X -> Zसंतोषजनक बनाने के लिए उनकी रचना का गणितीय संचालन है h(x) = g(f(x))। इस परिभाषा के साथ समस्या तब होती है जब परिणाम f(x)को तर्क के रूप में अनुमति नहीं दी जाती है g

गणित में उन कार्यों को बिना अतिरिक्त काम के नहीं बनाया जा सकता है। हमारे उपरोक्त उदाहरण के लिए सख्ती से गणितीय समाधान है fऔर परिभाषा की परिभाषा के सेट से gदूर करना 0है f। परिभाषा के उस नए सेट (नए और अधिक प्रतिबंधक प्रकार x) के साथ, के fसाथ रचना हो जाती है g

हालांकि, यह fउस तरह की परिभाषा के सेट को प्रतिबंधित करने के लिए प्रोग्रामिंग में बहुत व्यावहारिक नहीं है। इसके बजाय, अपवादों का उपयोग किया जा सकता है।

या फिर एक और दृष्टिकोण के रूप में, कृत्रिम मूल्यों की तरह बनाई गई हैं NaN, undefined, null, Infinityआदि तो तुम का मूल्यांकन 1/0करने के लिए Infinityऔर 1/-0करने के लिए -Infinity। और फिर अपवाद को फेंकने के बजाय नए मूल्य को अपनी अभिव्यक्ति में वापस लाएं। परिणामों के लिए अग्रणी आपको अनुमान लगाने योग्य नहीं मिल सकता है या नहीं:

1/0                // => Infinity
parseInt(Infinity) // => NaN
NaN < 0            // => false
false + 1          // => 1

और हम आगे बढ़ने के लिए तैयार नियमित संख्याओं में वापस आ रहे हैं;)

जावास्क्रिप्ट हमें उपरोक्त उदाहरण के रूप में त्रुटियों को फेंकने के बिना किसी भी कीमत पर संख्यात्मक अभिव्यक्तियों को निष्पादित करने की अनुमति देता है। इसका मतलब है कि, यह कार्यों की रचना करने की भी अनुमति देता है। जो वास्तव में मोनाड के बारे में है - यह इस उत्तर की शुरुआत के रूप में स्वयंसिद्धों को संतुष्ट करने वाले कार्यों की रचना करने के लिए एक नियम है।

लेकिन संख्यात्मक त्रुटियों से निपटने के लिए जावास्क्रिप्ट के कार्यान्वयन से उत्पन्न होने वाले समारोह की रचना का नियम है?

इस प्रश्न का उत्तर देने के लिए, आपको सभी स्वयंसिद्धों की जांच करनी है (यहाँ प्रश्न के भाग के रूप में व्यायाम नहीं किया गया है;)।

क्या एक मोनड के निर्माण के लिए अपवाद फेंकने का उपयोग किया जा सकता है?

वास्तव में, एक अधिक उपयोगी मोनाड यह नियम निर्धारित करेगा कि यदि fकुछ के लिए अपवाद फेंकता है x, तो इसकी रचना किसी के साथ भी होती है g। प्लस Eकेवल एक संभव मूल्य ( श्रेणी सिद्धांत में टर्मिनल ऑब्जेक्ट ) के साथ विश्व स्तर पर अद्वितीय बनाते हैं । अब दो स्वयंसिद्ध तुरन्त जांचने योग्य हैं और हमें एक बहुत उपयोगी मोनाड मिलता है। और नतीजा यह है कि शायद मोनाड के रूप में अच्छी तरह से जाना जाता है ।


3
अच्छा योगदान है। +1 लेकिन हो सकता है कि आप हटाना चाहते हैं "अधिकांश स्पष्टीकरण बहुत लंबे पाए गए हैं ..." आपका सबसे लंबा होना। अन्य लोग न्याय करेंगे यदि यह "सादा अंग्रेजी" है जैसा कि आवश्यक प्रश्न: "सादे अंग्रेजी == सरल शब्दों में, सरल तरीके से"।
cibercitizen1

@ cibercitizen1 धन्यवाद! यह वास्तव में छोटा है, यदि आप उदाहरण की गणना नहीं करते हैं। मुख्य बिंदु यह है कि परिभाषा को समझने के लिए आपको उदाहरण पढ़ने की आवश्यकता नहीं है । दुर्भाग्य से कई स्पष्टीकरण मुझे पहले उदाहरण पढ़ने के लिए मजबूर करते हैं , जो अक्सर अनावश्यक होता है लेकिन निश्चित रूप से, लेखक के लिए अतिरिक्त काम की आवश्यकता हो सकती है। विशिष्ट उदाहरणों पर बहुत अधिक निर्भरता के साथ, एक खतरा है कि महत्वहीन विवरण तस्वीर को अस्पष्ट करते हैं और इसे समझना मुश्किल हो जाता है। ऐसा कहने के बाद, आपके पास मान्य बिंदु हैं, अपडेट देखें।
दिमित्री जैतसेव

2
बहुत लंबा और भ्रमित
seenimurugan

1
@seenimurugan सुधार सुझावों का स्वागत है;)
दिमित्री

26

एक मोनाड एक डेटा प्रकार है जो एक मान को एनकैप्सुलेट करता है, और जिसके लिए, अनिवार्य रूप से, दो ऑपरेशन लागू किए जा सकते हैं:

  • return x मोनाड प्रकार का मान बनाता है जो एनकैप्सुलेट करता है x
  • m >>= f(इसे "बाइंड ऑपरेटर" के रूप में पढ़ें) fमान में फ़ंक्शन को लागू करता हैm

वह एक सन्यासी है। हैं कुछ और तकनीकी के , लेकिन मूल रूप से उन दो संचालन एक इकाई परिभाषित करते हैं। असली सवाल यह है कि, "एक सन्यासी क्या करता है ?" इसका मतलब यह है कि जब हम कहते हैं कि वे चीजें हैं तो वे साधु हैं returnऔर उनके पास मोनाड इंटरफेस है >>=


"एक सन्यासी क्या करता है, और यह कि सन्यासी पर निर्भर करता है": और अधिक सटीक रूप से, यह उस bindफ़ंक्शन पर निर्भर करता है जिसे प्रत्येक विवादास्पद प्रकार के लिए परिभाषित किया जाना चाहिए, है ना? यह रचना के साथ बाइंड को भ्रमित न करने का एक अच्छा कारण होगा, क्योंकि रचना के लिए एक ही परिभाषा है, जबकि एक बाइंड फ़ंक्शन के लिए सिर्फ एक ही परिभाषा नहीं हो सकती है, अगर मैं सही ढंग से समझता हूं, तो एक प्रति मौद्रिक प्रकार है।
हिबू ५ H

14

से विकिपीडिया :

कार्यात्मक प्रोग्रामिंग में, एक मोनाड एक प्रकार का सार डेटा प्रकार है जिसका उपयोग कम्प्यूटेशन (डोमेन मॉडल में डेटा के बजाय) का प्रतिनिधित्व करने के लिए किया जाता है। मोनाडर्स पाइपलाइन को बनाने के लिए प्रोग्रामर को एक साथ चेन एक्शन की अनुमति देते हैं, जिसमें प्रत्येक एक्शन को मोनड द्वारा प्रदान किए गए अतिरिक्त प्रोसेसिंग नियमों से सजाया जाता है। कार्यात्मक शैली में लिखे गए प्रोग्राम मोनडैड्स का उपयोग संरचना प्रक्रियाओं के लिए कर सकते हैं, जिसमें अनुक्रमित संचालन, 1 [2] शामिल हैं या मनमाने ढंग से नियंत्रण प्रवाह को परिभाषित करने के लिए (जैसे संक्षिप्तता, निरंतरता या अपवादों को संभालना)।

औपचारिक रूप से, दो कार्यों (बाइंड एंड रिटर्न) और एक प्रकार के निर्माता एम को परिभाषित करके एक मोनड का निर्माण किया जाता है, जिसे मोनडिक फ़ंक्शंस की सही रचना (यानी फ़ंक्शंस जो मोनड से मान का उपयोग उनके तर्कों के रूप में करते हैं) की अनुमति देने के लिए कई गुणों को पूरा करना होगा। रिटर्न ऑपरेशन एक सादे प्रकार से एक मूल्य लेता है और इसे एम के एक मोनडिक कंटेनर में डालता है। बाइंड ऑपरेशन रिवर्स प्रक्रिया करता है, कंटेनर से मूल मूल्य को निकालता है और इसे पाइपलाइन में संबंधित अगले फ़ंक्शन को पास करता है।

एक प्रोग्रामर एक डाटा-प्रोसेसिंग पाइपलाइन को परिभाषित करने के लिए मोनैडिक फ़ंक्शन की रचना करेगा। मोनाड एक रूपरेखा के रूप में कार्य करता है, क्योंकि यह एक पुन: प्रयोज्य व्यवहार है जो उस क्रम को तय करता है जिसमें पाइप लाइन में विशिष्ट मोनैडिक कार्यों को कहा जाता है, और गणना द्वारा आवश्यक सभी अंडरकवर कार्य का प्रबंधन करता है। [३] प्रत्येक मोनैडिक फ़ंक्शन रिटर्न नियंत्रण के बाद पाइपलाइन में बंधे हुए बाइंड और रिटर्न ऑपरेटरों को निष्पादित किया जाएगा, और मोनाड द्वारा नियंत्रित विशेष पहलुओं का ध्यान रखेगा।

मेरा मानना ​​है कि यह इसे बहुत अच्छी तरह से समझाता है।


12

मैं सबसे छोटी परिभाषा बनाने की कोशिश करूँगा जिसे मैं OOP शब्दों का उपयोग करके प्रबंधित कर सकता हूँ:

एक सामान्य वर्ग CMonadic<T>एक सन्यासी है यदि वह कम से कम निम्नलिखित विधियों को परिभाषित करता है:

class CMonadic<T> { 
    static CMonadic<T> create(T t);  // a.k.a., "return" in Haskell
    public CMonadic<U> flatMap<U>(Func<T, CMonadic<U>> f); // a.k.a. "bind" in Haskell
}

और यदि निम्नलिखित कानून सभी प्रकार के टी और उनके संभावित मूल्यों के लिए लागू होते हैं

बाईं पहचान:

CMonadic<T>.create(t).flatMap(f) == f(t)

सही पहचान

instance.flatMap(CMonadic<T>.create) == instance

संबद्धता:

instance.flatMap(f).flatMap(g) == instance.flatMap(t => f(t).flatMap(g))

उदाहरण :

एक सूची मोनाद हो सकता है:

List<int>.create(1) --> [1]

और सूची पर फ्लैटपाइप [1,2,3] ऐसा काम कर सकता है:

intList.flatMap(x => List<int>.makeFromTwoItems(x, x*10)) --> [1,10,2,20,3,30]

Iterables और Observables को मोनैडिक और साथ ही प्रॉमिस और टास्क भी बनाया जा सकता है।

कमेंट्री :

मोनड्स उस जटिल नहीं हैं। flatMapसमारोह और अधिक सामान्यतः सामना करना पड़ा की तरह एक बहुत कुछ है map। यह एक फ़ंक्शन तर्क (जिसे प्रतिनिधि के रूप में भी जाना जाता है) प्राप्त करता है, जिसे वह जेनेरिक वर्ग से आने वाले मान के साथ (तुरंत या बाद में, शून्य या अधिक बार) कॉल कर सकता है। यह उम्मीद करता है कि उत्तीर्ण कार्य भी उसी तरह के सामान्य वर्ग में अपना रिटर्न मूल्य लपेटें। इसके साथ मदद करने के लिए, यह प्रदान करता है create, एक निर्माता जो एक मूल्य से उस सामान्य वर्ग का एक उदाहरण बना सकता है। फ्लैटपाइप का रिटर्न परिणाम भी उसी प्रकार का एक सामान्य वर्ग है, जो अक्सर उन्हीं मूल्यों को पैकिंग करता है जो पहले वाले निहित मूल्यों के लिए फ्लैटपाइप के एक या अधिक अनुप्रयोगों के रिटर्न परिणामों में समाहित थे। इससे आप जितना चाहें उतना फ्लैटपूल को चेन कर सकते हैं:

intList.flatMap(x => List<int>.makeFromTwo(x, x*10))
       .flatMap(x => x % 3 == 0 
                   ? List<string>.create("x = " + x.toString()) 
                   : List<string>.empty())

यह सिर्फ इतना होता है कि इस तरह का सामान्य वर्ग बड़ी संख्या में चीजों के लिए आधार मॉडल के रूप में उपयोगी है। यह (श्रेणी सिद्धांत शब्दजालवाद के साथ) यही कारण है कि मोनाड्स को समझने या समझाने में इतनी मेहनत लगती है। वे एक बहुत सार बात कर रहे हैं और केवल विशेष रूप से उपयोगी हो जाते हैं एक बार वे विशेष कर रहे हैं।

उदाहरण के लिए, आप मोनैडिक कंटेनरों का उपयोग करके अपवादों को मॉडल कर सकते हैं। प्रत्येक कंटेनर में या तो ऑपरेशन का परिणाम होगा या जो त्रुटि हुई है। फ्लैटपैप कॉलबैक की श्रृंखला में अगला फ़ंक्शन (डेलीगेट) केवल तभी कहा जाएगा जब पिछले एक कंटेनर में एक मूल्य पैक किया जाता है। अन्यथा यदि कोई त्रुटि पैक की गई थी, तो त्रुटि तब तक जंजीरों के कंटेनर के माध्यम से फैलती रहेगी जब तक कि एक कंटेनर नहीं मिल जाता है जिसमें एक त्रुटि हैंडलर फ़ंक्शन होता है जिसे विधि के माध्यम से संलग्न किया जाता है .orElse()(ऐसी विधि एक अनुमत एक्सटेंशन होगी)

नोट्स : कार्यात्मक भाषाएं आपको ऐसे कार्यों को लिखने की अनुमति देती हैं जो किसी भी तरह के एक सामान्य सामान्य वर्ग पर काम कर सकते हैं। इस काम के लिए, किसी को भिक्षुओं के लिए एक सामान्य इंटरफ़ेस लिखना होगा। मुझे नहीं पता कि क्या इसका इंटरफ़ेस C # में लिखना संभव है, लेकिन जहाँ तक मुझे पता है कि यह नहीं है:

interface IMonad<T> { 
    static IMonad<T> create(T t); // not allowed
    public IMonad<U> flatMap<U>(Func<T, IMonad<U>> f); // not specific enough,
    // because the function must return the same kind of monad, not just any monad
}

7

क्या OO में एक भिक्षु की "प्राकृतिक" व्याख्या है, जो भिक्षु पर निर्भर करता है। जावा जैसी भाषा में, आप शायद मुनद को अशक्त बिंदुओं के लिए जाँच करने की भाषा में अनुवाद कर सकते हैं, ताकि गणना विफल हो जाए (यानी, हास्केल में कुछ भी नहीं पैदा करें) परिणाम के रूप में अशक्त बिंदुओं का उत्सर्जन करें। आप एक राज्य को बदलने के लिए एक परिवर्तनशील चर और तरीकों का निर्माण करके राज्य मोनड को भाषा में अनुवाद कर सकते हैं।

एक monad एंडोफुन्क्टरों की श्रेणी में एक मोनॉयड है।

वाक्य जो जानकारी एक साथ रखता है वह बहुत गहरी है। और आप किसी भी अनिवार्य भाषा के साथ एक सनक में काम करते हैं। एक मोनड एक "अनुक्रमित" डोमेन विशिष्ट भाषा है। यह कुछ दिलचस्प गुणों को संतुष्ट करता है, जो एक साथ ले जाता है एक मोनाड को "अनिवार्य प्रोग्रामिंग" का गणितीय मॉडल बनाता है। हास्केल छोटी (या बड़ी) अनिवार्य भाषाओं को परिभाषित करना आसान बनाता है, जिन्हें विभिन्न तरीकों से जोड़ा जा सकता है।

OO प्रोग्रामर के रूप में, आप अपनी भाषा के वर्ग पदानुक्रम का उपयोग उन कार्यों या प्रक्रियाओं के प्रकारों को व्यवस्थित करने के लिए करते हैं जिन्हें एक संदर्भ में कहा जा सकता है, जिसे आप एक वस्तु कहते हैं। इस विचार पर एक मोनाड भी अमूर्त है, क्योंकि अलग-अलग संन्यासी को अनियंत्रित तरीके से जोड़ा जा सकता है, प्रभावी रूप से उप-मोनाड के सभी तरीकों को दायरे में "आयात" कर सकता है।

वास्तुकला में, एक तब स्पष्ट रूप से व्यक्त करने के लिए टाइप हस्ताक्षर का उपयोग करता है कि एक मूल्य की गणना के लिए किन संदर्भों का उपयोग किया जा सकता है।

इस उद्देश्य के लिए कोई भी मोनाड ट्रांसफार्मर का उपयोग कर सकता है, और सभी "मानक" मठों का एक उच्च गुणवत्ता संग्रह है:

  • सूची (गैर-नियतात्मक संगणना, एक सूची को एक डोमेन के रूप में मानकर)
  • हो सकता है कि (गणनाएँ विफल हो सकती हैं, लेकिन जिसके लिए रिपोर्टिंग महत्वहीन है)
  • त्रुटि (गणनाएँ जो विफल हो सकती हैं और अपवाद हैंडलिंग की आवश्यकता होती है
  • पाठक (गणना जो सादे हास्केल कार्यों की रचनाओं द्वारा दर्शाई जा सकती है)
  • लेखक (अनुक्रमिक "रेंडरिंग" / "लॉगिंग" (स्ट्रिंग्स, HTML आदि के साथ संगणना)
  • योगदान (जारी)
  • IO (अभिकलन जो अंतर्निहित कंप्यूटर सिस्टम पर निर्भर करता है)
  • राज्य (अभिकलन जिनके संदर्भ में एक परिवर्तनीय मूल्य होता है)

इसी मोनड ट्रांसफार्मर और प्रकार की कक्षाओं के साथ। टाइप क्लासेस अपने इंटरफेस को एकजुट करके मोनड्स के संयोजन के लिए एक पूरक दृष्टिकोण की अनुमति देते हैं, ताकि कंक्रीट के मोनड्स "मोद" के लिए एक मानक इंटरफ़ेस लागू कर सकें। उदाहरण के लिए, मॉड्यूल कंट्रोल.मनड.सेट में एक क्लास मोनडस्टेट सम्‍मिलित है, और (स्‍टेट एस) फॉर्म का एक उदाहरण है

instance MonadState s (State s) where
    put = ...
    get = ...

लंबी कहानी यह है कि एक मोनाड एक फ़नकार है जो एक मूल्य के लिए "संदर्भ" देता है, जिसमें एक मान को इंजेक्षन करने का एक तरीका है, और जिसके पास इसके साथ जुड़े संदर्भ के संबंध में मूल्यों का मूल्यांकन करने का एक तरीका है, कम से कम एक प्रतिबंधित तरीके से।

इसलिए:

return :: a -> m a

एक प्रकार्य है जो एक प्रकार के एक मान "एक्शन" में टाइप एम ए के मान को इंजेक्ट करता है।

(>>=) :: m a -> (a -> m b) -> m b

एक फ़ंक्शन है जो एक मोनड एक्शन लेता है, इसके परिणाम का मूल्यांकन करता है, और परिणाम के लिए एक फ़ंक्शन लागू करता है। (>> =) के बारे में साफ बात यह है कि परिणाम एक ही मोनाड में है। दूसरे शब्दों में, m >> = f, (>> =) परिणाम को m से बाहर निकालता है, और इसे f से बांधता है, ताकि परिणाम मोनाड में हो। (वैकल्पिक रूप से, हम कह सकते हैं कि (>> =) f को m में खींचता है और परिणाम पर लागू करता है।) परिणामस्वरूप, अगर हमारे पास f :: a -> mb, और g :: b -> mc, हम कर सकते हैं। "अनुक्रम" क्रियाएँ:

m >>= f >>= g

या, "नोटेशन" का उपयोग कर

do x <- m
   y <- f x
   g y

(>>) के लिए प्रकार रोशन हो सकता है। यह है

(>>) :: m a -> m b -> m b

सी। जैसी प्रक्रियात्मक भाषाओं में यह (;) ऑपरेटर से मेल खाती है। यह जैसे नोटेशन की अनुमति देता है:

m = do x <- someQuery
       someAction x
       theNextAction
       andSoOn

गणितीय और दार्शनिक तर्क में, हमारे पास फ्रेम और मॉडल हैं, जो "स्वाभाविक रूप से" अद्वैतवाद के साथ मॉडलिंग करते हैं। एक व्याख्या एक फ़ंक्शन है जो मॉडल के डोमेन में दिखता है और एक प्रस्ताव (या सामान्यीकरण के तहत सूत्र) के सत्य मूल्य (या सामान्यीकरण) की गणना करता है। आवश्यकता के लिए एक तार्किक तर्क में, हम कह सकते हैं कि एक प्रस्ताव आवश्यक है यदि यह "हर संभव दुनिया में" सच है - अगर यह हर स्वीकार्य डोमेन के संबंध में सच है। इसका मतलब यह है कि एक प्रस्ताव के लिए एक भाषा में एक मॉडल को एक मॉडल के रूप में फिर से परिभाषित किया जा सकता है, जिसके डोमेन में अलग-अलग मॉडल (प्रत्येक संभव दुनिया के अनुरूप) का संग्रह होता है। हर संन्यासी के पास "जॉइन" नाम की एक विधि होती है जो परतों को समतल करती है, जिसका अर्थ है कि प्रत्येक संन्यासी क्रिया जिसका परिणाम एक संन्यासी क्रिया है, जिसे मोनाड में एम्बेड किया जा सकता है।

join :: m (m a) -> m a

इससे भी महत्वपूर्ण बात, इसका मतलब है कि "परत स्टैकिंग" ऑपरेशन के तहत मोनाड बंद है। यह है कि मोनाड ट्रांसफॉर्मर कैसे काम करते हैं: वे प्रकारों के लिए "जॉइन-लाइक" तरीके प्रदान करके मोनाड्स को जोड़ते हैं

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

ताकि हम प्रभावी रूप से ढहने वाली परतों में एक क्रिया को (MightT m) को m में एक क्रिया में बदल सकें। इस स्थिति में, runMaybeT :: MightT ma -> m (हो सकता है) हमारी ज्वाइन विधि है। (शायद टीटी एम) एक मोनाड है, और आईआईटी :: एम (शायद ए) -> आईबीटी मा प्रभावी रूप से मी में एक नए प्रकार के मोनाड कार्रवाई के लिए एक निर्माता है।

एक फ़नकार के लिए एक नि: शुल्क मोनाड, एफ को स्टैकिंग द्वारा उत्पन्न किया जाने वाला मोनाद है, इस निहितार्थ के साथ कि च के लिए निर्माणकर्ताओं के हर अनुक्रम मुक्त मोनाड का एक तत्व है (या, अधिक सटीक रूप से, उसी आकार के साथ कुछ, जो निर्माणकर्ताओं के दृश्यों के वृक्ष के समान है। च)। बॉयलर-प्लेट की न्यूनतम मात्रा के साथ लचीले मोनैड्स के निर्माण के लिए नि: शुल्क मोनैड्स एक उपयोगी तकनीक है। हास्केल कार्यक्रम में, मैं "उच्च स्तरीय प्रणाली प्रोग्रामिंग" के लिए सरल साधुओं को परिभाषित करने में मदद करने के लिए मुफ्त साधुओं का उपयोग कर सकता हूं ताकि प्रकार की सुरक्षा को बनाए रखा जा सके (मैं केवल प्रकारों और उनकी घोषणाओं का उपयोग कर रहा हूं। कार्यान्वयन सीधे दहनकर्ताओं के उपयोग के साथ आगे हैं):

data RandomF r a = GetRandom (r -> a) deriving Functor
type Random r a = Free (RandomF r) a


type RandomT m a = Random (m a) (m a) -- model randomness in a monad by computing random monad elements.
getRandom     :: Random r r
runRandomIO   :: Random r a -> IO a (use some kind of IO-based backend to run)
runRandomIO'  :: Random r a -> IO a (use some other kind of IO-based backend)
runRandomList :: Random r a -> [a]  (some kind of list-based backend (for pseudo-randoms))

मोनडिज़्म एक अंतर्निहित वास्तुकला है जिसे आप "इंटरप्रेटर" या "कमांड" पैटर्न कह सकते हैं, जो अपने सबसे स्पष्ट रूप से सार है, क्योंकि प्रत्येक मोनडिक अभिकलन को "रन" होना चाहिए, कम से कम तुच्छ रूप से। (रनटाइम सिस्टम हमारे लिए IO मोनाड चलाता है, और किसी भी Haskell प्रोग्राम का प्रवेश बिंदु है। IO क्रम में IO क्रियाओं को चलाकर, बाकी संगणनाओं को "ड्राइव" करता है)।

जुड़ने का प्रकार भी है जहां हमें यह कथन मिलता है कि एक भिक्षु एंडोफुन्क्टरों की श्रेणी में एक भिक्षु है। सैद्धांतिक रूप से, इसके प्रकार के आधार पर, जुड़ना अधिक महत्वपूर्ण है। लेकिन प्रकार को समझने का अर्थ है, भिक्षुओं को समझना। फंक्शन कंपोजिशन के अर्थ में, जॉइन और मोनाड ट्रांसफॉर्मर के प्रकार, प्रभावी रूप से एंडोफुन्केर्स की रचनाएँ हैं। इसे हास्केल की तरह छद्म भाषा में रखने के लिए,

फू :: एम (मा) <-> (एम। एम) ए


3

एक मोनड कार्यों की एक सरणी है

(Pst: कार्यों की एक सरणी बस एक संगणना है)।

वास्तव में, एक सच्चे सरणी (एक सेल एरे में एक फ़ंक्शन) के बजाय आपके पास उन फ़ंक्शन हैं जो किसी अन्य फ़ंक्शन >> >> = फ़ंक्शन को फ़ंक्शन I + 1 से फ़ीड करने के लिए परिणामों को अनुकूलित करने की अनुमति देता है, उनके बीच गणना करें या, यहां तक ​​कि फ़ंक्शन i + 1 को कॉल करने के लिए नहीं।

यहाँ उपयोग किए जाने वाले प्रकार "संदर्भ के साथ प्रकार" हैं। यह एक "टैग" के साथ एक मूल्य है। जंजीर किए जाने वाले कार्यों को "नग्न मूल्य" लेना चाहिए और टैग किए गए परिणाम को वापस करना होगा। >> = के कर्तव्यों में से एक इसके संदर्भ से एक नग्न मूल्य निकालना है। फ़ंक्शन "वापसी" भी है, जो नग्न मूल्य लेता है और इसे एक टैग के साथ रखता है।

शायद के साथ एक उदाहरण । चलो एक सरल पूर्णांक को संग्रहीत करने के लिए इसका उपयोग करते हैं, जिस पर गणना करते हैं।

-- a * b
multiply :: Int -> Int -> Maybe Int
multiply a b = return  (a*b)

-- divideBy 5 100 = 100 / 5
divideBy :: Int -> Int -> Maybe Int
divideBy 0 _ = Nothing -- dividing by 0 gives NOTHING
divideBy denom num = return (quot num denom) -- quotient of num / denom

-- tagged value
val1 = Just 160 

-- array of functions feeded with val1
array1 = val1 >>= divideBy 2  >>= multiply 3 >>= divideBy  4 >>= multiply 3

-- array of funcionts created with the do notation
-- equals array1 but for the feeded val1
array2 :: Int -> Maybe Int
array2 n = do
       v <- divideBy 2  n
       v <- multiply 3 v
       v <- divideBy 4 v
       v <- multiply 3 v
       return v

-- array of functions, 
-- the first >>= performs 160 / 0, returning Nothing
-- the second >>= has to perform Nothing >>= multiply 3 ....
-- and simply returns Nothing without calling multiply 3 ....
array3 = val1 >>= divideBy 0  >>= multiply 3 >>= divideBy  4 >>= multiply 3

main = do
     print array1
     print (array2 160)
     print array3

बस यह दिखाने के लिए कि भिक्षुओं को सहायक कार्यों के साथ कार्यों का सरणी है, उपरोक्त उदाहरण के बराबर पर विचार करें, बस वास्तविक सरणी का उपयोग करके

type MyMonad = [Int -> Maybe Int] -- my monad as a real array of functions

myArray1 = [divideBy 2, multiply 3, divideBy 4, multiply 3]

-- function for the machinery of executing each function i with the result provided by function i-1
runMyMonad :: Maybe Int -> MyMonad -> Maybe Int
runMyMonad val [] = val
runMyMonad Nothing _ = Nothing
runMyMonad (Just val) (f:fs) = runMyMonad (f val) fs

और इसका उपयोग इस तरह किया जाएगा:

print (runMyMonad (Just 160) myArray1)

1
सुपर साफ! तो बाँध सिर्फ संदर्भ के साथ एक क्रम में, संदर्भ के साथ कार्यों के एक सरणी का मूल्यांकन करने का एक तरीका है :)
मूसा अल-परेशानी

>>=एक ऑपरेटर है
1524 में user2418306

1
मुझे लगता है कि "कार्यों की सरणी" सादृश्य बहुत स्पष्ट नहीं करता है। यदि \x -> x >>= k >>= l >>= mकार्यों की एक सरणी है, तो यह है h . g . f, जो सभी में भिक्षुओं को शामिल नहीं करता है।
डूप्लोड

हम कह सकते हैं कि फंक्शनलर्स , चाहे वे मोनैडिक, एप्लिकेटिव या प्लेन हों, "अलंकृत एप्लिकेशन" के बारे में हैं । ining एप्लिकेटिव ’चेनिंग जोड़ता है, और ad मोनड’ निर्भरता जोड़ता है (यानी पिछले गणना कदम से परिणामों के आधार पर अगला गणना कदम बना रहा है)।
विल नेस

3

OO के संदर्भ में, एक सनक एक धाराप्रवाह कंटेनर है।

न्यूनतम आवश्यकता एक परिभाषा है class <A> Somethingजो एक निर्माता Something(A a)और कम से कम एक विधि का समर्थन करती हैSomething<B> flatMap(Function<A, Something<B>>)

यकीनन, यह भी गिना जाता है कि आपके मोनड क्लास के पास हस्ताक्षर के साथ कोई भी तरीका है Something<B> work()जो क्लास के नियमों को संरक्षित करता है - संकलनकर्ता समतल समय पर फ्लैटपैक में।

एक मोनाद क्यों उपयोगी है? क्योंकि यह एक कंटेनर है जो श्रृंखला-सक्षम संचालन की अनुमति देता है जो शब्दार्थ को संरक्षित करता है। उदाहरण के लिए, Optional<?>के लिए isPresent के शब्दों को बरकरार रखता है Optional<String>, Optional<Integer>, Optional<MyClass>, आदि

एक मोटे उदाहरण के रूप में,

Something<Integer> i = new Something("a")
  .flatMap(doOneThing)
  .flatMap(doAnother)
  .flatMap(toInt)

ध्यान दें कि हम एक स्ट्रिंग से शुरू करते हैं और एक पूर्णांक के साथ समाप्त होते हैं। बहुत अच्छा।

OO में, यह थोड़ा हाथ से लहराता है, लेकिन किसी चीज़ पर कोई विधि जो किसी चीज़ का दूसरा उपवर्ग लौटाती है, कंटेनर फ़ंक्शन की कसौटी पर खरी उतरती है जो मूल प्रकार के कंटेनर को लौटाती है।

यही कारण है कि आप शब्दार्थ को संरक्षित करते हैं - अर्थात कंटेनर के अर्थ और संचालन नहीं बदलते हैं, वे सिर्फ कंटेनर के अंदर वस्तु को लपेटते हैं और बढ़ाते हैं।


2

ठेठ उपयोग में मोनाड प्रक्रियात्मक प्रोग्रामिंग के अपवाद हैंडलिंग तंत्र के कार्यात्मक समकक्ष हैं।

आधुनिक प्रक्रियात्मक भाषाओं में, आप एक अपवाद हैंडलर को कथनों के अनुक्रम के चारों ओर रखते हैं, जिनमें से कोई भी अपवाद फेंक सकता है। यदि कोई भी कथन एक अपवाद फेंकता है, तो बयानों के अनुक्रम का सामान्य निष्पादन रुक जाता है और एक अपवाद हैंडलर को स्थानांतरित हो जाता है।

फ़ंक्शनल प्रोग्रामिंग लैंग्वेज, हालांकि, दार्शनिक रूप से उन की प्रकृति की तरह "गोटो" के कारण अपवाद हैंडलिंग सुविधाओं से बचती हैं। कार्यात्मक प्रोग्रामिंग परिप्रेक्ष्य यह है कि फ़ंक्शन को प्रोग्राम प्रवाह को बाधित करने वाले अपवादों की तरह "साइड-इफेक्ट्स" नहीं होने चाहिए।

वास्तव में, साइड-इफेक्ट्स को मुख्य रूप से I / O के कारण वास्तविक दुनिया में खारिज नहीं किया जा सकता है। फ़ंक्शनल प्रोग्रामिंग में मोनाड्स का उपयोग जंजीर फ़ंक्शन कॉल (जिनमें से कोई भी एक अप्रत्याशित परिणाम उत्पन्न कर सकता है) का एक सेट लेकर और किसी भी अप्रत्याशित परिणाम को एन्कैप्सुलेटेड डेटा में बदलकर किया जाता है जो अभी भी शेष फ़ंक्शन कॉल के माध्यम से सुरक्षित रूप से प्रवाह कर सकते हैं।

नियंत्रण का प्रवाह संरक्षित है लेकिन अप्रत्याशित घटना सुरक्षित रूप से समझाया और संभाला है।


2

मार्वल के केस स्टडी के साथ एक सरल मोनाड्स स्पष्टीकरण यहाँ है

मोनाड्स आश्रित हैं जो आश्रित कार्यों को अनुक्रमित करने के लिए उपयोग किए जाते हैं। यहाँ प्रभावशाली का मतलब है कि वे F [A] के रूप में एक प्रकार लौटाते हैं उदाहरण के लिए विकल्प [A] जहाँ विकल्प F है, जिसे टाइप कंस्ट्रक्टर कहा जाता है। आइए इसे 2 सरल चरणों में देखें

  1. नीचे फ़ंक्शन रचना सकर्मक है। अतः A से CI पर जाने के लिए A => B और B => C लिख सकते हैं।
 A => C   =   A => B  andThen  B => C

यहां छवि विवरण दर्ज करें

  1. हालाँकि, यदि फ़ंक्शन एक प्रभाव प्रकार लौटाता है जैसे विकल्प [A] अर्थात A => F [B] रचना B के पास जाने के लिए काम नहीं करती है तो हमें A => B की आवश्यकता होती है लेकिन हमारे पास A => F [B] है।
    यहां छवि विवरण दर्ज करें

    हमें एक विशेष ऑपरेटर की आवश्यकता है, "बाइंड" जो जानता है कि इन कार्यों को फ्यूज करना है जो एफ [ए] वापस करते हैं।

 A => F[C]   =   A => F[B]  bind  B => F[C]

"बाँध" समारोह विशिष्ट के लिए परिभाषित किया गया है एफ

" " भी है , किसी भी ए के लिए टाइप ए => एफ [ए] , कि विशिष्ट के लिए परिभाषित एफ भी। मोनाड होने के लिए, F के पास इसके लिए परिभाषित ये दो कार्य होने चाहिए।

इस प्रकार हम किसी भी शुद्ध कार्य से एक प्रभावशाली कार्य ए => एफ [बी] का निर्माण कर सकते हैं A => B ,

 A => F[B]   =   A => B  andThen  return

लेकिन एक एफ भी अपनी स्वयं की अपारदर्शी "निर्मित" को इस तरह के विशेष कार्यों में परिभाषित कर सकता है कि कोई उपयोगकर्ता खुद को ( शुद्ध भाषा में) परिभाषित नहीं कर सकता , जैसे

  • "रैंडम" ( रेंज => रैंडम [इंट] )
  • "प्रिंट" ( स्ट्रिंग => IO [()] )
  • "कोशिश ... पकड़", आदि।

2

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


1

यदि आपने कभी पॉवर्स का उपयोग किया है, तो एरिक द्वारा वर्णित पैटर्न को परिचित होना चाहिए। पॉवर्सशेल cmdlets मोनड हैं; कार्यात्मक संरचना को एक पाइपलाइन द्वारा दर्शाया जाता है

एरिक मीजर के साथ जेफरी स्नोवर का साक्षात्कार और अधिक विस्तार में जाता है।


1

मेरी देखें जवाब करने के लिए "क्या एक इकाई है?"

यह एक प्रेरक उदाहरण से शुरू होता है, उदाहरण के माध्यम से काम करता है, एक मोनड का उदाहरण देता है, और औपचारिक रूप से "मोनाड" को परिभाषित करता है।

यह कार्यात्मक प्रोग्रामिंग का कोई ज्ञान नहीं मानता है और यह function(argument) := expressionसरलतम संभव अभिव्यक्तियों के साथ वाक्यविन्यास के साथ छद्मकोड का उपयोग करता है ।

यह C ++ प्रोग्राम स्यूडोसोकोड मोनड का कार्यान्वयन है। (संदर्भ के लिए: Mटाइप कंस्ट्रक्टर feedहै, "बाइंड" ऑपरेशन है, और wrap"रिटर्न" ऑपरेशन है।)

#include <iostream>
#include <string>

template <class A> class M
{
public:
    A val;
    std::string messages;
};

template <class A, class B>
M<B> feed(M<B> (*f)(A), M<A> x)
{
    M<B> m = f(x.val);
    m.messages = x.messages + m.messages;
    return m;
}

template <class A>
M<A> wrap(A x)
{
    M<A> m;
    m.val = x;
    m.messages = "";
    return m;
}

class T {};
class U {};
class V {};

M<U> g(V x)
{
    M<U> m;
    m.messages = "called g.\n";
    return m;
}

M<T> f(U x)
{
    M<T> m;
    m.messages = "called f.\n";
    return m;
}

int main()
{
    V x;
    M<T> m = feed(f, feed(g, wrap(x)));
    std::cout << m.messages;
}

0

व्यावहारिक दृष्टिकोण से (पिछले कई उत्तरों और संबंधित लेखों में जो कहा गया है) संक्षेप में, यह मुझे प्रतीत होता है कि मोनाड के मौलिक "उद्देश्यों" (या उपयोगिता) में से एक पुनरावृत्ति विधि के आक्रमणों में निहित निर्भरता का लाभ उठाना है। उर्फ़ फंक्शन कंपोज़िशन (यानी जब f1 कॉल f2 कॉल f3, f3 से पहले f3 से पहले f3 से पहले मूल्यांकन किया जाना चाहिए) एक प्राकृतिक तरीके से अनुक्रमिक रचना का प्रतिनिधित्व करने के लिए, विशेष रूप से एक आलसी मूल्यांकन मॉडल के संदर्भ में (यानी, क्रमिक अनुक्रम एक सादे अनुक्रम के रूप में) , जैसे "f3 (); f2 (); f1 ();" सी में - ट्रिक विशेष रूप से स्पष्ट है यदि आप ऐसे मामले के बारे में सोचते हैं जहां f3, f2 और f1 वास्तव में कुछ भी नहीं लौटाते हैं [F1 (f2 (f3) के रूप में उनका पीछा) कृत्रिम है, विशुद्ध रूप से अनुक्रम बनाने का इरादा])।

यह विशेष रूप से प्रासंगिक है जब साइड-इफेक्ट्स शामिल होते हैं, अर्थात जब कुछ स्थिति बदल जाती है (यदि f1, f2, f3 का कोई साइड-इफेक्ट नहीं था, तो यह मायने नहीं रखेगा कि उनका मूल्यांकन किस क्रम में किया गया है; जो शुद्ध की एक बड़ी संपत्ति है। कार्यात्मक भाषाओं, उदाहरण के लिए उन संगणनाओं को समानांतर करने में सक्षम होना)। अधिक शुद्ध कार्य, बेहतर।

मुझे लगता है कि उस संकीर्ण दृष्टिकोण से, भाषा के मूल्यांकन के लिए मोनडैक्ट को चीनी के रूप में देखा जा सकता है जो आलसी मूल्यांकन के पक्ष में है (जो कि केवल तब आवश्यक चीजों का मूल्यांकन करता है, एक आदेश का पालन करता है जो कोड की प्रस्तुति पर भरोसा नहीं करता है), और यह है कि नहीं अनुक्रमिक रचना का प्रतिनिधित्व करने के अन्य साधन। शुद्ध परिणाम कोड के ऐसे खंड हैं जो "अशुद्ध" होते हैं (अर्थात जिनके साइड-इफेक्ट्स होते हैं) स्वाभाविक रूप से, अनिवार्य रूप से प्रस्तुत किए जा सकते हैं, फिर भी शुद्ध रूप से शुद्ध कार्यों (बिना साइड-इफेक्ट्स) से अलग किए जा सकते हैं, जो हो सकते हैं आलस्य का मूल्यांकन किया।

यह केवल एक पहलू है, हालांकि यहां चेतावनी दी गई है


0

सबसे सरल स्पष्टीकरण जो मैं सोच सकता हूं, वह यह है कि भिक्षु सुशोभित परिणामों (उर्फ क्लेसीली रचना) के साथ रचना करने का एक तरीका है। एक "एम्बेलिश्ड" फंक्शन में सिग्नेचर होता है a -> (b, smth)जहां aऔर bटाइप (थिंक ) होते हैं Int, Boolजो एक-दूसरे से अलग हो सकते हैं, लेकिन जरूरी नहीं - और smth"संदर्भ" या "इमेल" हो।

इस प्रकार के कार्यों को भी लिखा जा सकता है, a -> m bजहां m"अलंकरण" के बराबर है smth। तो ये फ़ंक्शन हैं जो संदर्भ में मान लौटाते हैं (लगता है कि फ़ंक्शंस जो अपने कार्यों को लॉग करते हैं, smthलॉगिंग संदेश कहां है; या ऐसे कार्य जो इनपुट \ आउटपुट करते हैं और उनके परिणाम आईओ कार्रवाई के परिणाम पर निर्भर करते हैं)।

एक मोनाड एक इंटरफ़ेस ("टाइपकास्ट") है जो कार्यान्वयनकर्ता को यह बताता है कि इस तरह के कार्यों की रचना कैसे की जाती है। कार्यान्वयनकर्ता को (a -> m b) -> (b -> m c) -> (a -> m c)किसी भी प्रकार के लिए एक रचना फ़ंक्शन को परिभाषित करने की आवश्यकता है mजो इंटरफ़ेस को लागू करना चाहता है (यह क्लेस्ली रचना है)।

इसलिए, अगर हम कहते हैं कि हमारे पास tuple प्रकार है, (Int, String)जो गणनाओं के परिणामों का प्रतिनिधित्व करता है, Intजो कि उनके कार्यों को भी लॉग करते हैं, (_, String)"एम्बेलिशन" होने के साथ - कार्रवाई का लॉग - और दो फ़ंक्शन increment :: Int -> (Int, String)और twoTimes :: Int -> (Int, String)हम एक फ़ंक्शन प्राप्त करना चाहते हैं, incrementThenDouble :: Int -> (Int, String)जो रचना है दो कार्य जो लॉग को भी ध्यान में रखते हैं।

दिए गए उदाहरण पर, दो कार्यों का एक मोनड कार्यान्वयन पूर्णांक मान 2 incrementThenDouble 2(जो कि बराबर है twoTimes (increment 2)) पर लागू होता है (6, " Adding 1. Doubling 3."), मध्यस्थ के परिणाम के increment 2बराबर (3, " Adding 1.")और twoTimes 3बराबर होगा(6, " Doubling 3.")

इस क्लेस्ली रचना समारोह से एक सामान्य मौद्रिक कार्यों को प्राप्त कर सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.