कार्यात्मक शैली अपवाद हैंडलिंग


24

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

def fn(*args):
    try:
        ... do something
    except SomeException:
        return None

क्या इससे पवित्रता का उल्लंघन होता है? और यदि ऐसा है, तो क्या इसका मतलब है, कि पाइथन में त्रुटियों को शुद्ध रूप से संभालना असंभव है?

अद्यतन करें

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

class Empty:
    def __repr__(self):
        return "Empty"


class Optional:
    def __init__(self, value=Empty):
        self._value = value

    @property
    def value(self):
        return Empty if self.isempty else self._value

    @property
    def isempty(self):
        return isinstance(self._value, BaseException) or self._value is Empty

    def __bool__(self):
        raise TypeError("Optional has no boolean value")


def optional(*exception_types):
    def build_wrapper(func):
        def wrapper(*args, **kwargs):
            try:
                return Optional(func(*args, **kwargs))
            except exception_types as e:
                return Optional(e)
        wrapper.__isoptional__ = True
        return wrapper
    return build_wrapper


class Carry:
    """
    >>> from functools import partial
    >>> @optional(ArithmeticError)
    ... def rdiv(a, b):
    ...     return b // a
    >>> (Carry() >> (rdiv, 0) >> (rdiv, 0) >> partial(rdiv, 1))(1)
    1
    >>> (Carry() >> (rdiv, 0) >> (rdiv, 1))(1)
    1
    >>> (Carry() >> rdiv >> rdiv)(0, 1) is Empty
    True
    """
    def __init__(self, steps=None):
        self._steps = tuple(steps) if steps is not None else ()

    def _add_step(self, step):
        fn, *step_args = step if isinstance(step, Sequence) else (step, )
        return type(self)(steps=self._steps + ((fn, step_args), ))

    def __rshift__(self, step) -> "Carry":
        return self._add_step(step)

    def _evaluate(self, *args) -> Optional:
        def caller(carried: Optional, step):
            fn, step_args = step
            return fn(*(*step_args, *args)) if carried.isempty else carried
        return reduce(caller, self._steps, Optional())

    def __call__(self, *args):
        return self._evaluate(*args).value

1
आपके प्रश्न का उत्तर पहले ही दिया जा चुका है, इसलिए सिर्फ एक टिप्पणी: क्या आपको समझ में आया है कि आपके फंक्शन को अपवाद के रूप में रखना कार्यात्मक प्रोग्रामिंग में क्यों है? यह एक मनमाना नहीं है :)
एंड्रेस एफ।

6
त्रुटि का संकेत देने वाले मान को वापस करने का एक और विकल्प है। याद रखें, अपवाद हैंडलिंग नियंत्रण प्रवाह है और नियंत्रण प्रवाह को संशोधित करने के लिए हमारे पास कार्यात्मक तंत्र हैं। आप दो कार्य करने के लिए अपना तरीका लिखकर कार्यात्मक भाषाओं में अपवाद से निपटने का अनुकरण कर सकते हैं: सफलता निरंतरता और त्रुटि निरंतरता । आपके द्वारा किया गया अंतिम कार्य सफलता की निरंतरता कहलाता है, "परिणाम", या "निरंतरता" को पारित करते हुए त्रुटि निरंतरता। नीचे की ओर यह है कि आपको अपने कार्यक्रम को इस अंदर से बाहर के फैशन में लिखना है।
एरिक लिपर्ट

3
नहीं, इस मामले में राज्य क्या होगा? कई समस्याएं हैं, लेकिन यहां कुछ हैं: 1- एक संभावित प्रवाह है जो टाइप में एन्कोड नहीं किया गया है, अर्थात आप यह नहीं जान सकते हैं कि क्या कोई फ़ंक्शन केवल इसके प्रकार को देखकर एक अपवाद फेंक देगा (जब तक कि आपने केवल जाँच नहीं की है अपवाद, निश्चित रूप से, लेकिन मैं किसी भी भाषा को नहीं जानता जो केवल उनके पास है)। आप प्रभावी ढंग से "बाहर" प्रकार की प्रणाली पर काम कर रहे हैं, 2- कार्यात्मक प्रोग्रामर जब भी संभव हो तो "कुल" फ़ंक्शन लिखने का प्रयास करते हैं, अर्थात प्रत्येक इनपुट के लिए एक मान लौटाते हैं (गैर-समाप्ति को छोड़कर)। अपवाद इसके खिलाफ काम करते हैं।
एंड्रेस एफ।

