البرمجة الوظيفية في Swift: من الألف إلى الياء
البرمجة الوظيفية (FP) هي نموذج برمجي ينظر إلى العمليات الحسابية على أنها حساب دوال رياضية ويتجنب تغيير الحالة والبيانات القابلة للتغيير. Swift، كونه لغة متعددة النماذج، يدعم الأسلوب الوظيفي بشكل ممتاز، خاصة في تطوير تطبيقات iOS و macOS. في هذه المقالة، سننتقل من المفاهيم الأساسية إلى التقنيات المتقدمة، مثل الـ monads وتركيب الدوال.
أساسيات المنهج الوظيفي في Swift
تقوم البرمجة الوظيفية على عدة مبادئ رئيسية:
- الدوال النقية — تعتمد النتيجة فقط على وسائط الإدخال، دون آثار جانبية.
- ثبات البيانات — استخدام
letبدلاً منvar. - الدوال ككائنات من الدرجة الأولى — يمكن تمريرها وإرجاعها وتخزينها.
لنلقِ نظرة على مثال بسيط لدالة نقية:
// دالة نقية: لا توجد آثار جانبيةfunc add(_ a: Int, _ b: Int) -> Int { return a + b}
// الاستخدامlet result = add(3, 5) // 8print(result)الإغلاقات والدوال عالية المستوى
الإغلاقات (closures) هي كتل وظيفية مكتفية بذاتها يمكن تمريرها واستخدامها في الكود. وهي أساس العمل مع الدوال عالية المستوى.
// إغلاق بسيطlet multiply = { (x: Int, y: Int) -> Int in return x * y}
let product = multiply(4, 7) // 28print(product)يوفر Swift دوالاً عالية المستوى قوية للعمل مع المجموعات:
map
map يطبق تحويلاً على كل عنصر من المصفوفة:
let numbers = [1, 2, 3, 4, 5]let squared = numbers.map { $0 * $0 }print(squared) // [1, 4, 9, 16, 25]filter
filter يختار العناصر التي تحقق الشرط:
let evenNumbers = numbers.filter { $0 % 2 == 0 }print(evenNumbers) // [2, 4]reduce
reduce يدمج جميع العناصر في قيمة واحدة:
let sum = numbers.reduce(0, +)print(sum) // 15تركيب الدوال والكاري (Currying)
التركيب يسمح بدمج الدوال البسيطة في دوال أكثر تعقيداً. لا يحتوي Swift على عامل تركيب مدمج، لكن من السهل تنفيذه:
// عامل التركيبprecedencegroup CompositionPrecedence { associativity: left higherThan: AssignmentPrecedence}
infix operator >>>: CompositionPrecedence
func >>> <A, B, C>(left: @escaping (A) -> B, right: @escaping (B) -> C) -> (A) -> C { return { right(left($0)) }}
// الاستخدامfunc double(_ x: Int) -> Int { x * 2 }func toString(_ x: Int) -> String { "\\(x)" }
let doubleThenString = double >>> toStringprint(doubleThenString(5)) // "10"الكاري (Currying) هو تحويل دالة تأخذ عدة وسائط إلى سلسلة من الدوال، كل منها يأخذ وسيطاً واحداً:
// دالة عاديةfunc add(_ a: Int, _ b: Int) -> Int { a + b }
// النسخة المُكَرَّاةfunc curriedAdd(_ a: Int) -> (Int) -> Int { return { b in a + b }}
let addFive = curriedAdd(5)print(addFive(3)) // 8الـ Monads والـ Functors في Swift
في البرمجة الوظيفية، الـ Functor هو نوع يمكن تعيينه (map). الـ Monad هو Functor مع عملية إضافية flatMap (أو >>=). المثال الأكثر شهرة في Swift هو Optional و Array.
Optional كـ Monad
let optionalValue: Int? = 5
// map — يطبق الدالة إذا كانت القيمة غير nillet doubled = optionalValue.map { $0 * 2 }print(doubled) // Optional(10)
// flatMap