शायद आपने अभी फंक्शनल प्रोग्रामिंग के बारे में सुना है और आपके कुछ सवाल हैं।
जैसे…
- फंक्शनल प्रोग्रामिंग वास्तव में क्या है?
- यह ऑब्जेक्ट-ओरिएंटेड प्रोग्रामिंग से कैसे तुलना करता है?
- क्या आपको रूबी में फंक्शनल प्रोग्रामिंग का उपयोग करना चाहिए?
मैं इन सवालों का जवाब दूंगा ताकि आप बेहतर ढंग से समझ सकें कि यह कैसे काम करता है।
फंक्शनल प्रोग्रामिंग क्या है?
यह केवल एक सनक या फैंसी शब्द नहीं है, यह एक वास्तविक प्रोग्रामिंग पैराडाइम है जो लंबे समय से मौजूद है लेकिन हाल ही में इसने फिर से लोकप्रियता हासिल की है।
और इस पैराडाइम के पीछे के मूल विचार आपके विचार से समझने में आसान हैं।
फंक्शनल प्रोग्रामिंग में हम स्टेट बदलने से बचते हैं और "शुद्ध" फंक्शन लिखने का प्रयास करते हैं।
स्टेट बदलने से बचने का मतलब है कि ये फंक्शन फंक्शन के बाहर कुछ भी नहीं बदलते, कोई इंस्टेंस वेरिएबल नहीं, पास किए गए किसी ऑब्जेक्ट को नहीं बदलते…
ऐसा कुछ भी नहीं!
एक फंक्शनल प्रोग्रामिंग भाषा (जैसे हास्केल) में सभी डेटा अपरिवर्तनीय (IMMUTABLE) होता है।
वेरिएबल्स जैसी चीजें होती हैं, लेकिन वे गणितीय दुनिया की तरह व्यवहार करती हैं। एक बार जब एक वेरिएबल को मान दिया जाता है, तो कंपाइलर आपको उस वेरिएबल को किसी अन्य मान से पुनर्परिभाषित करने की अनुमति नहीं देगा।

