نفّذ عمليات المصفوفة الأساسية.
في اللغات الوظيفية، تُعدّ عمليات المصفوفات مثل length وmap وreduce شائعة جدًا.
نفّذ سلسلة من عمليات المصفوفة الأساسية، دون استخدام دوال موجودة.
يعتمد العدد الدقيق للعمليات المطلوب تنفيذها وأسماؤها على المسار، لتجنّب التعارض مع الأسماء الموجودة، لكن العمليات العامة التي ستنفّذها تشمل:
append (بإعطاء مصفوفتين، أضِف كل عناصر المصفوفة الثانية إلى نهاية المصفوفة الأولى)؛concatenate (بإعطاء سلسلة من المصفوفات، ادمج كل عناصر المصفوفات كلها في مصفوفة واحدة مسطّحة)؛filter (بإعطاء دالة شرطية ومصفوفة، أرجِع المصفوفة التي تضم كل العناصر التي يكون عندها predicate(item) صحيحًا)؛length (بإعطاء مصفوفة، أرجِع العدد الإجمالي للعناصر داخلها)؛map (بإعطاء دالة ومصفوفة، أرجِع مصفوفة نتائج تطبيق function(item) على كل العناصر)؛foldl (بإعطاء دالة ومصفوفة وقيمة مراكم ابتدائية، اطوِ (اختزل) كل عنصر في المراكم من اليسار)؛foldr (بإعطاء دالة ومصفوفة وقيمة مراكم ابتدائية، اطوِ (اختزل) كل عنصر في المراكم من اليمين)؛reverse (بإعطاء مصفوفة، أرجِع مصفوفة تضم كل العناصر الأصلية، لكن بترتيب معكوس).لاحظ أن ترتيب تمرير الوسائط إلى دالتي الطيّ (foldl وfoldr) مهم.
ستحتاج في هذا التمرين إلى استخدام تعدد أشكال المعاملات في أودن (ويُشيع تسميته الأنواع العامة). وإن لم تكن قد رأيت هذه الميزة من قبل، فإليك شرحًا سريعًا يضعك على الطريق.
تعدد أشكال المعاملات ميزة في لغات البرمجة تسمح للمبرمجين بأن يكونوا أقل تحديدًا (وأكثر عمومية، ومن هنا جاء الاسم) بشأن الأنواع المستخدمة في الكود مع الحفاظ على أمان الأنواع. ومن الواضح أن هذا لا معنى له إلا في اللغات قوية الأنماط مثل أودن.
لنبدأ بمثال. لنفترض أنك تريد زيادة جميع عناصر مصفوفة بمقدار ثابت، وهي مسألة بسيطة بما يكفي.
incr_array_int :: proc(a: []int, by: int) -> []int {
new_array := make([]int, len(a))
for i := 0; i < len(a); i+= 1 {
new_array[i] = a[i] + by
}
return new_array
}
وماذا لو احتجت الآن الوظيفية نفسها لأعداد الفاصلة العائمة؟
incr_array_f64 :: proc(a: []f64, by: f64) -> []f64 {
new_array := make([]f64, len(a))
for i := 0; i < len(a); i+= 1 {
new_array[i] = a[i] + by
}
return new_array
}
ثم للأعداد الصحيحة بدون إشارة، وأعداد الفاصلة العائمة ذات 32 بت، وهكذا؟
وقبل أن تمضي فترة طويلة تجد نفسك أمام عدد كبير من الإجراءات التي تؤدي الوظيفة نفسها تمامًا لكن على نوع مختلف. وإذا احتجت يومًا إلى تحديث المنطق، فعليك أن تتأكد من تنفيذ ذلك في جميع الصيغ، وقد يتحول ذلك إلى قدر كبير من أعمال الصيانة. ومن المزعجات الأخرى أنك تحتاج إلى إعطاء كل إجراء اسمًا مختلفًا، لأن أودن لا يدعم التحميل الزائد الضمني للإجراءات (لا يزال بإمكانك استخدام التحميل الزائد الصريح، لكن تلك حكاية لتمرين آخر).
ولأن أودن لغة عملية، فإنه يقدم حلًا عبر تعدد أشكال المعاملات.
طالما استطاع المصرّف تحديد نوع المعامل في وقت التصريف، فيمكنك إعطاؤه اسمًا عامًا مثل T.
لنُعِد كتابة الإجراء أعلاه:
incr_array :: proc(a: []$T, by: T) -> []T {
new_array := make([]T, len(a))
for i := 0; i < len(a); i+= 1 {
new_array[i] = a[i] + by
}
return new_array
}
لاحظ أننا استبدلنا جميع إشارات الأنواع (int أو f64) بـ T، وأن أول ظهور لـ T تسبقه علامة الدولار ($T).
يخبر النوع $T مصرّف أودن بأن الاسم T اسم عام للنوع، سيُستبدل بالاسم الفعلي أثناء التصريف.
وبما أن المصرّف يعرف الآن النوع العام T، فلا حاجة بعد ذلك إلى تعليم بقية المواضع التي يظهر فيها النوع نفسه إلا باسم النوع المختار (T).
يمكنك الآن كتابة كود مثل:
a_int := incr_array([]int{1, 2, 3}, 10)
a_f64 := incr_array([]f64{1.0, 2.0, 3.0}, 10.0)
في العبارة الأولى، سيحدد مصرّف أودن نوع المعامل الأول ([]int) مع نوع المعامل العام ([]$T)، ويستنتج أن T = int، ثم يشرع في تصريف نسخة تُستبدل فيها كل المواضع التالية لـ T بـ int (وهي مكافئة للنسخة المتخصصة incr_array_int() أعلاه).
ولو حذفت علامة الدولار في تعريف المعامل الأول، لبحث المصرّف في الحزمة الحالية وقائمة الاستيرادات عن نوع اسمه T، والأرجح أنه كان سيرجع خطأ تصريف Error: Undeclared name: T.
أما العبارة الثانية فتعمل تمامًا مثل الأولى، لكن مع تحديد المصرّف T على أنها f64.
ومن المعتاد إعطاء الأنواع العامة أسماء من حرف واحد (غالبًا ما يُستخدم T وE).
أصبحت الآن تعرف ما يكفي عن تعدد أشكال المعاملات، أي الأنواع العامة، للتعامل مع تمرين عمليات القوائم.
سجّل في Exercism لتتعلّم وتتقن Odin عبر 73 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.
استمتع بمقدمة عملية إلى الاستدعاء الذاتي، واستكشف البدائل الأمرية والوظيفية لتمرين عمليات القوائم، وتعمّق في الاستدعاء الذاتي الذيلية ودوال المراكم.