शायद मोनड बनाम अपवाद


34

मुझे आश्चर्य है कि अपवादों पर Maybe मोनाड के फायदे क्या हैं ? ऐसा लगता है कि सिंटैक्स Maybeका सिर्फ स्पष्ट (और अंतरिक्ष-उपभोग) तरीका है try..catch

अद्यतन करें कृपया ध्यान दें कि मैं जानबूझकर हास्केल का उल्लेख नहीं कर रहा हूं ।

जवाबों:


57

का उपयोग करना Maybe(या उसके चचेरे भाई Eitherजो मूल रूप से उसी तरह काम करता है लेकिन आपको इसके स्थान पर एक मनमाना मूल्य वापस करने की अनुमति देता है Nothing) अपवादों से थोड़ा अलग उद्देश्य प्रदान करता है। जावा के संदर्भ में, यह रनटाइम अपवाद के बजाय एक जाँच अपवाद है। यह किसी ऐसी चीज का प्रतिनिधित्व करता है, जिसकी अपेक्षा आपको एक ऐसी त्रुटि से करनी है, जिसकी अपेक्षा आपने नहीं की थी।

तो एक फ़ंक्शन जैसा indexOfकोई Maybeमान लौटाएगा क्योंकि आप इस संभावना की अपेक्षा करते हैं कि आइटम सूची में नहीं है। यह nullएक प्रकार्य-सुरक्षित तरीके को छोड़कर किसी फ़ंक्शन से लौटने जैसा है, जो आपको nullमामले से निपटने के लिए मजबूर करता है। Eitherउसी तरह से काम करता है, सिवाय इसके कि आप त्रुटि मामले से जुड़ी जानकारी वापस कर सकते हैं, इसलिए यह वास्तव में अपवाद के समान है Maybe

तो Maybe/ Eitherदृष्टिकोण के फायदे क्या हैं ? एक के लिए, यह भाषा का प्रथम श्रेणी का नागरिक है। चलो Eitherएक अपवाद का उपयोग करके फ़ंक्शन की तुलना करें । अपवाद मामले के लिए, आपका एकमात्र वास्तविक सहारा एक try...catchबयान है। के लिए Eitherसमारोह, आप मौजूदा combinators का उपयोग प्रवाह नियंत्रण स्पष्ट करने के सकता है। यहां कुछ उदाहरण दिए गए हैं:

सबसे पहले, मान लें कि आप कई कार्यों को आज़माना चाहते हैं जो एक पंक्ति में त्रुटि कर सकते हैं जब तक कि आपको एक ऐसा नहीं मिलता। यदि आपको कोई त्रुटि नहीं मिलती है, तो आप एक विशेष त्रुटि संदेश वापस करना चाहते हैं। यह वास्तव में एक बहुत ही उपयोगी पैटर्न है लेकिन इसका उपयोग करते हुए एक भयानक दर्द होगा try...catch। खुशी से, चूंकि Eitherसिर्फ एक सामान्य मूल्य है, आप कोड को अधिक स्पष्ट करने के लिए मौजूदा कार्यों का उपयोग कर सकते हैं:

firstThing <|> secondThing <|> throwError (SomeError "error message")

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

do a <- getA
   b <- getB
   optional (optimize query)
   execute query a b

ये दोनों मामले स्पष्ट और उपयोग करने से कम हैं try..catch, और, अधिक महत्वपूर्ण बात, अधिक अर्थपूर्ण। किसी फ़ंक्शन का उपयोग करना <|>या हमेशा अपवादों को हैंडल करने की तुलना में optionalअपने इरादों को अधिक स्पष्ट try...catchकरना।

यह भी ध्यान दें कि आपको अपने कोड को लाइनों की तरह नहीं रखना है if a == Nothing then Nothing else ...! इलाज Maybeऔर Eitherएक सनक के रूप में इस से बचने के लिए पूरे बिंदु है । आप बाइंड फ़ंक्शन में प्रचार शब्दार्थ को सांकेतिक शब्दों में बदलना कर सकते हैं ताकि आपको मुफ्त में अशक्त / त्रुटि जांच मिल सके। आपके पास स्पष्ट रूप से जांचने का एकमात्र समय है यदि आप Nothingदिए गए ए के अलावा कुछ और वापस करना चाहते हैं Nothing, और फिर भी यह आसान है: उस कोड को अच्छे बनाने के लिए मानक पुस्तकालय कार्यों का एक समूह है।

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

