Kotlin में कार्यात्मक प्रोग्रामिंग: A से Z तक
\nकार्यात्मक प्रोग्रामिंग (FP) एक प्रतिमान है जो गणनाओं को गणितीय फ़ंक्शनों की गणना के रूप में मानता है और स्थिति में बदलाव और परिवर्तनीय डेटा से बचता है। Kotlin, एक बहु-प्रतिमान भाषा होने के नाते, कार्यात्मक दृष्टिकोण को लागू करने के लिए शक्तिशाली उपकरण प्रदान करता है, बिना आपको परिचित OOP को छोड़ने के लिए मजबूर किए। इस लेख में, हम Kotlin में FP की प्रमुख अवधारणाओं को समझेंगे: शुद्ध फ़ंक्शन और अपरिवर्तनीयता से लेकर संयोजन और मोनाड जैसी उन्नत तकनीकों तक।
\n\n1. कार्यात्मक दृष्टिकोण के मूल सिद्धांत: शुद्ध फ़ंक्शन और अपरिवर्तनीयता
\nFP की नींव दो सिद्धांतों पर बनी है: फ़ंक्शनों की शुद्धता और डेटा की अपरिवर्तनीयता।
\n- \n
- शुद्ध फ़ंक्शन एक ऐसा फ़ंक्शन है जिसका परिणाम केवल पारित तर्कों पर निर्भर करता है और जिसका कोई दुष्प्रभाव नहीं होता (बाहरी चर को नहीं बदलता, कंसोल पर आउटपुट नहीं देता, DB तक नहीं पहुँचता)। \n
- अपरिवर्तनीयता का अर्थ है कि डेटा बनने के बाद उसे बदला नहीं जा सकता। मौजूदा ऑब्जेक्ट को बदलने के बजाय, आवश्यक परिवर्तनों के साथ उसकी एक नई प्रतिलिपि बनाई जाती है। \n
Kotlin में शुद्ध और अशुद्ध फ़ंक्शन का उदाहरण:
\n// अशुद्ध फ़ंक्शन: इसका दुष्प्रभाव है (कंसोल पर आउटपुट)\nfun impureSum(a: Int, b: Int): Int {\n println("योग: ${a + b}") // दुष्प्रभाव\n return a + b\n}\n\n// शुद्ध फ़ंक्शन: केवल गणना\nfun pureSum(a: Int, b: Int): Int = a + b\n\n// अपरिवर्तनीयता: var के बजाय val का उपयोग\ndata class User(val name: String, val age: Int) // val फ़ील्ड को अपरिवर्तनीय बनाता है\nfun main() {\n val user = User("Alice", 30)\n // user.age = 31 // संकलन त्रुटि!\n val olderUser = user.copy(age = 31) // हम एक नई प्रतिलिपि बनाते हैं\n}\nKotlin में अपरिवर्तनीयता बनाए रखने के लिए val और copy() के साथ data class का उपयोग मानक तरीका है।
2. उच्च-क्रम फ़ंक्शन और लैम्ब्डा अभिव्यक्तियाँ
\nKotlin फ़ंक्शनों को प्रथम श्रेणी की वस्तुओं के रूप में समर्थन करता है। इसका अर्थ है कि फ़ंक्शनों को तर्क के रूप में पारित किया जा सकता है, अन्य फ़ंक्शनों से लौटाया जा सकता है, और चर में संग्रहीत किया जा सकता है। वे फ़ंक्शन जो अन्य फ़ंक्शनों को स्वीकार या लौटाते हैं, उच्च-क्रम फ़ंक्शन कहलाते हैं।
\nलैम्ब्डा अभिव्यक्तियाँ अनाम फ़ंक्शन बनाने का एक संक्षिप्त तरीका है। सिंटैक्स: { तर्क -> मुख्य भाग }।
// उच्च-क्रम फ़ंक्शन: एक फ़ंक्शन (Int, Int) -> Int स्वीकार करता है\nfun operateOnNumbers(a: Int, b: Int, operation: (Int, Int) -> Int): Int {\n return operation(a, b)\n}\n\nfun main() {\n // लैम्ब्डा अभिव्यक्तियाँ\n val sum: (Int, Int) -> Int = { x, y -> x + y }\n val multiply: (Int, Int) -> Int = { x, y -> x * y }\n\n println(operateOnNumbers(5, 3, sum)) // 8\n println(operateOnNumbers(5, 3, multiply)) // 15\n\n // "मौके पर" लैम्ब्डा का उपयोग\n println(operateOnNumbers(10, 2, { a, b -> a - b })) // 8\n\n // यदि लैम्ब्डा अंतिम तर्क है, तो इसे कोष्ठक के बाहर रखा जा सकता है (trailing lambda)\n println(operateOnNumbers(10, 2) { a, b -> a / b }) // 5\n}\nKotlin की मानक लाइब्रेरी संग्रह के लिए उच्च-क्रम फ़ंक्शनों का सक्रिय रूप से उपयोग करती है: map, filter, reduce।
val numbers = listOf(1, 2, 3, 4, 5)\nval evenSquares = numbers\n .filter { it % 2 == 0 } // {2, 4}\n .map { it * it } // {4, 16}\nprintln(evenSquares) // [4, 16]\n\n3. फ़ंक्शन संयोजन और करीइंग
\nसंयोजन एक नया फ़ंक्शन बनाने के लिए दो या अधिक फ़ंक्शनों को संयोजित करने की प्रक्रिया है। Kotlin में Haskell की तरह कोई अंतर्निहित संयोजन ऑपरेटर नहीं है, लेकिन इसे मैन्युअल रूप से या एक्सटेंशन फ़ंक्शनों का उपयोग करके आसानी से लागू किया जा सकता है।
\n// दो फ़ंक्शनों का संयोजन\ninfix fun ((B) -> C).compose(f: (A) -> B): (A) -> C = { a -> this(f(a)) }\n\nfun main() {\n val toInt: (String) -> Int = { it.toInt() }\n val square: (Int) -> Int = { it * it }\n\n val squ