البرمجة الوظيفية في C++: المستوى المتقدم

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

البرمجة الوظيفية في لغة C++: المستوى المتقدم



البرمجة الوظيفية (FP) هي نموذج يتم فيه تمثيل العمليات الحسابية كتقييم للدوال الرياضية، مع تجنب تغييرات الحالة والبيانات القابلة للتغيير. على الرغم من أن لغة 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; };

// تطبيق التحويل بدون آثار جانبية 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. الكيرينج والتطبيق الجزئي



الكيرينج هو تحويل دالة ذات عدة وسائط إلى

المدونات

توصيات الكتب