مقدمة في البرمجة الوظيفية على المستوى المتقدم
\n\nالبرمجة الوظيفية (FP) هي نموذج ينظر إلى العمليات الحسابية على أنها تنفيذ دوال رياضية ويتجنب تغيير الحالة والبيانات القابلة للتغيير. في JavaScript، خاصة في بيئة Node.js، أصبحت البرمجة الوظيفية أكثر شيوعًا بفضل قابليتها للتنبؤ، وقابلية الاختبار، والتوازي.
\n\nإذا كنت قد أتقنت بالفعل أساسيات البرمجة الوظيفية (الدوال النقية، دوال الترتيب الأعلى، map، filter، reduce)، فقد حان الوقت للانتقال إلى المستوى التالي. في هذه المقالة، سنناقش المفاهيم المتقدمة: الكاري، التركيب، المونادات، والعمل مع البيانات الثابتة.
1. الكاري والتطبيق الجزئي
\n\nما هو الكاري؟
\nالكاري هو عملية تحويل دالة تأخذ عدة وسائط إلى سلسلة من الدوال، كل منها يأخذ وسيطة واحدة. هذا يسمح بإنشاء دوال متخصصة بناءً على دوال عامة.
\n\n// دالة عادية\nconst add = (a, b, c) => a + b + c;\nconsole.log(add(1, 2, 3)); // 6\n\n// النسخة المُكَرْيَة\nconst curriedAdd = a => b => c => a + b + c;\nconsole.log(curriedAdd(1)(2)(3)); // 6\n\n// دالة كاري عامة\nconst curry = (fn) => {\n const arity = fn.length;\n const resolver = (...args) => {\n if (args.length < arity) {\n return (...nextArgs) => resolver(...args, ...nextArgs);\n }\n return fn(...args);\n };\n return resolver;\n};\n\nconst multiply = (a, b, c) => a * b * c;\nconst curriedMultiply = curry(multiply);\nconsole.log(curriedMultiply(2)(3)(4)); // 24\nconsole.log(curriedMultiply(2, 3)(4)); // 24\n\nالتطبيق الجزئي
\nالتطبيق الجزئي هو تثبيت جزء من وسائط الدالة، مما يؤدي إلى إنشاء دالة جديدة بعدد أقل من الوسائط. على عكس الكاري، لا يتطلب التطبيق الجزئي تسلسلًا صارمًا للاستدعاءات.
\n\nconst partial = (fn, ...presetArgs) => (...laterArgs) => fn(...presetArgs, ...laterArgs);\n\nconst greet = (greeting, name) => `${greeting}, ${name}!`;\nconst sayHello = partial(greet, 'Hello');\nconst sayHi = partial(greet, 'Hi');\n\nconsole.log(sayHello('Alice')); // Hello, Alice!\nconsole.log(sayHi('Bob')); // Hi, Bob!\n\n2. تركيب الدوال
\n\nالتركيب المتقدم
\nالتركيب هو عملية دمج عدة دوال لإنشاء دالة جديدة. في البرمجة الوظيفية المتقدمة، نستخدم التركيب من اليمين إلى اليسار (compose) ومن اليسار إلى اليمين (pipe).
// تركيب بسيط (من اليمين إلى اليسار)\nconst compose = (...fns) => (value) => fns.reduceRight((acc, fn) => fn(acc), value);\n\n// تركيب من اليسار إلى اليمين (pipe)\nconst pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value);\n\n// مثال: معالجة سلسلة نصية\nconst trim = (str) => str.trim();\nconst toLowerCase = (str) => str.toLowerCase();\nconst capitalize = (str) => str.charAt(0).toUpperCase() + str.slice(1);\nconst removeSpaces = (str) => str.replace(/\\s+/g, '-');\n\nconst slugify = compose(capitalize, toLowerCase, trim, removeSpaces);\n// المكافئ: removeSpaces(trim(toLowerCase(capitalize(" Hello World "))))\n\nconsole.log(slugify(' Hello World ')); // Hello-world\n\nالمحولات (Transducers)
\nالمحولات هي تركيب لدوال التحويل التي تعمل مع أي هياكل بيانات قابلة للتكرار. تسمح بدمج عدة عمليات (مثل map و filter) في مسار واحد.
const transducer = (mapper, predicate) => (reducer) => (acc, value) => {\n const mapped = mapper(value);\n return predicate(mapped) ? reducer(acc, mapped) : acc;\n};\n\nconst double = (x) => x * 2;\nconst isEven = (x) => x % 2 === 0;\n\nconst processNumbers = transducer(double, isEven);\nconst sumReduc