स्टेटलेस प्रोग्रामिंग के लाभ?


132

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

क्या हास्केल (या एक और विशुद्ध रूप से कार्यात्मक भाषा) को गहराई से सीखना जारी रखने के लायक है? क्या क्रियात्मक या स्टेटलेस प्रोग्रामिंग वास्तव में प्रक्रियात्मक से अधिक उत्पादक है? क्या यह संभावना है कि मैं हास्केल या किसी अन्य कार्यात्मक भाषा का बाद में उपयोग करना जारी रखूंगा, या क्या मुझे इसे केवल समझ के लिए सीखना चाहिए?

मैं उत्पादकता की तुलना में प्रदर्शन के बारे में कम परवाह करता हूं। इसलिए मैं मुख्य रूप से पूछ रहा हूं कि क्या मैं एक प्रक्रियात्मक / वस्तु-उन्मुख / जो भी हो, की तुलना में कार्यात्मक भाषा में अधिक उत्पादक होगा।

जवाबों:


168

संक्षेप में कार्यात्मक प्रोग्रामिंग पढ़ें ।

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

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


5
मैं इसे अपनी सहमति देता हूँ! मेरा मानना ​​है कि कार्यात्मक प्रोग्रामिंग को समानांतर प्रोग्रामिंग के लिए इसकी उपयुक्तता के कारण भविष्य में अधिक व्यापक रूप से उपयोग किया जाएगा।
रे हिदायत

@ रे: मैं वितरित प्रोग्रामिंग भी जोड़ूंगा!
एंटोन टायखी

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

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

2
एफपी के साथ स्टैटिस्टिकल को बराबर करना। कई एफपी कार्यक्रम राज्य से भरे हुए हैं, यह बस एक वस्तु के बजाय एक बंद में मौजूद है।
मीकेमेकाना

46

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

आप जॉन ह्यूज के पेपर व्हाई फंक्शनल प्रोग्रामिंग मैटर्स (पीडीएफ) में बहुत सारे उदाहरणों के साथ एक अच्छा ट्यूटोरियल पा सकते हैं ।

आप हो जाएगा gobs अधिक उत्पादक, खासकर यदि आप एक कार्यात्मक भाषा भी बीजीय डेटा प्रकार और पैटर्न मिलान (CAML, एसएमएल, हास्केल) है कि लेने।


क्या मिक्सिन भी OOP के साथ पुन: प्रयोज्य कोड प्रदान नहीं करेगा? OOP की वकालत न करते हुए सिर्फ चीजों को खुद समझने की कोशिश करें।
मीकेमेकाना

20

कई अन्य उत्तरों ने कार्यात्मक प्रोग्रामिंग के प्रदर्शन (समानांतरवाद) पक्ष पर ध्यान केंद्रित किया है, जो मुझे लगता है कि बहुत महत्वपूर्ण है। हालाँकि, आपने विशेष रूप से उत्पादकता के बारे में पूछा था, जैसा कि आप एक कार्यात्मक प्रतिमान की तुलना में एक ही कार्य को तेजी से कर सकते हैं।

मुझे वास्तव में (व्यक्तिगत अनुभव से) लगता है कि एफ # में प्रोग्रामिंग उस तरह से मेल खाती है जो मुझे बेहतर लगता है, और इसलिए यह आसान है। मुझे लगता है कि यही सबसे बड़ा अंतर है। मैंने F # और C # दोनों में प्रोग्राम किया है, और F # में "भाषा से लड़ने" में बहुत कम है, जो मुझे पसंद है। आपको F # के विवरण के बारे में सोचने की जरूरत नहीं है। यहाँ कुछ उदाहरण हैं जो मैंने पाया है कि मैं वास्तव में आनंद लेता हूं।

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

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

let matchingFactors =
    factors
    |> Seq.filter (fun x -> largestPalindrome % x = 0)
    |> Seq.map (fun x -> (x, largestPalindrome / x))

