المسارات
/
Gleam
Gleam
/
المنهج
/
تحسين استدعاء الذيل
تح

تحسين استدعاء الذيل في Gleam

تمرينان

نبذة عن تحسين استدعاء الذيل

في كل مرة تُستدعى فيها دالة، يُنشأ إطار مكدس جديد في الذاكرة لتخزين وسائط الدالة ومتغيراتها المحلية، ويُلغى تخصيص هذا الإطار عند إرجاع الدالة. ولأن Gleam تستخدم استدعاءات الدوال العودية بدلًا من صيغة تكرار، فقد يؤدي ذلك إلى استخدام هذه الإطارات لكمية كبيرة من الذاكرة.

لتجنب هذه المشكلة، تدعم Gleam تحسين الاستدعاء الذيلّي، وهو يسمح للمصرّف بإعادة استخدام إطار مكدس الدالة الحالية إذا كان استدعاء دالة هو آخر ما تفعله الدالة. وهذا يعني أن الدالة يمكنها استدعاء نفسها عددًا لا نهائيًا من المرات دون استخدام أي ذاكرة إضافية.

يمكن غالبًا إعادة كتابة الدوال العودية غير المحسّنة على شكل دوال محسّنة بالاستدعاء الذيلّي باستخدام مُجمّع.

المُجمّع هو متغير يُمرَّر إلى جانب البيانات. ويُستخدم لتمرير الحالة الحالية لتنفيذ الدالة، إلى أن يتم الوصول إلى الحالة الأساسية.

ينبغي أن يهيّئ مؤلف الدالة المُجمّعات، لا مستخدم الدالة. ولتحقيق ذلك، عرّف دالتين: دالة عامة تأخذ البيانات الضرورية فقط كوسائط وتهيئ المُجمّع، ودالة خاصة تأخذ أيضًا مُجمّعًا.

// Count the length of a list without tail call optimisation
pub fn count(list: List(String)) -> Int {
  case list {
    [] -> 0
    [_, ..rest] -> {
      let amount = count(rest) // Non-tail recursive call
      amount + 1
    }
  }
}
// Count the length of a list with tail call optimisation
pub fn count(list: List(String)) -> Int {
  count_elements(list, 0)
}

fn count_elements(list: List(String), accumulator: Int) -> Int {
  case list {
    [] -> accumulator
    [_, ..rest] -> {
      let accumulator = accumulator + 1
      count_elements(rest, accumulator) // Tail recursive call
    }
  }
}
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة

تعلّم تحسين استدعاء الذيل

التدريب مقفل

افتح تمرينين إضافيين لممارسة تحسين استدعاء الذيل