एक अन्य जीत यह है कि Maybe/ Eitherफंक्शनलर्स और मोनड्स हैं, जिसका अर्थ है कि वे मौजूदा मोनाड नियंत्रण प्रवाह कार्यों का लाभ उठा सकते हैं (जिनमें से एक उचित संख्या है) और, सामान्य रूप से, अन्य साधुओं के साथ अच्छी तरह से खेलते हैं।

उस ने कहा, कुछ कैवियट हैं। एक के लिए, न तो Maybeऔर न ही अनियंत्रित अपवादों को Eitherप्रतिस्थापित करें । आप 0 से विभाजित करने जैसी चीजों को संभालने के लिए कुछ और तरीका चाहते हैं क्योंकि यह एक दर्द होगा कि हर एक डिवीजन का मूल्य वापस आ जाए ।Maybe

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

फिर भी, मैं अधिक Maybe/ Eitherदृष्टिकोण को पसंद करता हूं क्योंकि मुझे यह सरल और अधिक लचीला लगता है।


ज्यादातर सहमत हैं, लेकिन मुझे नहीं लगता कि "वैकल्पिक" उदाहरण समझ में आता है - ऐसा लगता है कि आप ऐसा कर सकते हैं और साथ ही अपवाद भी कर सकते हैं: शून्य वैकल्पिक (एक्शन एक्ट) {कोशिश {अधिनियम (); } catch (अपवाद) {}}
Errorsatz

11
  1. एक अपवाद समस्या के स्रोत के बारे में अधिक जानकारी ले सकता है। OpenFile()फेंक FileNotFoundया NoPermissionया सकता है TooManyDescriptors। कोई भी इस जानकारी को नहीं ले जाता है।
  2. अपवाद उन संदर्भों में उपयोग किए जा सकते हैं जिनमें रिटर्न मानों की कमी होती है (जैसे कि उनके पास मौजूद भाषाओं में निर्माणकर्ता)।
  3. एक अपवाद आपको बहुत आसानी से स्टैक अप की जानकारी भेजने की अनुमति देता है, बिना if None return None-स्टाइल स्टेटमेंट के।
  4. लगभग हमेशा एक मूल्य को वापस लेने की तुलना में उच्च प्रदर्शन प्रभाव को संभालने वाला अपवाद।
  5. सबसे महत्वपूर्ण बात, एक अपवाद और शायद एक सनक के अलग-अलग उद्देश्य हैं - एक अपवाद का उपयोग किसी समस्या को इंगित करने के लिए किया जाता है, जबकि एक शायद नहीं है।

    "नर्स, अगर कमरा 5 में कोई मरीज है, तो क्या आप उसे इंतजार करने के लिए कह सकते हैं?"

    • शायद मोनाद: "डॉक्टर, कमरा 5 में कोई मरीज नहीं है।"
    • अपवाद: "डॉक्टर, कोई कमरा नहीं है 5!"

    ("अगर" नोटिस - इसका मतलब है कि डॉक्टर शायद एक सनक की उम्मीद कर रहे हैं )


7
मैं अंक 2 और 3 से सहमत नहीं हूं। विशेष रूप से, 2 वास्तव में भाषाओं में एक समस्या पैदा नहीं करता है जो कि भिक्षुओं का उपयोग करते हैं क्योंकि उन भाषाओं में अभिसमय हैं जो निर्माण के दौरान विफलता को संभालने के लिए पैदा नहीं करते हैं। 3 के बारे में, भिक्षुओं के साथ भाषाओं में पारदर्शी तरीके से भिक्षुओं को संभालने के लिए उपयुक्त वाक्यविन्यास होता है जिसमें स्पष्ट जाँच की आवश्यकता नहीं होती है (उदाहरण के लिए, Noneमानों को केवल प्रचारित किया जा सकता है)। आपकी बात 5 ही सही है ... सवाल यह है कि कौन सी परिस्थितियाँ स्पष्ट रूप से असाधारण हैं? जैसा कि यह पता चला है ... कई नहीं
कोनराड रुडोल्फ

