मैं पढ़ रहा हूं और सुन रहा हूं कि लोग (इस साइट पर भी) नियमित रूप से कार्यात्मक प्रोग्रामिंग प्रतिमान की प्रशंसा करते हैं, इस बात पर जोर देते हैं कि सब कुछ अपरिवर्तनीय होना कितना अच्छा है। विशेष रूप से, लोग इस दृष्टिकोण को पारंपरिक रूप से अनिवार्य OO भाषाओं में भी प्रस्तावित करते हैं, जैसे C #, Java या C ++, न केवल विशुद्ध रूप से कार्यात्मक भाषाओं में, जैसे हास्केल जो प्रोग्रामर पर इसे लागू करता है।
मुझे समझने में मुश्किल होती है, क्योंकि मुझे परिवर्तनशीलता और साइड-इफेक्ट ... सुविधाजनक लगते हैं। हालांकि, यह देखते हुए कि लोग वर्तमान में दुष्प्रभावों की निंदा कैसे करते हैं और जहां कहीं भी संभव हो उनसे छुटकारा पाने के लिए इसे एक अच्छा अभ्यास मानते हैं, मेरा मानना है कि अगर मैं एक सक्षम प्रोग्रामर बनना चाहता हूं तो मुझे प्रतिमान की कुछ बेहतर समझ के लिए अपना न्याय शुरू करना होगा ... इसलिए मेरा क्यू।
एक जगह जब मैं कार्यात्मक प्रतिमान के साथ समस्याओं का पता लगाता हूं, जब एक वस्तु को कई स्थानों से स्वाभाविक रूप से संदर्भित किया जाता है। इसका दो उदाहरणों पर वर्णन करता हूं।
पहला उदाहरण मेरा सी # गेम होगा जिसे मैं अपने खाली समय में बनाने की कोशिश कर रहा हूं । यह टर्न-बेस्ड वेब गेम है, जहां दोनों खिलाड़ियों में 4 राक्षसों की टीमें हैं और अपनी टीम से एक राक्षस को युद्ध के मैदान में भेज सकते हैं, जहां इसका सामना विरोधी खिलाड़ी द्वारा भेजे गए राक्षस से होगा। खिलाड़ी युद्ध के मैदान से राक्षसों को भी याद कर सकते हैं और उन्हें अपनी टीम (इसी तरह से पोकेमोन) से एक और राक्षस के साथ बदल सकते हैं।
इस सेटिंग में, एक एकल राक्षस को कम से कम 2 स्थानों से स्वाभाविक रूप से संदर्भित किया जा सकता है: एक खिलाड़ी की टीम और युद्धक्षेत्र, जो दो "सक्रिय" राक्षसों का संदर्भ देता है।
अब उस स्थिति पर विचार करें जब एक राक्षस मारा जाता है और 20 स्वास्थ्य बिंदु खो देता है। अनिवार्य प्रतिमान के कोष्ठक के भीतर मैं health
इस परिवर्तन को प्रतिबिंबित करने के लिए इस राक्षस के क्षेत्र को संशोधित करता हूं - और यही मैं अभी कर रहा हूं। हालाँकि, यह Monster
वर्ग को परिवर्तनशील और संबंधित कार्यों (विधियों) को अशुद्ध बनाता है , जो मुझे लगता है कि अब तक एक बुरा अभ्यास माना जाता है।
भले ही मैंने खुद को इस खेल के कोड को कम-से-आदर्श राज्य में रखने की अनुमति दी हो, ताकि भविष्य के किसी बिंदु पर वास्तव में इसे खत्म करने की कोई उम्मीद हो, मैं जानना चाहता हूं और समझना चाहता हूं कि यह कैसा होना चाहिए ठीक से लिखा है। इसलिए: यदि यह एक डिजाइन दोष है, तो इसे कैसे ठीक करें?
कार्यात्मक शैली में, जैसा कि मैं इसे समझता हूं, मैं इस Monster
ऑब्जेक्ट की एक प्रति बनाऊंगा, इसे इस एक क्षेत्र को छोड़कर पुराने के समान रखता हूं; और विधि suffer_hit
पुराने स्थान को संशोधित करने के बजाय इस नई वस्तु को लौटा देगी। फिर मैं वैसे Battlefield
ही इस राक्षस को छोड़कर अपने सभी क्षेत्रों को एक समान रखते हुए वस्तु की नकल करूंगा ।
यह कम से कम 2 कठिनाइयों के साथ आता है:
- पदानुक्रम आसानी से सिर्फ
Battlefield
-> के इस सरलीकृत उदाहरण से बहुत गहरा हो सकता हैMonster
। मुझे एक को छोड़कर सभी क्षेत्रों की ऐसी नकल करनी होगी और इस पदानुक्रम में एक नई वस्तु को वापस करना होगा। यह बॉयलरप्लेट कोड होगा, जो मुझे विशेष रूप से कष्टप्रद लगता है क्योंकि बॉयलरप्लेट को कम करने के लिए कार्यात्मक प्रोग्रामिंग माना जाता है। - हालाँकि, एक और गंभीर समस्या यह है कि इससे डेटा सिंक से बाहर हो जाएगा । क्षेत्र के सक्रिय राक्षस अपने स्वास्थ्य को कम होते देखेंगे; हालांकि, यह एक ही राक्षस, अपने नियंत्रित खिलाड़ी से संदर्भित है
Team
, नहीं होगा। अगर मैं इसके बजाय अनिवार्य शैली को अपनाता हूं, तो डेटा का प्रत्येक संशोधन कोड के अन्य सभी स्थानों से तुरंत दिखाई देगा और इस तरह के मामलों में मुझे यह वास्तव में सुविधाजनक लगता है - लेकिन जिस तरह से मुझे चीजें मिल रही हैं वह ठीक वही है जो लोग कहते हैं अनिवार्य शैली के साथ गलत है!- अब
Team
प्रत्येक हमले के बाद यात्रा करके इस मुद्दे पर ध्यान देना संभव होगा । यह अतिरिक्त काम है। हालांकि, क्या होगा अगर एक राक्षस को बाद में और भी अधिक स्थानों से अचानक संदर्भित किया जा सकता है? क्या होगा अगर मैं एक क्षमता के साथ आता हूं, उदाहरण के लिए, एक राक्षस एक और राक्षस पर ध्यान केंद्रित करने देता है जो आवश्यक रूप से क्षेत्र पर नहीं है (मैं वास्तव में ऐसी क्षमता पर विचार कर रहा हूं)? क्या मैं निश्चित रूप से प्रत्येक हमले के बाद तुरंत राक्षसों पर ध्यान केंद्रित करने के लिए यात्रा करना याद रखूंगा? ऐसा लगता है कि एक समय बम होगा जो कोड के रूप में अधिक जटिल हो जाएगा, इसलिए मुझे लगता है कि यह कोई समाधान नहीं है।
- अब
एक बेहतर समाधान के लिए एक विचार मेरे दूसरे उदाहरण से आता है, जब मैंने उसी समस्या को मारा। एकेडेमिया में हमें हास्केल में अपने स्वयं के डिजाइन की एक भाषा की व्याख्या लिखने के लिए कहा गया था। (यह भी है कि एफपी क्या है यह समझने के लिए मुझे मजबूर किया गया था)। समस्या तब दिखाई दी जब मैं क्लोजर लागू कर रहा था। एक बार फिर एक ही गुंजाइश को अब कई स्थानों से संदर्भित किया जा सकता है: चर के माध्यम से जो इस दायरे को रखता है और किसी भी नेस्टेड स्कोप के मूल दायरे के रूप में! जाहिर है, अगर इस ओर इशारा करते हुए किसी भी संदर्भ के माध्यम से इस दायरे में परिवर्तन किया जाता है, तो यह परिवर्तन अन्य सभी संदर्भों के माध्यम से भी दिखाई देना चाहिए।
मैं जो हल लेकर आया था, उसमें प्रत्येक स्कोप को एक आईडी आवंटित करने और State
मोनाड में सभी स्कोपों का एक केंद्रीय शब्दकोश रखने का था । अब वैरिएबल केवल उस स्कोप की आईडी को धारण करेंगे, जो वे स्कोप के बजाय खुद के लिए बाध्य थे, और नेस्टेड स्कोप भी अपने पेरेंट स्कोप की आईडी को धारण करेंगे।
मुझे लगता है कि मेरे राक्षस से जूझ रहे खेल में उसी दृष्टिकोण का प्रयास किया जा सकता है ... फ़ील्ड और टीम राक्षसों का संदर्भ नहीं देते हैं; इसके बजाय वे राक्षसों की आईडी रखते हैं जो एक केंद्रीय राक्षस शब्दकोश में सहेजे जाते हैं।
हालाँकि, मैं एक बार फिर इस दृष्टिकोण के साथ एक समस्या देख सकता हूं जो मुझे समस्या के समाधान के रूप में बिना किसी हिचकिचाहट के इसे स्वीकार करने से रोकता है:
यह एक बार फिर बॉयलरप्लेट कोड का एक स्रोत है। यह आवश्यक रूप से 3-लाइनर्स बनाता है: पहले जो एकल फ़ील्ड का एक-इन-लाइन संशोधन था, उसके लिए अब आवश्यक है (a) केंद्रीय शब्दकोश से ऑब्जेक्ट को पुनर्प्राप्त करना (b) परिवर्तन करना (c) नई ऑब्जेक्ट को सहेजना केंद्रीय शब्दकोश में। इसके अलावा, संदर्भ होने के बजाय वस्तुओं और केंद्रीय शब्दकोशों की आईडी रखने से जटिलता बढ़ जाती है। चूंकि एफपीआई को जटिलता और बॉयलरप्लेट कोड को कम करने के लिए विज्ञापित किया गया है , इसलिए यह संकेत है कि मैं इसे गलत कर रहा हूं।
मैं asecond समस्या के बारे में लिखने जा रहा था जो बहुत अधिक गंभीर लगती है: यह दृष्टिकोण स्मृति लीक का परिचय देता है । अनुपयोगी वस्तुएं सामान्य रूप से एकत्रित कचरा होंगी। हालाँकि, कोई केंद्रीय शब्दकोश में रखी गई वस्तुओं को एकत्र नहीं किया जा सकता है, भले ही कोई भी पहुंच योग्य वस्तु इस विशेष आईडी को संदर्भित न करे। और जबकि सैद्धांतिक रूप से सावधान प्रोग्रामिंग मेमोरी लीक से बच सकती है (हम ध्यान रख सकते हैं कि प्रत्येक वस्तु को केंद्रीय शब्दकोश से मैन्युअल रूप से हटाने के लिए एक बार इसकी आवश्यकता नहीं है), यह त्रुटि प्रवण है और एफपी को कार्यक्रमों की शुद्धता बढ़ाने के लिए विज्ञापित किया जाता है ताकि एक बार फिर ऐसा हो सके। सही तरीका नहीं है।
हालाँकि, मुझे समय पर पता चला कि यह एक सुलझी हुई समस्या लगती है। जावा प्रदान करता है WeakHashMap
कि इस मुद्दे को हल करने के लिए इस्तेमाल किया जा सकता है। C # एक समान सुविधा प्रदान करता है - ConditionalWeakTable
- यद्यपि डॉक्स के अनुसार इसका उपयोग संकलक द्वारा किया जाना है। और हास्केल में हमारे पास System.Mem.Weak है ।
क्या इस तरह के शब्दकोशों को इस समस्या के लिए सही कार्यात्मक समाधान के रूप में संग्रहीत किया जा रहा है या क्या कोई सरल है जिसे मैं देखने में असफल हो रहा हूं? मैं कल्पना करता हूं कि ऐसे शब्दकोशों की संख्या आसानी से और बुरी तरह से बढ़ सकती है; इसलिए अगर इन डिक्शनरों को भी अपरिवर्तनीय माना जाता है, तो इसका मतलब बहुत सारे पैरामीटर-पासिंग या, उन भाषाओं में हो सकता है जो समर्थन करते हैं, जो कि मोनोडिक संगणना करते हैं, क्योंकि शब्दकोशों को मोनडेस में आयोजित किया जाएगा (लेकिन एक बार फिर मैं इसे शुद्ध रूप से पढ़ रहा हूं जितनी संभव हो उतनी कम कोड वाली भाषाएं मुंदादिक होनी चाहिए, जबकि यह डिक्शनरी समाधान State
मोनड के अंदर लगभग सभी कोड को जगह देगा , जो एक बार फिर मुझे संदेह करता है कि क्या यह सही समाधान है।)
कुछ विचार के बाद मुझे लगता है कि मैं एक और सवाल जोड़ूंगा: हम इस तरह के शब्दकोशों का निर्माण करके क्या हासिल कर रहे हैं? कई विशेषज्ञों के अनुसार, यह अनिवार्य प्रोग्रामिंग के साथ गलत है, जो कुछ वस्तुओं में परिवर्तन कोड के अन्य टुकड़ों के लिए प्रचारित करता है। इस मुद्दे को हल करने के लिए वस्तुओं को अपरिवर्तनीय माना जाता है - ठीक इसी कारण से, अगर मैं सही ढंग से समझता हूं, तो उनके लिए किए गए परिवर्तन कहीं और दिखाई नहीं देने चाहिए। लेकिन अब मैं आउट-ऑफ-डेट डेटा पर काम करने वाले कोड के अन्य टुकड़ों के बारे में चिंतित हूं, इसलिए मैं केंद्रीय शब्दकोशों का आविष्कार करता हूं ताकि ... एक बार फिर कोड के कुछ टुकड़ों में परिवर्तन कोड के अन्य टुकड़ों में फैल जाए! इसलिए, हम अपनी कथित कमियों के साथ अनिवार्य शैली में वापस नहीं हैं, लेकिन अतिरिक्त जटिलता के साथ?
Team
) लड़ाई के परिणाम को पुनः प्राप्त कर सकते हैं और इस प्रकार राक्षसों की स्थिति एक (लड़ाई संख्या, राक्षस इकाई आईडी) टपल से होती है।