"कार्यात्मक शैली" माना जाने वाले साइड-इफेक्ट्स के साथ क्लोजर हैं?


9

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

  1. एक मूल्य के रूप में माना जा सकता है, और इसलिए एक चर में संग्रहीत किया जाता है, कोड के विभिन्न हिस्सों के चारों ओर पारित किया जाता है, एक कार्यक्रम के एक हिस्से में परिभाषित किया जाता है और एक ही कार्यक्रम के बिल्कुल अलग हिस्से में आह्वान किया जाता है।
  2. चर को उस संदर्भ से कैप्चर कर सकते हैं जिसमें इसे परिभाषित किया गया है, और जब बाद में इसे लागू किया जाता है (संभवत: एक पूरी तरह से अलग संदर्भ में) उन्हें एक्सेस करें।

यहाँ स्काला में लिखित क्लोजर का एक उदाहरण दिया गया है:

def filterList(xs: List[Int], lowerBound: Int): List[Int] =
  xs.filter(x => x >= lowerBound)

फ़ंक्शन शाब्दिक x => x >= lowerBoundमें मुक्त चर होता है lowerBound, जो फ़ंक्शन के तर्क से बंद (बाध्य) होता filterListहै जिसमें समान नाम होता है। लाइब्रेरी पद्धति को बंद कर दिया जाता है filter, जो इसे सामान्य कार्य के रूप में बार-बार लागू कर सकता है।

मैं इस साइट पर बहुत सारे सवाल और जवाब पढ़ रहा हूं और जहां तक ​​मैं समझता हूं, शब्द बंद करना अक्सर कार्यात्मक प्रोग्रामिंग और कार्यात्मक प्रोग्रामिंग शैली के साथ स्वचालित रूप से जुड़ा हुआ है।

विकिपीडिया पर फ़ंक्शन प्रोग्रामिंग की परिभाषा पढ़ता है:

कंप्यूटर विज्ञान में, कार्यात्मक प्रोग्रामिंग एक प्रोग्रामिंग प्रतिमान है जो गणना को गणितीय कार्यों के मूल्यांकन के रूप में मानता है और राज्य और पारस्परिक डेटा से बचा जाता है। यह अनिवार्य प्रोग्रामिंग शैली के विपरीत कार्यों के आवेदन पर जोर देता है, जो राज्य में परिवर्तनों पर जोर देता है।

और आगे

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

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

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

क्या कार्यात्मक शैली माने जाने वाले साइड इफेक्ट्स के साथ क्लोजर का उपयोग किया जाता है या क्लोजर को एक अधिक सामान्य निर्माण माना जाता है जिसे कार्यात्मक और गैर-कार्यात्मक प्रोग्रामिंग शैली दोनों के लिए इस्तेमाल किया जा सकता है? क्या इस विषय पर कोई साहित्य है?

महत्वपूर्ण लेख

मैं साइड-इफेक्ट्स की उपयोगिता या साइड इफेक्ट्स के बंद होने पर सवाल नहीं उठा रहा हूं। इसके अलावा, मैं साइड इफेक्ट्स के साथ या इसके बिना बंद होने के फायदे / नुकसान के बारे में चर्चा में दिलचस्पी नहीं रखता।

मुझे केवल यह जानने में दिलचस्पी है कि क्या ऐसे क्लोजर का उपयोग करना अभी भी कार्यात्मक प्रोग्रामिंग के प्रस्तावक द्वारा कार्यात्मक शैली माना जाता है या यदि इसके विपरीत, कार्यात्मक शैली का उपयोग करते समय उनका उपयोग हतोत्साहित किया जाता है।


3
विशुद्ध रूप से कार्यात्मक शैली / भाषा में, साइड इफेक्ट्स असंभव हैं ... इसलिए मुझे लगता है कि यह एक बात होगी: किस स्तर पर शुद्धता को कोई व्यक्ति कार्यात्मक मानता है?
स्टीवन एवर्स

@SnOrfus: 100% पर?
जियोर्जियो

1
विशुद्ध रूप से कार्यात्मक भाषा में दुष्प्रभाव असंभव हैं, जिससे आपको अपने प्रश्न का उत्तर देना चाहिए।
स्टीवन एवर्स

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

