हास्केल में त्रुटियों की रिपोर्ट करने का सबसे साफ तरीका


22

मैं हास्केल सीखने पर काम कर रहा हूं, और मेरे द्वारा लिखे गए कार्यों में त्रुटियों से निपटने के तीन अलग-अलग तरीके हैं।

  1. मैं बस लिख सकता हूं error "Some error message.", जो एक अपवाद फेंकता है।
  2. मैं अपना फ़ंक्शन वापस कर सकता हूं Maybe SomeType, जहां मैं वापसी करने में सक्षम हो सकता हूं या नहीं कर सकता हूं।
  3. मैं अपने फ़ंक्शन को वापस कर सकता हूं Either String SomeType, जहां मैं या तो एक त्रुटि संदेश वापस कर सकता हूं या मुझे पहले स्थान पर लौटने के लिए कहा गया था।

मेरा प्रश्न है: त्रुटियों से निपटने की मुझे किस विधि का उपयोग करना चाहिए, और क्यों? शायद मुझे संदर्भ के आधार पर अलग-अलग तरीके चाहिए?

मेरी वर्तमान समझ है:

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

जवाबों:


32

ठीक है, हास्केल में त्रुटि से निपटने का पहला नियम: कभी भी उपयोग न करेंerror

यह हर तरह से भयानक है। यह विशुद्ध रूप से इतिहास के एक अधिनियम के रूप में मौजूद है और प्रेडल इसे उपयोग करने वाले तथ्य भयानक है। इसका उपयोग न करें।

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

अब सवाल Maybeबनाम बन जाता है EitherMaybeअच्छी तरह से कुछ के लिए अनुकूल है head, जो मान वापस कर सकता है या नहीं कर सकता है लेकिन असफल होने का केवल एक संभावित कारण है। Nothingकुछ ऐसा कह रहा है जैसे "यह टूट गया, और आप पहले से ही जानते हैं कि क्यों"। कुछ लोग कहेंगे कि यह एक आंशिक कार्य को इंगित करता है।

त्रुटि से निपटने का सबसे मजबूत रूप Either+ ADT एक त्रुटि है।

उदाहरण के लिए मेरे एक शौक कंपाइलर में, मुझे कुछ पसंद है

data CompilerError = ParserError ParserError
                   | TCError TCError
                   ...
                   | ImpossibleError String

data ParserError = ParserError (Int, Int) String
data TCError = CouldntUnify Ty Ty
             | MissingDefinition Name
             | InfiniteType Ty
             ...

type ErrorM m = ExceptT CompilerError m -- from MTL

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

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

अंत में मैं इस प्रकार को ExceptTएमटीएल से एक नया मोनाड ट्रांसफार्मर में पैक करता हूं । यह अनिवार्य रूप से है EitherTऔर शुद्ध, सुखद तरीके से त्रुटियों को फेंकने और पकड़ने के लिए कार्यों का एक अच्छा बैच है।

अंत में, यह उल्लेखनीय है कि हास्केल के पास अन्य भाषाओं की तरह अपवादों को संभालने का तंत्र है, सिवाय इसके कि अपवाद जीवन को पकड़ना है IO। मुझे पता है कि कुछ लोग IOभारी अनुप्रयोगों के लिए इनका उपयोग करना पसंद करते हैं, जहां सब कुछ संभावित रूप से विफल हो सकता है, लेकिन इतनी बार कि वे इसके बारे में सोचना पसंद नहीं करते हैं। चाहे आप इन अशुद्ध अपवादों का उपयोग करें या बस ExceptT Error IOवास्तव में स्वाद की बात है। व्यक्तिगत रूप से मैं ExceptTइसलिए चुनता हूं क्योंकि मुझे असफलता के अवसर की याद दिलाई जाती है।


सारांश के रूप में,

  • Maybe - मैं एक स्पष्ट तरीके से विफल हो सकता हूं
  • Either CustomType - मैं असफल हो सकता हूं, और मैं आपको बताऊंगा कि क्या हुआ
  • IO+ अपवाद - मैं कभी-कभी असफल हो जाता हूं। यह देखने के लिए कि मैं क्या करता हूं, यह देखने के लिए मेरे डॉक्स जांचें
  • error - मुझे आपसे बहुत ज्यादा नफरत है

यह जवाब मेरे लिए बहुत कुछ साफ करता है। मैं इस तथ्य के आधार पर खुद का दूसरा अनुमान लगा रहा था कि बिल्ट-इन फ़ंक्शंस जैसे कि उपयोग करने के लिए headया lastप्रतीत होते हैं error, इसलिए मैं सोच रहा था कि क्या वास्तव में चीजें करने का एक अच्छा तरीका था और मैं बस कुछ याद कर रहा था। यह उस सवाल का जवाब देता है। :)
CmdrMoozy

5
@CmdrMoozy Glad मदद करने के लिए :) यह वास्तव में दुर्भाग्यपूर्ण है कि प्रस्तावना में ऐसे बुरे व्यवहार हैं। यह विरासत का तरीका है: /
डैनियल ग्रैजर

3
+1 आपका सारांश अद्भुत है
recursion.ninja

2

मैं 2 और 3 को अलग नहीं कर सकता कि कितने तरीकों से कुछ विफल हो सकता है। जैसे ही आपको लगता है कि केवल एक ही संभव तरीका है, दूसरा अपना चेहरा दिखाएगा। इसके बजाय मीट्रिक को "क्या मेरे कॉलर को परवाह है कि कुछ असफल क्यों हुआ ? क्या वे वास्तव में इसके बारे में कुछ भी कर सकते हैं?"।

इसके अलावा, यह मेरे लिए तुरंत स्पष्ट नहीं है कि Either String SomeTypeत्रुटि की स्थिति उत्पन्न हो सकती है। मैं और अधिक वर्णनात्मक नाम के साथ शर्तों के साथ एक सरल बीजीय डेटा प्रकार बनाऊंगा।

जो आप उपयोग करते हैं वह आपके द्वारा सामना की जा रही समस्या की प्रकृति और आपके द्वारा काम कर रहे सॉफ़्टवेयर पैकेज के मुहावरों पर निर्भर करता है। हालांकि मैं # 1 से बचना चाहूंगा।


वास्तव में, Eitherत्रुटियों के लिए उपयोग हास्केल में एक बहुत प्रसिद्ध पैटर्न है।
Rufflewind

1
@rufflewind - Eitherअस्पष्ट हिस्सा नहीं है, Stringवास्तविक स्ट्रिंग के बजाय त्रुटि के रूप में उपयोग ।
तेलस्टिन

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