फंक्शनल प्रोग्रामिंग के लाभ
अपरिवर्तनीयता फंक्शनल प्रोग्रामिंग का मुख्य लाभ है क्योंकि परिवर्तनशील डेटा सूक्ष्म त्रुटियों को जन्म दे सकता है जिन्हें ट्रैक करना कठिन होता है।
उदाहरण:
def all_different_from_first?(arr) first = arr.shift arr.all? { |n| n != first } end arr = [1,3,5,7,9] p all_different_from_first?(arr) # true इस उदाहरण में मैं यह पता लगाना चाहता हूं कि सरणी के सभी तत्व पहले तत्व से भिन्न हैं या नहीं।
इसे काम करने के लिए हमें सरणी से पहले तत्व को हटाना होगा और साथ ही उस तत्व को सहेजना होगा ताकि हम उसकी तुलना बाकी से कर सकें।
हम ऐसा कैसे कर सकते हैं?
हम एक सरणी के साथ काम कर रहे हैं और यदि आप उपलब्ध मेथड्स की सूची देखते हैं तो आप पाएंगे कि Array#shift मेथड ठीक वही करता है जो हम चाहते हैं।
यह तब तक ठीक काम करता है जब तक…
…आप मेथड को एक बार कॉल करने के बाद arr के मान को देखते हैं:
all_different_from_first?(arr) # true arr # [3,5,7,9]
आश्चर्य!
सरणी ने एक तत्व (1) खो दिया और हमने ध्यान नहीं दिया।
यही कारण है कि इस तरह के म्यूटेबिलिटी बग कितने चालाक हो सकते हैं।
सुधारा गया संस्करण:
def all_different_from_first?(arr) arr[1..-1].all? { |n| n != arr.first } end फंक्शनल बनाम OOP
क्या हम सभी को केवल फंक्शनल प्रोग्रामिंग अपनाना चाहिए?
ऐसा लग सकता है कि यह अपरिवर्तनीय स्टेट फंक्शनल प्रोग्रामिंग को OOP का पूर्ण विपरीत बनाता है, और एक अर्थ में यह है, लेकिन फिर भी एक तरीका है जिससे दोनों प्रोग्रामिंग पैराडाइम एक साथ काम कर सकते हैं।
तो नहीं, पूर्ण फंक्शनल प्रोग्रामिंग की ओर भागने की कोई आवश्यकता नहीं है। रूबी वैसे भी OOP के लिए डिज़ाइन किया गया है, इसलिए आप धारा के विरुद्ध लड़ रहे होंगे।
अच्छी खबर:
आप अभी भी फंक्शनल प्रोग्रामिंग के सर्वोत्तम विचारों का उपयोग कर सकते हैं और उन्हें अपने रूबी कोड पर लागू कर सकते हैं।
आइए बात करते हैं कि ऐसा कैसे करें।
म्यूटेबिलिटी को यथासंभव कम करें
ऐसा करने का एक तरीका है attr_accessor का उपयोग बंद करना, केवल attr_reader पर टिके रहना।
ऐसा करने के बाद आपको स्ट्रिंग्स, सरणियों और हैशेज पर नजर रखने की आवश्यकता है।
ऐसे मेथड्स हैं जो इन ऑब्जेक्ट्स को बदल देंगे:
- अधिकांश मेथड्स जो
!में समाप्त होते हैं (जैसेgsub!) - delete
- update
- clear
- shift / unshift / pop / push
पहला कदम इन मेथड्स के बारे में जागरूक होना है।
यदि आपको इन मेथड्स में से किसी एक का उपयोग करना है तो आप एक डुप्लीकेट ऑब्जेक्ट पर काम कर सकते हैं।
एक स्ट्रिंग और उस स्ट्रिंग का क्लोन दिए जाने पर:
str = "abcd" dup = str.dup
जब हम डुप्लीकेट स्ट्रिंग को clear करते हैं तो हमें ये परिणाम मिलते हैं:
dup.clear # str => "abcd" # dup => ""
यह मूल स्ट्रिंग को सुरक्षित रखता है।
आंशिक अनुप्रयोग (Partial Application)
फंक्शनल प्रोग्रामिंग में अपरिवर्तनीय डेटा और शुद्ध फंक्शन के अलावा भी बहुत कुछ है।
जैसे फंक्शन का आंशिक अनुप्रयोग, जिसे "करीइंग" (currying) के नाम से भी जाना जाता है।
उदाहरण:
def add(a,b) a + b end add_five = method(:add).curry[5] add_five.call(5) # 10 add_five.call(20) # 25
ध्यान दें कि add मेथड दो आर्गुमेंट्स लेता है, लेकिन curry मेथड का उपयोग करके हम आर्गुमेंट्स में से एक को "प्रीलोड" कर सकते हैं।
फिर हमें एक लैम्ब्डा मिलता है जिसे हम केवल दूसरे आर्गुमेंट के साथ कॉल कर सकते हैं।
यहाँ एक और उदाहरण है:
list = (1..10) greater_than = ->(x,y) { y > x }.curry list.select(&greater_than.(5)) # [6, 7, 8, 9, 10] list.select(&greater_than.(8)) # [9, 10] एक और उदाहरण:
divisible_by = ->(x,y) { y % x == 0 }.curry list.select(&divisible_by.(5)) # [5, 10] list.select(&divisible_by.(2)) # [2, 4, 6, 8, 10] सारांश
आपने फंक्शनल प्रोग्रामिंग के बारे में सीखा, इसका मूल शुद्ध फंक्शन और अपरिवर्तनीय डेटा है, यह आपके कोड के बारे में सोचने का एक तरीका है और OOP के साथ पूरी तरह असंगत नहीं है।
पढ़ने के लिए धन्यवाद, यदि आपने अभी तक न्यूज़लेटर की सदस्यता नहीं ली है तो सदस्यता लेना न भूलें! 🙂