3
3- जब आप कुल कार्यों के साथ काम करते हैं, तो आप उन्हें अन्य कार्यों के साथ रचना कर सकते हैं और त्रुटि परिणामों के बारे में चिंता किए बिना "उच्च प्रकार में एन्कोडेड" अर्थात अपवादों के बिना उच्चतर कार्यों में उनका उपयोग कर सकते हैं।
एंड्रेस एफ।

1
@EliKorvigo एक चर की स्थापना राज्य का परिचय देता है, परिभाषा के अनुसार, पूर्ण विराम। चर का संपूर्ण उद्देश्य यह है कि वे राज्य धारण करते हैं। इसका अपवादों से कोई लेना-देना नहीं है। फ़ंक्शन के रिटर्न मान का अवलोकन करना और अवलोकन के आधार पर वैरिएबल का मान सेट करना मूल्यांकन में राज्य का परिचय देता है, है ना?
23:25 पर user253751

जवाबों:


20

सबसे पहले, आइए कुछ भ्रांतियों को दूर करें। कोई "निचला मूल्य" नहीं है। नीचे के प्रकार को एक प्रकार के रूप में परिभाषित किया जाता है जो भाषा में हर दूसरे प्रकार का एक उपप्रकार है। इससे, कोई भी साबित कर सकता है (किसी भी दिलचस्प प्रकार की प्रणाली में कम से कम), कि नीचे के प्रकार का कोई मूल्य नहीं है - यह खाली है । इसलिए नीचे मूल्य जैसी कोई चीज नहीं है।

निचला प्रकार क्यों उपयोगी है? खैर, यह जानते हुए कि यह खाली है आइए हम कार्यक्रम के व्यवहार पर कुछ कटौती करें। उदाहरण के लिए, यदि हमारे पास फ़ंक्शन है:

def do_thing(a: int) -> Bottom: ...

हम जानते हैं कि do_thingकभी वापस नहीं कर सकते हैं, क्योंकि यह प्रकार का मान प्रदान करने के लिए होगा Bottom। इस प्रकार, केवल दो संभावनाएँ हैं:

  1. do_thing रुकता नहीं है
  2. do_thing एक अपवाद फेंकता है (अपवाद तंत्र वाली भाषाओं में)

ध्यान दें कि मैंने एक प्रकार बनाया है Bottomजो वास्तव में पायथन भाषा में मौजूद नहीं है। Noneएक मिथ्या नाम है; यह वास्तव में इकाई मूल्य है , इकाई प्रकार का एकमात्र मूल्य , जिसे NoneTypeपायथन में कहा जाता है (अपने type(None)लिए पुष्टि करने के लिए)।

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

def safe_div(num: int, den: int) -> Option[int]:
  return Some(num/den) if den != 0 else None

दुर्भाग्य से, चूंकि पायथन वास्तव में योग के प्रकार नहीं है, यह एक व्यवहार्य दृष्टिकोण नहीं है। आप विफलता का संकेत देने के लिए एक गरीब-आदमी के विकल्प प्रकार के रूप में लौट सकते हैं None, लेकिन यह वास्तव में लौटने से बेहतर नहीं है Null। कोई प्रकार-सुरक्षा नहीं है।

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


"नीचे मूल्य" से मेरा वास्तव में मतलब था "निचला प्रकार", यही कारण है कि मैंने लिखा कि Noneपरिभाषा का अनुपालन नहीं किया। वैसे भी, मुझे सही करने के लिए धन्यवाद। क्या आपको नहीं लगता कि केवल अपवाद को पूरी तरह से बंद करने या वैकल्पिक मूल्य वापस करने के लिए केवल पायथन के सिद्धांतों का उपयोग करना ठीक है? मेरा मतलब है, जटिल नियंत्रण के लिए अपवाद का उपयोग करने से रोकना क्यों बुरा है?
एली कोरविगो

