C++ में कार्यात्मक प्रोग्रामिंग: उन्नत स्तर
कार्यात्मक प्रोग्रामिंग (एफपी) एक प्रतिमान है जिसमें गणनाओं को गणितीय फलनों की गणना के रूप में प्रस्तुत किया जाता है, जिसमें अवस्था में परिवर्तन और परिवर्तनीय डेटा से बचा जाता है। हालाँकि C++ मूल रूप से एक ऑब्जेक्ट-ओरिएंटेड और प्रक्रियात्मक भाषा थी, C++11 मानक से शुरू होकर इसमें एफपी के लिए शक्तिशाली उपकरण मिले: लैम्ब्डा एक्सप्रेशन, std::function, std::bind, और C++17 में std::optional और std::variant का समर्थन जोड़ा गया, जो मोनैडिक पैटर्न को लागू करने की अनुमति देते हैं। इस लेख में हम C++ में कार्यात्मक प्रोग्रामिंग की उन्नत तकनीकों पर विचार करेंगे: फ़ंक्शन संयोजन, करीइंग, मोनाड के साथ काम करना और भाषा की आधुनिक क्षमताओं का उपयोग करके शुद्ध फ़ंक्शन बनाना।
1. लैम्ब्डा एक्सप्रेशन और शुद्ध फ़ंक्शन
लैम्ब्डा एक्सप्रेशन C++ में कार्यात्मक शैली का आधार हैं। वे मौके पर ही अनाम फ़ंक्शन बनाने की अनुमति देते हैं, जो <algorithm> से एल्गोरिदम के लिए आदर्श है। हालाँकि, वास्तविक एफपी के लिए यह महत्वपूर्ण है कि लैम्ब्डा शुद्ध हों - अर्थात उनके कोई दुष्प्रभाव न हों और वे बाहरी परिवर्तनीय अवस्था पर निर्भर न हों।
#include <iostream>#include <vector>#include <algorithm>
int main() { std::vector<int> numbers = {1, 2, 3, 4, 5};
// शुद्ध लैम्ब्डा: केवल इनपुट डेटा, केवल आउटपुट auto square = [](int x) { return x * x; };
// बिना दुष्प्रभावों के transform लागू करें std::vector<int> squared; std::transform(numbers.begin(), numbers.end(), std::back_inserter(squared), square);
for (int n : squared) std::cout << n << " "; // 1 4 9 16 25 return 0;}उन्नत उपयोग के लिए, यदि यह महत्वपूर्ण न हो तो संदर्भ द्वारा कैप्चर ([&]) से बचना चाहिए। मान द्वारा कैप्चर ([=]) या कैप्चर की स्पष्ट सूची लैम्ब्डा को अधिक पूर्वानुमानित और परीक्षण योग्य बनाती है।
2. std::function और ऑपरेटरों के साथ फ़ंक्शन संयोजन
संयोजन दो या अधिक फ़ंक्शनों को एक में मिलाना है। C++ में टेम्पलेट और std::function का उपयोग करके संयोजन को लागू किया जा सकता है। आइए एक सामान्यीकृत संयोजक पर विचार करें:
#include <functional>#include <iostream>
template <typename F, typename G>auto compose(F f, G g) { return [f, g](auto x) { return f(g(x)); };}
int main() { auto addOne = [](int x) { return x + 1; }; auto multiplyByTwo = [](int x) { return x * 2; };
auto addThenMultiply = compose(multiplyByTwo, addOne); std::cout << addThenMultiply(5) << std::endl; // (5+1)*2 = 12
// कई फ़ंक्शनों का संयोजन auto triple = compose(multiplyByTwo, compose(addOne, addOne)); std::cout << triple(5) << std::endl; // ((5+1)+1)*2 = 14 return 0;}अधिक जटिल श्रृंखलाओं के लिए पाइपलाइन ऑपरेटर (अन्य भाषाओं में |> के समान) का उपयोग किया जा सकता है। C++20 में सुविधाजनक सिंटैक्स बनाने के लिए operator| को ओवरलोड करने की संभावना आई:
#include <functional>#include <iostream>
template <typename F>class Pipeable { F f;public: Pipeable(F func) : f(func) {} template <typename T> auto operator()(T x) const { return f(x); }};
template <typename T, typename F>auto operator|(T x, Pipeable<F> p) { return p(x);}
int main() { auto addOne = Pipeable([](int x) { return x + 1; }); auto square = Pipeable([](int x) { return x * x; });
int result = 5 | addOne | square; // (5+1)^2 = 36 std::cout << result << std::endl; return 0;}ऐसा दृष्टिकोण कोड को घोषणात्मक और आसानी से पढ़ने योग्य बनाता है।
3. करीइंग और आंशिक अनुप्रयोग
करीइंग - कई तर्कों वाले फ़ंक्शन को