कार्यात्मक प्रोग्रामिंग में, स्थानीय उत्परिवर्तनीय चर हैं जिनके कोई दुष्प्रभाव नहीं हैं जिन्हें अभी भी "बुरा अभ्यास" माना जाता है?


23

क्या किसी फ़ंक्शन में परिवर्तनशील स्थानीय चर हैं जो केवल आंतरिक रूप से उपयोग किए जाते हैं, (उदाहरण के लिए फ़ंक्शन का कोई दुष्प्रभाव नहीं है, कम से कम जानबूझकर नहीं) अभी भी "गैर कार्यात्मक" माना जाता है?

जैसे "फंक्शनल प्रोग्रामिंग विद स्काला" कोर्स शैली की जाँच किसी भी varउपयोग को बुरा मानती है

मेरा प्रश्न, यदि फ़ंक्शन का कोई दुष्प्रभाव नहीं है, तो क्या अनिवार्य शैली कोड लिखना अभी भी हतोत्साहित है?

उदाहरण के लिए, संचायक पैटर्न के साथ पूंछ पुनर्संरचना का उपयोग करने के बजाय, लूप के लिए एक स्थानीय करने और एक स्थानीय परिवर्तनशील बनाने ListBufferऔर इसे जोड़ने के साथ क्या गलत है, जब तक कि इनपुट नहीं बदला जाता है?

यदि उत्तर "हां, वे हमेशा हतोत्साहित होते हैं, भले ही कोई साइड इफेक्ट न हो" तो इसका कारण क्या है?


3
विषय के बारे में सभी सलाह, उपदेश आदि जो मैंने कभी सुने हैं वह साझा उत्परिवर्तनीय स्थिति को जटिलता का स्रोत कहते हैं। क्या वह कोर्स केवल शुरुआती लोगों द्वारा खाया जाना है? तो फिर यह शायद एक अच्छी तरह से जानबूझकर ओवरसिम्प्लीफिकेशन है।
किलन फ़ॉथ

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

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

जवाबों:


17

यहां एक चीज जो असमान रूप से बुरी प्रथा है, वह दावा कर रही है कि कुछ शुद्ध कार्य है जब ऐसा नहीं होता है।

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

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


16

समस्या प्रति se mutability नहीं है, यह संदर्भात्मक पारदर्शिता की कमी है।

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

एक ऐसा उदाहरण है जिसके बारे में मैं सोच सकता हूं कि उत्परिवर्तन का उपयोग कुछ ऐसा करने के लिए किया जाना चाहिए जो बहुत कार्यात्मक हो: संस्मरण। मेमोएशन एक फ़ंक्शन से मूल्यों को कैशिंग कर रहा है, इसलिए उन्हें पुन: प्रतिष्ठित होने की आवश्यकता नहीं है; यह संदर्भित रूप से पारदर्शी है, लेकिन यह उत्परिवर्तन का उपयोग करता है।

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


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

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

@ मिचेल शॉ: +1 के लिए "समस्या प्रति परिवर्तनशीलता नहीं है, यह संदर्भित पारदर्शिता की कमी है।" हो सकता है कि आप उस क्लीन लैंग्वेज का हवाला दे सकते हैं जिसमें आपकी विशिष्टता है: ये आपस में परिवर्तनशीलता की अनुमति देते हैं लेकिन फिर भी प्रासंगिक पारदर्शिता की गारंटी देते हैं।
जियोर्जियो

@ जियोर्जियो: मैं वास्तव में क्लीन के बारे में कुछ नहीं जानता, हालांकि मैंने समय-समय पर इसका उल्लेख किया है। शायद मुझे इस पर गौर करना चाहिए।
माइकल शॉ

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

8

यह "अच्छा अभ्यास" बनाम "बुरा अभ्यास" के लिए उबालना वास्तव में अच्छा नहीं है। स्काला, परिवर्तनशील मूल्यों का समर्थन करता है क्योंकि वे कुछ समस्याओं को अपरिवर्तनीय मूल्यों से बेहतर तरीके से हल करते हैं, अर्थात् वे जो प्रकृति में पुनरावृत्त होते हैं।

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

