أساسيات الاستدعاء الذاتي
دوال استدعائية ذاتيًا
أساسيات الاستدعاء الذاتي درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.
ما هو الاستدعاء الذاتي؟
الاستدعاء الذاتي هو أن تستدعي الدالة نفسها لحل نسخة أصغر من المشكلة نفسها. وهو ملائم بطبيعته للبرمجة الوظيفية، إذ يستبدل كثيرًا من الحلقات بتعريفات تستدعي نفسها.
جزآن أساسيان
تحتاج كل دالة استدعاء ذاتي صحيحة إلى:
- حالة أساس توقف الاستدعاء الذاتي.
- حالة استدعاء ذاتي تقترب من حالة الأساس.
من دون حالة أساس يمكن الوصول إليها، يستمر الاستدعاء الذاتي إلى ما لا نهاية.
المضروب
المثال الكلاسيكي هو: n! = n * (n-1)!، مع اعتبار 0! = 1 حالة الأساس.
object Main {
def factorial(n: Int): Int =
if (n <= 1) 1
else n * factorial(n - 1)
def main(args: Array[String]): Unit = {
println(factorial(5))
}
}تتبّع الاستدعاءات
يتوقف كل استدعاء ذاتي مؤقتًا وينتظر نتيجة الاستدعاء الداخلي. يتوسع factorial(3) إلى 3 * (2 * (1)). وتُجرى عمليات الضرب عند عودة الاستدعاءات.
object Main {
def factorial(n: Int): Int = {
println(s"entering factorial($n)")
if (n <= 1) 1 else n * factorial(n - 1)
}
def main(args: Array[String]): Unit = {
println("result = " + factorial(3))
}
}مجموع قائمة
الاستدعاء الذاتي على قائمة: المجموع هو الرأس مضافًا إليه مجموع الذيل، بينما يكون مجموع القائمة الفارغة صفرًا.
object Main {
def sum(xs: List[Int]): Int = xs match {
case Nil => 0
case h :: t => h + sum(t)
}
def main(args: Array[String]): Unit = {
println(sum(List(1, 2, 3, 4)))
}
}طول قائمة
يحسب النمط نفسه الطول: تكون القائمة الفارغة بطول 0، وإلا فالنتيجة هي 1 مضافًا إليها طول الذيل.
object Main {
def length[A](xs: List[A]): Int = xs match {
case Nil => 0
case _ :: t => 1 + length(t)
}
def main(args: Array[String]): Unit = {
println(length(List("a", "b", "c")))
}
}مكدس الاستدعاءات
يستخدم كل استدعاء ذاتي معلّق إطار مكدس. ويؤدي الاستدعاء الذاتي العميق إلى تكديس إطارات كثيرة. وبالنسبة إلى المدخلات الكبيرة جدًا، قد يستنفد ذلك المكدس ويطرح StackOverflowError.
فيبوناتشي
تتفرع بعض المسائل إلى استدعاءات ذاتية متعددة. تستدعي دالة فيبوناتشي نفسها مرتين، وهو أمر أنيق لكنه أُسّي من حيث التكلفة.
object Main {
def fib(n: Int): Int =
if (n < 2) n
else fib(n - 1) + fib(n - 2)
def main(args: Array[String]): Unit = {
println(fib(10))
}
}عكس قائمة
يمكن للاستدعاء الذاتي بناء هياكل جديدة: تضيف دالة العكس الرأس بعد عكس الذيل.
object Main {
def reverse[A](xs: List[A]): List[A] = xs match {
case Nil => Nil
case h :: t => reverse(t) :+ h
}
def main(args: Array[String]): Unit = {
println(reverse(List(1, 2, 3)))
}
}الاستدعاء الذاتي مقابل التكرار
تعدّل الحلقات عدّادًا، بينما يعبّر الاستدعاء الذاتي عن المشكلة بصورة تصريحية. وكلاهما صالح. يبرز الاستدعاء الذاتي في البيانات الشجرية وخوارزميات فرق تسد، لكن الاستدعاء الذاتي الساذج قد يؤدي إلى تجاوز المكدس عند التعامل مع مدخلات خطية كبيرة.
القاسم المشترك الأكبر
تُعد خوارزمية إقليدس مناسبة بطبيعتها للاستدعاء الذاتي، وتتقارب بسرعة.
object Main {
def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
def main(args: Array[String]): Unit = {
println(gcd(48, 18))
}
}تحقق سريع
اختبر أساسيات الاستدعاء الذاتي لديك.
مراجعة
لقد تعلمت أساسيات الاستدعاء الذاتي:
- تحتاج كل دالة استدعاء ذاتي إلى حالة أساس وحالة استدعاء ذاتي.
- يستخدم كل استدعاء معلّق إطار مكدس؛ وقد يؤدي الاستدعاء الذاتي العميق إلى تجاوز المكدس.
- يعبّر الاستدعاء الذاتي طبيعيًا عن خوارزميات القوائم والأشجار.
بعد ذلك، ستجعل الاستدعاء الذاتي آمنًا للمكدس باستخدام التعليمة التوضيحية @tailrec.
الأسئلة الشائعة
هل درس «أساسيات الاستدعاء الذاتي» مجاني؟
نعم — نص درس «أساسيات الاستدعاء الذاتي» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.
ماذا ستتعلم في «أساسيات الاستدعاء الذاتي»؟
دوال استدعائية ذاتيًا تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟
لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.
كم من الوقت يستغرق درس «أساسيات الاستدعاء الذاتي»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟
نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات الاستدعاء الذاتي
- التعليق التوضيحي tailrec
- نمط المُراكِم
- Trampolining