क्या कार्यात्मक प्रोग्रामिंग भाषाएँ दुष्प्रभाव को कम करती हैं?


10

विकिपीडिया के अनुसार, फंक्शनल प्रोग्रामिंग लैंग्वेजेस , जो कि डिक्लेरेटिव हैं, वे साइड इफेक्ट्स को कम करती हैं। सामान्य रूप से घोषणात्मक प्रोग्रामिंग , साइड इफेक्ट्स को कम करने या समाप्त करने का प्रयास करता है।

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

लेकिन, इसके अलावा, एक साइड इफेक्ट की एक और परिभाषा है। खराब असर

अपने कॉलिंग फ़ंक्शंस या बाहरी दुनिया के साथ एक माननीय बातचीत का एक मान लौटाने के अलावा है। उदाहरण के लिए, एक विशेष फ़ंक्शन वैश्विक चर या स्थिर चर को संशोधित कर सकता है, इसके किसी एक तर्क को संशोधित कर सकता है, एक अपवाद को बढ़ा सकता है, किसी प्रदर्शन या फ़ाइल को डेटा लिख ​​सकता है, डेटा पढ़ सकता है या अन्य साइड-इफ़ेक्टिंग कार्यों को कॉल कर सकता है।

इस अर्थ में, कार्यात्मक प्रोग्रामिंग भाषाएं वास्तव में दुष्प्रभाव की अनुमति देती हैं, क्योंकि उनके बाहरी दुनिया को प्रभावित करने वाले कार्यों के अनगिनत उदाहरण हैं, अन्य कार्यों को कॉल करना, अपवादों को उठाना, फाइलों में लिखना आदि।

तो, आखिरकार, कार्यात्मक प्रोग्रामिंग भाषाएं साइड इफेक्ट की अनुमति देती हैं या नहीं?

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

जवाबों:


26

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

फ़ंक्शन के साइड इफेक्ट्स होने चाहिए, यह काफी पकड़ नहीं है। रिटर्न वैल्यू फंक्शन कॉल के बराबर नहीं है, क्योंकि रिटर्न वैल्यू में साइड इफेक्ट्स नहीं होते हैं।

इसका समाधान साइड इफेक्ट्स का उपयोग बंद करना है और इन प्रभावों को रिटर्न वैल्यू में एन्कोडिंग करना है । विभिन्न भाषाओं में अलग-अलग प्रभाव प्रणालियाँ होती हैं। ईजी हास्केल कुछ प्रभाव जैसे कि आईओ या स्टेट म्यूटेशन को एनकोड करने के लिए मोनाड्स का उपयोग करता है। C / C ++ / Rust भाषाओं में एक प्रकार की प्रणाली होती है जो कुछ मूल्यों के उत्परिवर्तन को रोक सकती है।

अनिवार्य भाषा में, एक print("foo")फ़ंक्शन कुछ प्रिंट करेगा और कुछ भी नहीं लौटाएगा। हास्केल जैसी शुद्ध कार्यात्मक भाषा में, एक printफ़ंक्शन बाहरी दुनिया की स्थिति का प्रतिनिधित्व करने वाली एक वस्तु भी लेता है, और इस आउटपुट का प्रदर्शन करने के बाद एक नई वस्तु को राज्य का प्रतिनिधित्व करता है। के समान कुछ newState = print "foo" oldState। मैं पुराने राज्य से जितने चाहे नए राज्य बना सकता हूं। हालांकि, मुख्य फ़ंक्शन द्वारा केवल एक का उपयोग किया जाएगा। इसलिए मुझे कार्यों को पूरा करके राज्यों को कई कार्यों से अनुक्रम करने की आवश्यकता है। प्रिंट करने के लिए foo bar, मैं कुछ ऐसा कह सकता हूं print "bar" (print "foo" originalState)

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

ध्यान दें कि हास्केल एकमात्र सामान्य रूप से प्रयुक्त कार्यात्मक भाषा है जो इस मार्ग का उपयोग करती है। अन्य कार्यात्मक भाषाएं। लिस्प परिवार, एमएल परिवार और नई कार्यात्मक भाषाएँ जैसे स्काला हतोत्साहित करती हैं लेकिन फिर भी दुष्प्रभाव की अनुमति देती हैं - उन्हें अनिवार्य-कार्यात्मक भाषा कहा जा सकता है।

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

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


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