3
(2) के संबंध में, आप bindइस तरह से लिख सकते हैं कि परीक्षण के लिए Noneएक सिंटैक्टिक ओवरहेड को लाइक नहीं करता है। एक बहुत ही सरल उदाहरण, C # बस Nullableऑपरेटरों को उचित रूप से अधिभारित करता है। Noneप्रकार का उपयोग करते समय भी आवश्यक के लिए कोई जाँच नहीं । बेशक चेक अभी भी किया जाता है (यह सुरक्षित है), लेकिन पर्दे के पीछे और अपने कोड को अव्यवस्थित नहीं करता है। वही कुछ आपत्ति के लिए मेरी आपत्ति (5) पर लागू होता है, लेकिन मैं मानता हूं कि यह हमेशा लागू नहीं हो सकता है।
कोनराड रुडोल्फ

4
@Oak: (3) के संबंध में, एक सन्यासी के रूप में व्यवहार करने का पूरा मतलब Maybeप्रचार प्रसार करना Noneहै। इसका मतलब है कि यदि आप Noneदिए गए रिटर्न को वापस करना चाहते हैं None, तो आपको कोई विशेष कोड लिखने की आवश्यकता नहीं है। आपको मैच के लिए केवल तभी समय चाहिए जब आप कुछ विशेष करना चाहते हैं None। आपको कभी भी if None then Noneकथनों की आवश्यकता नहीं है ।
तिखन जेल्विस

5
@ ओक: यह सच है, लेकिन यह वास्तव में मेरी बात नहीं थी। मैं जो कह रहा हूं वह यह है कि आप nullबिल्कुल वैसे ही चेक करें (जैसे if Nothing then Nothing) मुफ्त में क्योंकि Maybeएक सन्यासी है। यह बाइंड की परिभाषा में एन्कोडेड है ( >>=) के लिए Maybe
तिखन जेल्विस

2
इसके अलावा, (1) के बारे में: आप आसानी से एक मोनाड लिख सकते हैं जो त्रुटि सूचना (जैसे Either) ले जा सकता है जो बिल्कुल व्यवहार करता है MaybeMaybeवास्तव में सिर्फ एक विशेष मामला है क्योंकि दोनों के बीच स्विच करना वास्तव में सरल है Either। (में हास्केल, तो आप के बारे में सोच सकता है Maybeके रूप में Either ()।)
टिकोन Jelvis

6

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


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

3
@ डायलेन: मैं यह नहीं कह रहा हूं कि एक लापता मूल्य कभी भी एक असाधारण स्थिति का संकेत नहीं हो सकता है - यह सिर्फ होना ही नहीं है। हो सकता है कि वास्तव में एक ऐसी स्थिति का मॉडल हो जहां एक चर का मान हो या न हो - C # में अशक्त प्रकार सोचें।
नेमंजा ट्रिफ़ुनोविक

6

मैं दूसरे टिखोन का जवाब देता हूं, लेकिन मुझे लगता है कि बहुत महत्वपूर्ण व्यावहारिक बिंदु है जो हर किसी को याद आ रहा है:

  1. कम से कम मुख्यधारा की भाषाओं में अपवाद हैंडलिंग तंत्र, व्यक्तिगत रूप से अलग-अलग धागों के साथ जोड़े जाते हैं।
  2. इस Eitherतंत्र को धागों से जोड़ा नहीं जाता है।

तो कुछ जो हम आजकल वास्तविक जीवन में देख रहे हैं, वह यह है कि कई अतुल्यकालिक प्रोग्रामिंग समाधान Eitherत्रुटि हैंडलिंग के -स्टाइल के एक संस्करण को अपना रहे हैं । जावास्क्रिप्ट वादों पर विचार करें , जैसा कि इनमें से किसी भी लिंक में विस्तृत है:

वादों की अवधारणा आपको इस तरह अतुल्यकालिक कोड लिखने की अनुमति देती है (अंतिम लिंक से लिया गया):

var greetingPromise = sayHello();
greetingPromise
    .then(addExclamation)
    .then(function (greeting) {
        console.log(greeting);    // 'hello world!!!!’
    }, function(error) {
        console.error('uh oh: ', error);   // 'uh oh: something bad happened’
    });