इसका मतलब यह नहीं है कि जब आप एक समस्या है जो परस्पर परिवर्तन के लिए बेहतर है, तो आपको आंतरिक रूप से उत्परिवर्तित संरचनाओं और मूल्यों से बचने की आवश्यकता है।

इस बात को ध्यान में रखते हुए कि बहुत सी समस्याओं के लिए आमतौर पर म्यूटेबल वैरिएबल (जैसे कि लूपिंग) की आवश्यकता होती है, जो कि उच्चतर ऑर्डर फंक्शंस जैसे स्कैला (मैप / फिल्टर / फोल्ड) प्रदान करता है, के साथ बेहतर तरीके से हल किया जा सकता है। उन लोगों के बारे में पता होना।


2
हां, स्कैला के संग्रह का उपयोग करते समय मुझे लगभग कभी भी लूप की आवश्यकता नहीं होती है। map, filter, foldLeftऔर forEach समय के सबसे अधिक चाल करते हैं, लेकिन जब वे ऐसा नहीं, महसूस करने के लिए मैं जानवर बल जरूरी कोड पर वापस लौट रहा करने के लिए "ठीक" कर रहा हूँ में सक्षम होने के लिए अच्छा है। (जब तक कोर्स का कोई साइड इफेक्ट न हो)
एरन मेडन

3

थ्रेड सुरक्षा के साथ संभावित मुद्दों के अलावा, आप आमतौर पर कई प्रकार की सुरक्षा भी खो देते हैं। इंपीरियल लूप्स का रिटर्न प्रकार होता हैUnit और इनपुट के लिए बहुत अधिक अभिव्यक्ति ले सकता है। उच्च-क्रम के कार्यों और यहां तक ​​कि पुनरावृत्ति में बहुत अधिक सटीक शब्दार्थ और प्रकार हैं।

आपके पास कार्यात्मक छोरों की तुलना में कार्यात्मक कंटेनर प्रसंस्करण के लिए कई और विकल्प हैं। अनिवार्य के साथ, आप मूल रूप से है for, while, और उन दो तरह पर मामूली बदलाव do...whileऔरforeach

कार्यात्मक में, आपके पास कुल, गिनती, फ़िल्टर, फ़ाइनल, फ्लैटपाइप, फोल्ड, GroupBy, lastIndexWhere, मैप, maxBy, minBy, विभाजन, स्कैन, sortBy, सॉर्टविथ, स्पैन, और टेकहाइल है, बस स्काला के कुछ और आम लोगों के नाम हैं। मानक पुस्तकालय। जब आप उन उपलब्ध होने के आदी हो जाते हैं, तो जरूरी हैfor लूप तुलना में बहुत बुनियादी लगते हैं।

स्थानीय परिवर्तनशीलता का उपयोग करने का एकमात्र वास्तविक कारण प्रदर्शन के लिए कभी-कभी होता है।


2

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

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

जैसा कि लिंक कहता है:

अगर कोई पेड़ जंगल में गिरता है, तो क्या इससे आवाज आती है? यदि कोई शुद्ध फ़ंक्शन अपरिवर्तनीय रिटर्न वैल्यू बनाने के लिए कुछ स्थानीय डेटा को म्यूट करता है, तो क्या यह ठीक है?


2

कोई स्थानीय परिवर्तनशील चर होने का एक फायदा नहीं है - यह फ़ंक्शन को थ्रेड्स के प्रति अधिक अनुकूल बनाता है।

मैं इस तरह के एक स्थानीय चर (मेरे कोड में नहीं, और न ही मेरे पास स्रोत था) द्वारा जला दिया गया, जिससे कम-संभावना डेटा भ्रष्टाचार हो सकता है। थ्रेड सेफ्टी का एक तरह से या किसी अन्य तरीके से उल्लेख नहीं किया गया था, कोई भी ऐसा राज्य नहीं था जो कॉल के पार बना रहे और कोई साइड इफेक्ट न हो। यह मेरे लिए नहीं था कि यह थ्रेड सेफ नहीं हो सकता, 100,000 यादृच्छिक डेटा भ्रष्टाचार में 1 का पीछा करना एक शाही दर्द है।

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