कार्यात्मक प्रोग्रामिंग - अपरिवर्तनीयता


12

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

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


संगामिति मुद्दों को संभालने का एक तरीका यह है कि हर बार कतार की प्रतियां बनाई जाए (कुछ महंगी, लेकिन काम करता है)।
जॉब

infoq.com/pretations/Functional-Data-Structures-in-Scala आपको यह स्पीच व्यावहारिक लग सकता है।
deadalnix

जवाबों:


19

हालांकि यह कभी-कभी इस तरह से व्यक्त किया जाता है, कार्यात्मक प्रोग्रामिंग 'स्टेटफुल कंप्यूटेशन को रोकता नहीं है। यह जो करता है वह प्रोग्रामर को राज्य को स्पष्ट करने के लिए मजबूर करता है।

उदाहरण के लिए, चलिए कुछ प्रोग्राम की मूल संरचना को एक अनिवार्य कतार (कुछ छद्म भाषा में) का उपयोग करके लेते हैं:

q := Queue.new();
while (true) {
    if (Queue.is_empty(q)) {
        Queue.add(q, producer());
    } else {
        consumer(Queue.take(q));
    }
}

एक कार्यात्मक कतार डेटा संरचना के साथ संबंधित संरचना (अभी भी एक अनिवार्य भाषा में, ताकि एक समय में एक अंतर से निपटने के लिए) इस तरह दिखाई दे:

q := Queue.empty;
while (true) {
    if (q = Queue.empty) {
        q := Queue.add(q, producer());
    } else {
        (tail, element) := Queue.take(q);
        consumer(element);
        q := tail;
    }
}

चूंकि अब कतार अपरिवर्तनीय है, इसलिए वस्तु स्वयं नहीं बदलती है। इस छद्म कोड में, qस्वयं एक चर है; असाइनमेंट q := Queue.add(…)और q := tailयह एक अलग वस्तु की ओर इशारा करते हैं। कतार फ़ंक्शन का इंटरफ़ेस बदल गया है: प्रत्येक को ऑपरेशन से उत्पन्न नई कतार ऑब्जेक्ट को वापस करना होगा।

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

main_loop(q, other_state) {
    if (q = Queue.empty) {
        let (new_state, element) = producer(other_state);
        main_loop(Queue.add(q, element), new_state);
    } else {
        let (tail, element) = Queue.take(q);
        let new_state = consumer(other_state, element);
        main_loop(tail, new_state);
    }
}
main_loop(Queue.empty, initial_state)

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

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

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

main_loop(q) =
    consumer->consume(q->take()) || q->add(producer->produce());
    main_loop(q)

एक "औद्योगिक" भाषा है कि संगामिति right³ हो जाता है Erlang । सीखना Erlang निश्चित रूप से समवर्ती प्रोग्रामिंग के बारे में ज्ञानोदय का मार्ग है।

हर कोई अब साइड-इफ़ेक्ट-फ्री भाषाओं पर स्विच करता है!

Several इस शब्द के कई अर्थ हैं; यहाँ मुझे लगता है कि आप इसका उपयोग साइड इफेक्ट्स के बिना प्रोग्रामिंग के लिए कर रहे हैं, और इसका अर्थ है कि मैं भी उपयोग कर रहा हूँ।
² अंतर्निहित अवस्था के साथ प्रोग्रामिंग अनिवार्य प्रोग्रामिंग है ; ऑब्जेक्ट ओरिएंटेशन पूरी तरह से ऑर्थोगोनल चिंता है।
³ भड़काऊ, मुझे पता है, लेकिन मेरा मतलब है। साझा मेमोरी के साथ थ्रेड्स समवर्ती प्रोग्रामिंग की विधानसभा भाषा है। संदेश पास करना समझने में बहुत आसान है, और जैसे ही आप संक्षिप्तता का परिचय देते हैं, साइड इफेक्ट्स की कमी वास्तव में चमक जाती है।
Coming और यह किसी ऐसे व्यक्ति से आ रहा है जो एर्लांग का प्रशंसक नहीं है, लेकिन अन्य कारणों से।


2
+1 बहुत अधिक पूर्ण उत्तर, हालांकि मुझे लगता है कि कोई यह समझा सकता है कि एर्लांग एक शुद्ध एफपी भाषा नहीं है।
रीन हेनरिक्स

1
@ राइन हेनरिक: वास्तव में। वास्तव में, वर्तमान में सभी मौजूदा मुख्यधारा की भाषाओं में, एरलंग वह है जो ऑब्जेक्ट-ओरिएंटेशन को सबसे अधिक ईमानदारी से लागू करता है।
जोर्ग डब्ल्यू मित्तग

2
@ जार्ज सहमत। हालांकि, फिर से, कोई भी यह समझा सकता है कि शुद्ध एफपी और ओओ ओर्थोगोनल हैं।
रीन हेनरिच