@EliKorvigo यह वही है जो कमोबेश मैंने कहा है, ठीक है? अपवाद मुहावरेदार पायथन हैं।
गार्डेनहेड

1
उदाहरण के लिए, मैं अपने अंडरग्रेजुएट छात्रों को try/except/finallyदूसरे विकल्प की तरह उपयोग करने के लिए हतोत्साहित करता हूं if/else, अर्थात try: var = expession1; except ...: var = expression 2; except ...: var = expression 3..., हालांकि किसी भी अनिवार्य भाषा में करना एक सामान्य बात है (btw, मैं दृढ़ता से if/elseइस के लिए ब्लॉक का उपयोग करके भी हतोत्साहित करता हूं )। क्या आपका मतलब है, कि मैं अनुचित हूं और "यह अजगर है" के बाद से इस तरह के पैटर्न की अनुमति देनी चाहिए?
एली कोरविगो 15

@EliKorvigo मैं आपसे सामान्य रूप से सहमत हूँ (btw, आप एक प्रोफेसर हैं?)। नियंत्रण प्रवाह के लिए इस्तेमाल नहीं किया try... catch...जाना चाहिए । किसी कारण के लिए, यह है कि अजगर समुदाय ने हालांकि चीजों को करने का फैसला किया। उदाहरण के लिए, मैंने जो फ़ंक्शन ऊपर लिखा है वह आमतौर पर लिखा जाएगा । इसलिए यदि आप उन्हें सामान्य सॉफ़्टवेयर इंजीनियरिंग सिद्धांत सिखा रहे हैं, तो आपको निश्चित रूप से इसे हतोत्साहित करना चाहिए। एक कोड गंध भी है, लेकिन यहाँ जाने के लिए बहुत लंबा है। safe_divtry: result = num / div: except ArithmeticError: result = Noneif ... else...
गार्डेनहेड

2
एक "निचला मूल्य" है (इसका उपयोग हास्केल के शब्दार्थ के बारे में बात करने में किया जाता है, उदाहरण के लिए), और इसका नीचे के प्रकार के साथ बहुत कम संबंध है। तो यह वास्तव में ओपी की गलत धारणा नहीं है, सिर्फ एक अलग चीज के बारे में बात कर रहा है।
बेन

11

चूंकि पिछले कुछ दिनों में शुद्धता में इतनी रुचि है, इसलिए हम यह जांच नहीं करते हैं कि शुद्ध फ़ंक्शन कैसा दिखता है।

एक शुद्ध कार्य:

  • संदर्भित रूप से पारदर्शी है; अर्थात्, दिए गए इनपुट के लिए, यह हमेशा एक ही आउटपुट का उत्पादन करेगा।

  • दुष्प्रभाव उत्पन्न नहीं करता है; यह अपने बाहरी वातावरण में इनपुट, आउटपुट, या कुछ और को नहीं बदलता है। यह केवल एक वापसी मूल्य पैदा करता है।

इसलिए खुद से पूछिए। क्या आपका कार्य कुछ भी करता है लेकिन एक इनपुट स्वीकार करता है और एक आउटपुट वापस करता है?


3
इसलिए, इससे कोई फर्क नहीं पड़ता है कि जब तक यह कार्यात्मक रूप से व्यवहार नहीं करता है तब तक यह कितना बदसूरत है?
एली कोरविगो

8
सही है, अगर आप केवल शुद्धता में रुचि रखते हैं। बेशक, अन्य बातों पर विचार करना चाहिए।
रॉबर्ट हार्वे

3
शैतानों के वकील की भूमिका निभाने के लिए, मेरा तर्क है कि एक अपवाद को फेंकना उत्पादन का एक रूप है और फेंकने वाले कार्य शुद्ध होते हैं। क्या यही समस्या है?
बरगी