3
@ कोडबॉट, बिल्कुल नहीं, मेरी राय में। यदि ठीक से लागू किया गया है, तो कार्यात्मक प्रोग्रामिंग में साइड इफेक्ट को फ़ंक्शन के रिटर्न प्रकार में परिलक्षित किया जाना चाहिए। उदाहरण के लिए, यदि कोई फ़ंक्शन विफल हो सकता है (यदि कोई विशेष फ़ाइल मौजूद नहीं है या डेटाबेस कनेक्शन स्थापित नहीं किया जा सकता है), तो फ़ंक्शन के रिटर्न प्रकार को फ़ंक्शन को अपवाद के बजाय विफलता को एन्कैप करना चाहिए। उदाहरण के लिए रेलवे-ओरिएंटेड प्रोग्रामिंग पर एक नज़र डालें ( fsharpforfunandprofit.com/posts/recipe-part2 )।
आरोन एम। एशबैक

"... उन्हें अनिवार्य-कार्यात्मक भाषा कहा जा सकता है।": साइमन पेटन जोन्स ने लिखा है ... "हास्केल दुनिया की सबसे बेहतरीन अनिवार्य प्रोग्रामिंग भाषा है।"
जियोर्जियो

5

कोई भी प्रोग्रामिंग भाषा दुष्प्रभाव को समाप्त नहीं करती है । मुझे लगता है कि यह कहना बेहतर है कि घोषणात्मक भाषाओं में दुष्प्रभाव होते हैं जबकि अनिवार्यता वाली भाषाएं नहीं होती हैं। हालाँकि, मुझे इतना यकीन नहीं है कि साइड इफेक्ट्स के बारे में इस बारे में कोई भी बात दो प्रकार की भाषाओं के बीच मूलभूत अंतर पर मिलती है और यह वास्तव में ऐसा लगता है कि आप क्या चाहते हैं।

मुझे लगता है कि यह एक उदाहरण के साथ अंतर को स्पष्ट करने में मदद करता है।

a = b + c

कोड की उपरोक्त पंक्ति वस्तुतः किसी भी भाषा में लिखी जा सकती है इसलिए हम कैसे निर्धारित कर सकते हैं कि हम एक अनिवार्य या घोषित भाषा का उपयोग कर रहे हैं? भाषा के दो वर्गों में कोड की उस पंक्ति के गुण कैसे भिन्न हैं?

एक अनिवार्य भाषा में (सी, जावा, जावास्क्रिप्ट, और सी।) कोड की वह पंक्ति केवल एक प्रक्रिया में एक कदम का प्रतिनिधित्व करती है। यह हमें किसी भी मूल्य की मौलिक प्रकृति के बारे में कुछ नहीं बताता है। यह हमें बताता है कि कोड की इस पंक्ति के बाद इस समय (लेकिन अगली पंक्ति से पहले,) aके बराबर होगा bप्लस cलेकिन यह हमें के बारे में कुछ नहीं बताता है aबड़ा अर्थ में।

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

मेरे विचार से यह , नहीं दुष्प्रभाव या राज्य, कौन-सी भाषाओं के दो प्रकार के अलग बनाता है। एक अनिवार्य भाषा में, कोड की कोई विशेष रेखा आपको प्रश्न में चर के समग्र अर्थ के बारे में कुछ नहीं बताती है। दूसरे शब्दों में, a = b + cकेवल इसका मतलब है कि समय में एक बहुत ही संक्षिप्त समय aके लिए bऔर के योग के बराबर हुआ c

इस बीच, घोषणात्मक भाषाओं में कोड की हर पंक्ति एक मौलिक सत्य की स्थापना करती है जो कार्यक्रम के पूरे जीवनकाल में मौजूद रहेगी। इन भाषाओं में, a = b + cआपको बताता है कि कोई बात नहीं क्या कोड के किसी भी अन्य लाइन में होता है aहमेशा की राशि के बराबर हो जाएगा bऔर c

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