C++ में कार्यात्मक प्रोग्रामिंग: लैम्ब्डा से कम्पोज़िशन तक
कार्यात्मक प्रोग्रामिंग (Functional Programming - FP) एक प्रतिमान है जिसमें गणनाएँ शुद्ध फ़ंक्शनों (pure functions), डेटा की अपरिवर्तनीयता (immutability) और साइड इफ़ेक्ट्स (side effects) की अनुपस्थिति पर आधारित होती हैं। हालाँकि C++ मूल रूप से एक मल्टी-पैराडाइम भाषा थी, इसके आधुनिक मानकों (C++11/14/17/20) ने FP के लिए शक्तिशाली उपकरण शामिल किए हैं: लैम्ब्डा एक्सप्रेशन (lambda expressions), std::function, STL एल्गोरिदम, कोरूटीन (coroutines) और यहाँ तक कि मोनैडिक पैटर्न (monadic patterns) का समर्थन भी। इस लेख में, हम समझेंगे कि प्रदर्शन (performance) खोए बिना C++ में कार्यात्मक कोड कैसे लिखें।
1. कार्यात्मक शैली के मूल तत्व: लैम्ब्डा और std::function
लैम्ब्डा एक्सप्रेशन C++ में FP का हृदय हैं। ये संदर्भ (context) को कैप्चर करते हुए, तुरंत (on the fly) अनाम फ़ंक्शन (anonymous functions) बनाने की अनुमति देते हैं।
#include <iostream>#include <vector>#include <algorithm>
int main() { std::vector<int> nums = {1, 2, 3, 4, 5}; // सम संख्याओं को फ़िल्टर करने के लिए लैम्ब्डा auto is_even = [](int x) { return x % 2 == 0; }; // std::copy_if एल्गोरिदम के साथ उपयोग std::vector<int> evens; std::copy_if(nums.begin(), nums.end(), std::back_inserter(evens), is_even); for (int n : evens) std::cout << n << " "; // 2 4 return 0;}लैम्ब्डा के प्रमुख बिंदु:
- कैप्चर (Capture) —
[=](मान द्वारा),[&](संदर्भ द्वारा),[this](क्लास मेथड के लिए). - प्रकार (Type) — प्रत्येक लैम्ब्डा का एक अद्वितीय प्रकार होता है, इसलिए फ़ंक्शन में पास करने के लिए
std::functionया टेम्पलेट का उपयोग किया जाता है। - वापसी मान (Return Value) — यदि अन्यथा निर्दिष्ट नहीं किया गया है, तो स्वचालित रूप से अनुमान लगाया जाता है।
std::function — callable-ऑब्जेक्ट्स (फ़ंक्शन, लैम्ब्डा, फ़ंक्टर) के लिए एक रैपर है। भंडारण और पास करने के लिए सुविधाजनक है, लेकिन इसमें अतिरिक्त ओवरहेड (वर्चुअल कॉल) जुड़ जाता है।
#include <functional>
void apply_twice(std::function<int(int)> f, int x) { std::cout << f(f(x)) << std::endl; // कम्पोज़िशन}
int main() { auto square = [](int x) { return x * x; }; apply_twice(square, 3); // (3^2)^2 = 81 return 0;}2. कार्यात्मक श्रृंखलाओं के आधार के रूप में STL एल्गोरिदम
STL एल्गोरिदम (std::transform, std::copy_if, std::accumulate आदि) कार्यात्मक शैली पर पूरी तरह फिट बैठते हैं। ये सीधे कंटेनरों को संशोधित नहीं करते हैं, बल्कि इटरेटर लेते हैं और परिणाम लौटाते हैं।
उदाहरण: फ़िल्टरिंग और रूपांतरण (map/filter)
#include <numeric>#include <ranges> // C++20
int main() { std::vector<int> data = {1, 2, 3, 4, 5, 6}; // क्लासिकल दृष्टिकोण (C++11) std::vector<int> filtered; std::copy_if(data.begin(), data.end(), std::back_inserter(filtered), [](int x) { return x > 3; }); std::vector<int> result; std::transform(filtered.begin(), filtered.end(), std::back_inserter(result), [](int x) { return x * 2; }); // ranges के साथ आधुनिक दृष्टिकोण (C++20) auto view = data | std::views::filter([](int x) { return x > 3; }) | std::views::transform([](int x) { return x * 2; }); for (int v : view) std::cout << v << " "; // 8 10 12 return 0;}std::accumulate के साथ फोल्ड (fold)
#include <numeric>
int main() { std::vector<int> nums = {1, 2, 3, 4}; // प्रारंभिक मान 0 के साथ योग int sum = std::accumulate(nums.begin(), nums.end(), 0, [](int a, int b) { return a + b; }); // प्रारंभिक मान 1 के साथ गुणनफल int prod = std::acc
```