मुझे लगता है कि फ़िल्टर करना तो C # में एक नक्शा (जो प्रत्येक तत्व का रूपांतरण है) काफी सरल होगा, लेकिन आपको निचले स्तर पर सोचना होगा। विशेष रूप से, आपको स्वयं लूप लिखना होगा, और यदि स्टेटमेंट, और उन प्रकार की चीजों का अपना स्वयं का स्पष्ट विवरण होगा। एफ # सीखने के बाद से, मैंने महसूस किया है कि मैंने कार्यात्मक तरीके से कोड करना आसान पाया है, जहां यदि आप फ़िल्टर करना चाहते हैं, तो आप "फ़िल्टर" लिखते हैं, और यदि आप मैप करना चाहते हैं, तो आप लागू करने के बजाय "मैप" लिखते हैं। प्रत्येक विवरण।

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

तो बस सामान्य तौर पर, भले ही मैं C # और F # दोनों में प्रोग्राम कर सकता हूं, मुझे F # का उपयोग करना आसान लगता है क्योंकि आप उच्च स्तर पर सोच सकते हैं। मैं यह तर्क दूंगा कि छोटे विवरण कार्यात्मक प्रोग्रामिंग (एफ # कम से कम) से हटा दिए जाते हैं, इसलिए कि मैं अधिक उत्पादक हूं।

संपादित करें : मैंने उन टिप्पणियों में से एक में देखा जो आपने एक कार्यात्मक प्रोग्रामिंग भाषा में "राज्य" का एक उदाहरण पूछा था। F # को अनिवार्य रूप से लिखा जा सकता है, इसलिए यहां एक प्रत्यक्ष उदाहरण है कि आप F # में कैसे परस्पर स्थिति रख सकते हैं:

let mutable x = 5
for i in 1..10 do
    x <- x + i

1
मैं आपकी पोस्ट से आम तौर पर सहमत हूं, लेकिन>> प्रति से कार्यात्मक प्रोग्रामिंग के साथ कुछ नहीं करना है। वास्तव में, के a |> b (p1, p2)लिए सिर्फ सिंथेटिक चीनी है b (a, p1, p2)। इसे सही-संगति के साथ जोड़े और आपको मिल गया है।
एंटोन टायखी

2
सच है, मुझे यह स्वीकार करना चाहिए कि शायद F # के साथ मेरे बहुत सारे सकारात्मक अनुभव F # के साथ अधिक है, जितना कि यह कार्यात्मक प्रोग्रामिंग के साथ है। लेकिन फिर भी, दोनों के बीच एक मजबूत सहसंबंध है, और भले ही प्रकार प्रतिक्षेप और /> जैसी चीजें कार्यात्मक प्रोग्रामिंग नहीं हैं, निश्चित रूप से मैं दावा करूंगा कि वे "क्षेत्र के साथ चलते हैं।" कम से कम सामान्य तौर पर।
रे हिदायत

|> इस मामले में एक अन्य उच्च-क्रम infix फ़ंक्शन है, इस मामले में एक फ़ंक्शन-एप्लिकेशन ऑपरेटर। अपने स्वयं के उच्च-क्रम को परिभाषित करते हुए, infix ऑपरेटर्स निश्चित रूप से कार्यात्मक प्रोग्रामिंग का एक हिस्सा है (जब तक कि आप एक स्कीमर नहीं हैं)। हास्केल के पास अपना $ है जो पाइप लाइन में सूचना को छोड़कर दाएं से बाएं ओर बहता है।
नॉर्मन राम्से

15

लंबे समय तक डिबगिंग में बिताए गए सभी कठिन बगों पर विचार करें।

अब, उन बगों में से कितने एक कार्यक्रम के दो अलग-अलग घटकों के बीच "अनजाने बातचीत" के कारण थे? (लगभग सभी थ्रेडिंग बग्स में यह रूप है: साझा डेटा, गतिरोधों को लिखने वाली दौड़ ... इसके अलावा, यह उन पुस्तकालयों को खोजने के लिए आम है जो वैश्विक राज्य पर कुछ अप्रत्याशित प्रभाव डालते हैं, या रजिस्ट्री / पर्यावरण को पढ़ते / लिखते हैं, आदि) I यह मानते हैं कि कम से कम 1 से 3 'हार्ड बग' इस श्रेणी में आते हैं।

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