1
@Bergi मुझे नहीं पता कि आप शैतान के वकील की भूमिका निभा रहे हैं, क्योंकि यह वही है जो इसका जवाब देता है :) समस्या यह है कि शुद्धता के अलावा अन्य विचार भी हैं। यदि आप अनियंत्रित अपवादों की अनुमति देते हैं (जो परिभाषा द्वारा फ़ंक्शन के हस्ताक्षर का हिस्सा नहीं हैं) तो प्रभावी रूप से प्रत्येक फ़ंक्शन का रिटर्न प्रकार T + { Exception }(जहां Tस्पष्ट रूप से घोषित रिटर्न प्रकार है), जो समस्याग्रस्त है। आप यह नहीं जान सकते हैं कि क्या कोई फ़ंक्शन इसके स्रोत कोड को देखे बिना एक अपवाद को फेंक देगा, जो लेखन के साथ-साथ उच्च क्रम वाले कार्यों को भी समस्याग्रस्त बनाता है।
एंड्रेस एफ।

2
@Begri फेंकते समय यकीनन शुद्ध हो सकता है, अपवादों का उपयोग करते हुए IMO प्रत्येक फ़ंक्शन के रिटर्न प्रकार को और अधिक जटिल करता है। यह कार्यों की रचनाशीलता को नुकसान पहुंचाता है। क्रियान्वयन पर विचार करें कि त्रुटि map : (A->B)->List A ->List Bकहां A->Bहो सकती है। यदि हम f को अपवाद फेंकने की अनुमति देते map f L हैं तो कुछ प्रकार के वापस आ जाएंगे Exception + List<B>। यदि इसके बजाय हम इसे एक optionalशैली प्रकार वापस करने की अनुमति देते हैं, तो map f Lइसके बजाय सूची <वैकल्पिक <b> `लौटाएंगे। यह दूसरा विकल्प मेरे लिए अधिक कार्यात्मक लगता है।
माइकल एंडरसन

7

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

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

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

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

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

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

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

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

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

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

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

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

एक समारोह है कि या तो रिटर्न None(यदि कोई त्रुटि हुआ) या कुछ मूल्य (अगर कोई त्रुटि थी) पीछा कर रहा है ऊपर रणनीतियों में से।

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


1
+1 बहुत बढ़िया जवाब! और बहुत व्यापक भी।
एंड्रेस एफ।

6

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

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

दूसरी ओर, यदि आप किसी दिए गए तार से पूर्णांक को पार्स करने की कोशिश कर रहे हैं और यदि यह विफल रहता है, तो एक अपवाद फेंकना, यह शुद्ध हो सकता है, जब तक कि कोई अपवाद आपके फ़ंक्शन से बाहर नहीं निकल सकता।

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


आप नीचे का प्रकार नहीं लौटा सकते।
गार्डेनहेड

1
@gardenhead तुम सही हो, मैं इकाई प्रकार के बारे में सोच रहा था। फिक्स्ड।
8bittree

आपके पहले उदाहरण के मामले में, फाइलसिस्टम नहीं है और इसके भीतर कौन सी फाइलें मौजूद हैं, जो कि फंक्शन के इनपुट में से एक है?
वैलिटी

2
@Vaility वास्तव में आपके पास संभवतः फ़ाइल के लिए एक हैंडल या पथ है। यदि फ़ंक्शन fशुद्ध है, तो आप f("/path/to/file")हमेशा उसी मान को वापस करने की अपेक्षा करेंगे। यदि वास्तविक फ़ाइल दो इनवोकेशन के बीच डिलीट या बदल जाती है तो क्या होता है f?
एंड्रेस एफ।

2
@Vaility फ़ंक्शन शुद्ध हो सकता है यदि फ़ाइल के हैंडल के बजाय आपने इसे फ़ाइल की वास्तविक सामग्री (यानी बाइट्स का सटीक स्नैपशॉट) पास किया है, तो इस स्थिति में आप गारंटी दे सकते हैं कि यदि वही सामग्री अंदर जाती है, तो वही आउटपुट बाहर चला जाता है। लेकिन एक फ़ाइल तक पहुँचना ऐसा नहीं है :)
एंड्रेस एफ।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.