क्या डाउनवॉटर इस प्रश्न को सुधारने के लिए एक नोट छोड़ सकता है?
जियोर्जियो

जवाबों:


7

नहीं; कार्यात्मक प्रतिमान की परिभाषा राज्य की कमी और स्पष्ट रूप से दुष्प्रभावों की कमी के बारे में है। यह उच्च-क्रम के कार्यों, क्लोजर, भाषा समर्थित सूची हेरफेर या अन्य भाषा सुविधाओं के बारे में नहीं है ...

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

यह, निश्चित रूप से, एक बहुत ही सरल दृष्टिकोण है।


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

@ दोस्त मैं शायद बहुत स्पष्ट रूप से व्यक्त नहीं किया था; जब मैंने कहा कि फ़ंक्शन म्यूट हो गए हैं तो मैंने डेटा म्यूटेबिलिटी का उल्लेख नहीं किया है लेकिन इस तथ्य के लिए कि किसी फ़ंक्शन का व्यवहार (उच्च-क्रम फ़ंक्शन द्वारा) बदला जा सकता है।
m3th0dman

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

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

@Giorgio: क्लासिक एफपी भाषाओं के सबसे कर अस्थिरता है, हास्केल केवल एक ही है जो मैं अपने सिर के ऊपर से सोच सकता हूं जो कि उत्परिवर्तन की अनुमति नहीं देता है। फिर भी, एफपी में राज्य को टालना एक महत्वपूर्ण मूल्य है।
tdammers

9

नंबर "कार्यात्मक-शैली" का अर्थ है साइड-इफ़ेक्ट-फ्री प्रोग्रामिंग।

यह देखने के लिए कि, विस्तार विधि के बारे में एरिक लिपर्ट के ब्लॉग प्रविष्टि पर एक नज़र ForEach<T>क्यों है, और क्यों Microsoft ने इसे Linq में एक अनुक्रम विधि शामिल नहीं किया है :

मैं दो तरीकों से, इस तरह की विधि प्रदान करने के लिए दार्शनिक रूप से विरोध कर रहा हूं।

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

दूसरा कारण यह है कि ऐसा करने से भाषा में शून्य नई प्रतिनिधित्वात्मक शक्ति जुड़ जाती है। ऐसा करने से आप इस पूरी तरह से स्पष्ट कोड को फिर से लिख सकते हैं:

foreach(Foo foo in foos){ statement involving foo; }

इस कोड में:

foos.ForEach((Foo foo)=>{ statement involving foo; });

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


1
हालाँकि, मैं उससे सहमत हूँ ... विचार करने पर उसका तर्क थोड़ा कमजोर हो जाता है ParallelQuery<T>.ForAll(...)IEnumerable<T>.ForEach(...)डिबगिंग ForAllस्टेटमेंट्स के लिए इस तरह का कार्यान्वयन बेहद उपयोगी है (इसके ForAllसाथ बदलें ForEachऔर हटा दें AsParallel()और आप बहुत आसानी से इसे डीबग / स्टेप कर सकते हैं)
स्टीवन एवर्स

स्पष्ट रूप से जो डफी के अलग विचार हैं। : D
रॉबर्ट हार्वे

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

5
@ जियोर्जियो: क्लोजर को अभी भी क्लोजर माना जाने वाला शुद्ध होना जरूरी नहीं है। हालांकि, उन्हें "कार्यात्मक शैली" माना जाना शुद्ध होना चाहिए।
रॉबर्ट हार्वे

3
@ जिओर्जियो: यह वास्तव में उपयोगी है कि यह परस्पर स्थिति और दुष्प्रभावों के आसपास बंद करने में सक्षम हो और इसे किसी अन्य समारोह में पारित कर सके। यह कार्यात्मक प्रोग्रामिंग के लक्ष्यों के विपरीत है। मुझे लगता है कि मेमने के लिए कार्यात्मक भाषा में सामान्य भाषा के समर्थन से बहुत भ्रम पैदा होता है।
ग्लेनपेटर्सन

0

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

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

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

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

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