यह 'अपरिवर्तनीयता' IMO से बड़ी जीत है। एक आदर्श दुनिया में, हम सभी भयानक एपीआई डिजाइन करेंगे और यहां तक ​​कि जब चीजें परस्पर थीं, तो प्रभाव स्थानीय और अच्छी तरह से प्रलेखित होंगे और 'अप्रत्याशित' बातचीत को न्यूनतम रखा जाएगा। वास्तविक दुनिया में, बहुत सारे एपीआई हैं जो वैश्विक रूप से असंख्य तरीकों से बातचीत करते हैं, और ये सबसे खतरनाक कीड़े का स्रोत हैं। स्टैच्यूलेसनेस की आकांक्षा घटकों के बीच अनजाने / अंतर्निहित / पीछे-पीछे के दृश्यों से छुटकारा पाने की आकांक्षा है।


6
किसी ने एक बार कहा था कि एक परिवर्तनशील मूल्य को अधिलेखित करने का मतलब है कि आप पिछले मूल्य को एकत्रित / मुक्त कर रहे हैं। कुछ मामलों में उस मान का उपयोग करके कार्यक्रम के अन्य हिस्सों को नहीं किया गया। जब मूल्यों को उत्परिवर्तित नहीं किया जा सकता है, तो बगों का यह वर्ग भी चला जाता है।
shapr

8

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

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

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


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

मान लें कि आपके पास sin(PI/3)अपने कोड में है, जहां PI एक स्थिर है, संकलक इस फ़ंक्शन का संकलन समय पर मूल्यांकन कर सकता है और परिणाम को उत्पन्न कोड में एम्बेड कर सकता है।
आर्टिलियस

6

राज्य के बिना, अपने कोड को स्वचालित रूप से समानांतर करना बहुत आसान है (जैसा कि सीपीयू अधिक से अधिक कोर के साथ किया जाता है यह बहुत महत्वपूर्ण है)।


हां, मैंने उस पर जरूर गौर किया है। विशेष रूप से एर्लैंग का कंसीलर मॉडल बहुत पेचीदा है। हालाँकि, इस बिंदु पर मैं वास्तव में समसामयिकता की उतनी परवाह नहीं करता, जितनी उत्पादकता की। क्या राज्य के बिना प्रोग्रामिंग से उत्पादकता बोनस है?
साशा चोडगोव

2
@musicfreak, नहीं, कोई उत्पादकता बोनस नहीं है। लेकिन एक नोट के रूप में, आधुनिक एफपी भाषाएँ अभी भी आपको राज्य का उपयोग करने देती हैं यदि आपको वास्तव में इसकी आवश्यकता है।
अज्ञात

वास्तव में? क्या आप एक कार्यात्मक भाषा में राज्य का एक उदाहरण दे सकते हैं, बस मैं देख सकता हूं कि यह कैसे किया जाता है?
साशा चेदिगोव

हास्केल में स्टेट मोनाड की
रैंपियन

4
@ परिचित: मैं असहमत हूं। राज्य के बिना प्रोग्रामिंग उन बगों की घटना को कम करता है जो विभिन्न घटकों के अप्रत्याशित / अनपेक्षित इंटरैक्शन के कारण होते हैं। यह बेहतर डिजाइन (अधिक पुन: प्रयोज्य, तंत्र और नीति के पृथक्करण, और उस तरह का सामान) को भी प्रोत्साहित करता है। यह हमेशा हाथ में काम के लिए उपयुक्त नहीं है, लेकिन कुछ मामलों में वास्तव में चमकता है।
आर्टेलियस

6

जब आप उच्च यातायात शुरू करते हैं तो स्टेटलेस वेब एप्लिकेशन आवश्यक होते हैं।

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

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

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


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