मूल रूप से, एक वादा एक वस्तु है कि:

  1. एक अतुल्यकालिक गणना के परिणाम का प्रतिनिधित्व करता है, जो अभी तक समाप्त हो भी सकता है और नहीं भी;
  2. आपको इसके परिणाम पर प्रदर्शन करने के लिए आगे के संचालन की श्रृंखला बनाने की अनुमति देता है, जो उस परिणाम के उपलब्ध होने पर चालू हो जाएगा, और जिसके परिणाम बदले में वादे के लिए उपलब्ध हैं;
  3. यदि आप प्रतिज्ञा की विफलता विफल हो जाती है, तो आपको असफल हैंडलर को हुक करने की अनुमति देता है। यदि कोई हैंडलर नहीं है, तो त्रुटि श्रृंखला में बाद के हैंडलर को प्रचारित की जाती है।

मूल रूप से, के बाद से भाषा की मूल अपवाद समर्थन काम जब अपने गणना एक से अधिक थ्रेड भर में हो रहा है नहीं है, एक वादे कार्यान्वयन एक त्रुटि हैंडलिंग प्रणाली प्रदान करने के लिए है, और इन हास्केल के समान monads होने के लिए बाहर बारी Maybe/ Eitherप्रकार के।


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

1

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


1
जावा में कुछ अपवाद हैं। और लोग अक्सर उनके साथ बहुत बुरा व्यवहार करते थे।
व्लादिमीर

1
@ DairT'arg ButJava को IO त्रुटियों (उदाहरण के लिए) के लिए चेक की आवश्यकता होती है, लेकिन NPEs के लिए नहीं। हास्केल में यह दूसरा तरीका है: अशक्त समतुल्य (शायद) की जाँच की जाती है, लेकिन IO त्रुटियाँ केवल (अनियंत्रित) अपवादों को फेंकती हैं। मैं अनिश्चित हूं कि इससे कितना अंतर पड़ता है, लेकिन मैंने हास्केलर्स को शायद शिकायत के बारे में नहीं सुना है और मुझे लगता है कि बहुत सारे लोग चाहेंगे कि एनपीई की जांच हो।

1
@delnan लोग चाहते हैं कि NPE को चेक किया जाए? उन्हें पागल होना चाहिए। और मेरा मतलब है कि। NPE चेक करना केवल तभी समझ में आता है जब आपके पास इसे पहली जगह से बचने का एक तरीका है (गैर-अशक्त संदर्भ होने से, जो जावा के पास नहीं है)।
कोनराड रुडोल्फ

5
@KonradRudolph जी हाँ, लोग शायद इस अर्थ में जाँच नहीं करना चाहते हैं कि उन्हें throws NPEहर एक हस्ताक्षर और catch(...) {throw ...} हर एक विधि निकाय में जोड़ना पड़ेगा । लेकिन मेरा मानना ​​है कि शायद एक ही अर्थ में जाँच के लिए बाजार है: शायद अशक्तता वैकल्पिक है और प्रकार प्रणाली में ट्रैक किया गया है।

1
@ डेलनान आह, तो मैं सहमत हूं।
कोनराड रुडोल्फ

0

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


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

वास्तव में। आपको कैसे लगता है कि इसे स्पष्ट किया जाना चाहिए?
तेलस्टिन

@ कोनराड ऐसा इसलिए है क्योंकि हो सकता है कि मूल्य (संभवतः) का उपयोग करने के लिए, आपको किसी के लिए भी जांच करनी चाहिए (हालांकि निश्चित रूप से उस जाँच को स्वचालित करने की क्षमता है)। अन्य भाषाएँ उस तरह की चीज़ों को मैनुअल रखती हैं (ज्यादातर दार्शनिक कारणों से मेरा मानना ​​है)।
डोनल फेलो

2
@ डोनल हाँ, लेकिन ध्यान दें कि अधिकांश भाषाएं जो मोनस को लागू करती हैं, उपयुक्त संश्लिष्ट चीनी प्रदान करती हैं ताकि यह जाँच प्रायः पूरी तरह से छिपी रह सके। उदाहरण के लिए, आप जांच करने की आवश्यकता के बिना केवल दो Maybeनंबर जोड़ सकते हैं , और परिणाम एक बार फिर से वैकल्पिक मूल्य है। a + b None
कोनराड रूडोल्फ

2
नल प्रकार के साथ तुलना के लिए सच है Maybe प्रकार है, लेकिन का उपयोग कर Maybeएक इकाई के रूप में वाक्य रचना चीनी कि व्यक्त की अनुमति देता है एक बहुत अधिक सुंदर ढंग से अशक्त-ish तर्क कहते हैं।
तदमर्स

0

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

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

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

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

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