نمط المُراكِم
التحويل إلى استدعاء ذاتي ذي ذيل
نمط المُراكِم درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.
بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.
The Accumulator Pattern
The accumulator pattern converts a non-tail-recursive function into a tail-recursive one. You carry the partial result in an extra parameter (the accumulator) instead of building it up after the call returns.
The Core Idea
Instead of n + sum(n-1) (work after the call), you compute the new partial total before the call: sum(n-1, acc + n). Now the recursive call is the last action.
Before: Non-Tail Sum
This direct version is not tail-recursive: the addition waits for the recursive call.
object Main {
def sum(n: Int): Int =
if (n == 0) 0 else n + sum(n - 1)
def main(args: Array[String]): Unit = {
println(sum(50))
}
}After: Tail Sum with Accumulator
Add an acc parameter that holds the running total. The recursive call is now in tail position and can be optimized.
import scala.annotation.tailrec
object Main {
@tailrec
def sum(n: Int, acc: Int = 0): Int =
if (n == 0) acc else sum(n - 1, acc + n)
def main(args: Array[String]): Unit = {
println(sum(50))
}
}Tail-Recursive Factorial
Apply the same transformation to factorial: multiply into the accumulator before recursing.
import scala.annotation.tailrec
object Main {
@tailrec
def factorial(n: Int, acc: Long = 1): Long =
if (n <= 1) acc else factorial(n - 1, acc * n)
def main(args: Array[String]): Unit = {
println(factorial(10))
}
}Hiding the Accumulator
The extra parameter is an implementation detail. Wrap the tail-recursive worker in a clean public function so callers do not see acc.
import scala.annotation.tailrec
object Main {
def factorial(n: Int): Long = {
@tailrec
def loop(m: Int, acc: Long): Long =
if (m <= 1) acc else loop(m - 1, acc * m)
loop(n, 1)
}
def main(args: Array[String]): Unit = {
println(factorial(6))
}
}Accumulating a List
The pattern also builds collections. A tail-recursive reverse prepends each head to the accumulator list.
import scala.annotation.tailrec
object Main {
def reverse[A](xs: List[A]): List[A] = {
@tailrec
def loop(rem: List[A], acc: List[A]): List[A] = rem match {
case Nil => acc
case h :: t => loop(t, h :: acc)
}
loop(xs, Nil)
}
def main(args: Array[String]): Unit = {
println(reverse(List(1, 2, 3, 4)))
}
}Order of Accumulation
Note that prepending to the accumulator naturally reverses order. For a list-building function that preserves order, you often build reversed and reverse at the end, or use an efficient append structure.
Tail-Recursive map
Build a result list with an accumulator, then reverse once at the end to restore order.
import scala.annotation.tailrec
object Main {
def mapTail[A, B](xs: List[A])(f: A => B): List[B] = {
@tailrec
def loop(rem: List[A], acc: List[B]): List[B] = rem match {
case Nil => acc.reverse
case h :: t => loop(t, f(h) :: acc)
}
loop(xs, Nil)
}
def main(args: Array[String]): Unit = {
println(mapTail(List(1, 2, 3))(_ * 10))
}
}Relation to foldLeft
The accumulator pattern is exactly what foldLeft generalizes: it threads an accumulator through a collection tail-recursively. Many manual accumulator functions can be rewritten as a single foldLeft.
@main def run(): Unit = {
val total = List(1, 2, 3, 4).foldLeft(0)(_ + _)
println(total)
}When to Use It
Reach for the accumulator pattern when a recursive function processes a large linear structure and would otherwise overflow the stack. It trades a slightly less obvious shape for guaranteed stack safety.
Quick Check
Test your grasp of the accumulator pattern.
Recap
You learned the accumulator pattern:
- Carry the partial result in an extra parameter.
- Compute it before recursing to reach tail position.
- Hide the accumulator behind a clean public function.
- It generalizes to
foldLeft.
الأسئلة الشائعة
هل درس «نمط المُراكِم» مجاني؟
نعم — نص درس «نمط المُراكِم» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 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 منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «نمط المُراكِم»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟
نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.