इसलिए, समवर्ती सॉफ्टवेयर में एक अपरिवर्तनीय कतार को लागू करने के लिए, संदेशों को नोड्स के बीच भेजने और प्राप्त करने की आवश्यकता होती है। कहाँ संग्रहीत संदेश लंबित हैं?
मौविसीयल

@mouviciel कतार तत्व नोड के आने वाले संदेश कतार में संग्रहीत किए जाते हैं। यह संदेश कतार की सुविधा वितरित बुनियादी सुविधाओं की एक बुनियादी विशेषता है। एक वैकल्पिक अवसंरचना डिजाइन जो स्थानीय संगामिति के लिए अच्छी तरह से काम करता है लेकिन वितरित सिस्टम के साथ नहीं होता है जब तक कि रिसीवर तैयार न हो तब तक प्रेषक को ब्लॉक न करें। मुझे लगता है कि यह सब कुछ स्पष्ट नहीं करता है, यह पूरी तरह से समझाने के लिए समवर्ती प्रोग्रामिंग पर एक पुस्तक के एक या दो अध्याय ले जाएगा।
गिलेस एसओ- बुराई को रोकना '23

4

एफपी लैंगगेज में स्टेटफुल व्यवहार को एक पूर्व राज्य से एक नए राज्य में परिवर्तन के रूप में लागू किया जाता है। उदाहरण के लिए, enqueue एक कतार से एक रूपांतरण होगा और एक नई कतार के मान के साथ एक मूल्य होगा। Dequeue एक कतार से मान में परिवर्तन और हटाए गए मान के साथ एक नई कतार होगी। इस राज्य परिवर्तन (और संगणना के अन्य परिणाम) को उपयोगी तरीकों से अलग करने के लिए मठों जैसे निर्माणों को तैयार किया गया है


3
यदि यह प्रत्येक ऐड / रिमूवल ऑपरेशन के लिए एक नई कतार है, तो दो (या अधिक) async ऑपरेशन (थ्रेड्स) कतार को कैसे साझा करेंगे? क्या यह कतार की नई-आईएनजी को अमूर्त करने का एक पैटर्न है?
वेनकराम

कंसीडर एक बिल्कुल अलग सवाल है। मैं एक टिप्पणी में पर्याप्त जवाब नहीं दे सकता।
रीन हेनरिक्स

2
@ हेन हेनरिक्स: "टिप्पणी में पर्याप्त जवाब नहीं दे सकता है"। आमतौर पर इसका मतलब है कि आपको टिप्पणी से संबंधित मुद्दों के समाधान के लिए उत्तर को अद्यतन करना चाहिए।
एस.लॉट

कंसीडर भी मोनैडिक हो सकते हैं, हैक्सल्स कंट्रोल देखें। Concurrency.STM
वैकल्पिक

1
@ S.Lott इस मामले में इसका मतलब है कि ओपी को एक नया सवाल पूछना चाहिए। इस प्रश्न के बारे में कंज्यूरिटी ओटी है, जो अपरिवर्तनीय डेटा संरचनाओं के बारे में है।
रीन हेनरिक्स

2

... समस्याएं जो एफपी में अपरिवर्तनीय लोगों के साथ ओओपी में राज्य के प्रतिनिधित्व द्वारा हल की जाती हैं (उदाहरण के लिए: उत्पादकों और उपभोक्ता के साथ एक कतार)

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

कई उत्पादकों के लिए कई तरीके हैं जो एक एकल साझा उपभोक्ता को अपना परिणाम भेजते हैं। एफ # में शायद सबसे स्पष्ट समाधान उपभोक्ता को एक एजेंट (उर्फ MailboxProcessor) बनाना है और उत्पादकों Postको उपभोक्ता एजेंट के लिए अपने परिणाम देना है। यह आंतरिक रूप से एक कतार का उपयोग करता है और यह शुद्ध नहीं है (एफ # में संदेश भेजना एक अनियंत्रित दुष्प्रभाव है, एक अशुद्धता है)।

हालांकि, यह काफी संभावना है कि अंतर्निहित समस्या समानांतर प्रोग्रामिंग से बिखरने वाले पैटर्न की तरह कुछ और है। इस समस्या को हल करने के लिए आप इनपुट मानों की एक सरणी बना सकते हैं और फिर Array.Parallel.mapउन पर और एक धारावाहिक का उपयोग करके परिणाम एकत्र कर सकते हैं Array.reduce। वैकल्पिक रूप से, आप PSeqसमानांतर में अनुक्रमों के तत्वों को संसाधित करने के लिए मॉड्यूल से कार्यों का उपयोग कर सकते हैं ।

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


1

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

मैं आपको क्लजुरे में राज्य और पहचान के बारे में एक उत्कृष्ट लेख पढ़ने की सलाह देता हूं , यह विवरणों को बहुत बेहतर तरीके से समझाता है।

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