ماهي الحلقات؟


نستخدم الحلقات ( Loops ) بهدف تكرار نفس الكود عدة مرات. إذاً أي كود نريده أن يتنفذ عدة مرات، نقوم بكتابته داخل حلقة فتقوم هي بإعادة تنفيذ الكود قدر ما شئنا ضمن شروط معينة نقوم نحن بتحديدها.
عندما تتنفذ الحلقة فإن الأوامر الموضوعة فيها تنفذ بشكل منفصل عن باقي الأوامر الموجودة في البرنامج، أي يمكنك إعتبار أن جميع أوامر الحلقة توضع في مكان خاص في الذاكرة، هذا المكان يسمى مجال (scope). بعد أن تتنفذ جميع أوامر الحلقة في هذا الـمجال, يتم مسح الـمجال كلياً من الذاكرة.

لكل (for)


تستخدم الحلقة `لكل` (for) غالباً في حال كان عدد المرات التي سيعاد فيها تنفيذ الكود معروفاً. ولها الشكل التالي في لغة الأسس:


لكل تهيئة، شرط، تحديث {
  جمل
}
for initialization, condition, update {
  statements
}

يتم تنفيذ خطوة التهيئة (initialization) أولاً، ومرة واحدة فقط. تتيح لك هذه الخطوة تهيئة المتغيرات التحكم بالحلقة.
بعد ذلك ، يتم تقييم الشرط (condition). إذا كان هذا صحيحًا (محققًا)، فسيتم تنفيذ متن الحلقة (أي الـمجال (scope) وهذا يشمل كل ماهو موجود ضمن القوسين الحاصرين {جمل}). أما إذا كان الشرط غير محقق، فلن يتم تنفيذ جسم الحلقة وسيقفز تدفق التحكم إلى العبارة التالية بعد حلقة "for" مباشرةً.
بعد تنفيذ جسم الحلقة، ينتقل تدفق التحكم إلى تعليمة التحديث update. تسمح لك هذه العبارة بتحديث أي متغيرات تحكم في الحلقة.
يتم بعدها تقييم الشرط مرة أخرى. إذا كان هذا محققاً، فسيتم تنفيذ الحلقة وتكرر العملية نفسها (جسم الحلقة ، ثم خطوة الزيادة ، ثم الشرط مرة أخرى). عندما يصبح الشرط غير محقق، تنتهي الحلقة.

مثال:

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف ع: صحيح؛
لكل ع = 2، ع < 11، ع = ع + 1 {
  اطبع("قيمة ع: %d\ج"، ع)؛
}
/*
قيمة ع: 2
قيمة ع: 3
قيمة ع: 4
قيمة ع: 5
قيمة ع: 6
قيمة ع: 7
قيمة ع: 8
قيمة ع: 9
قيمة ع: 10
*/
import "Srl/Console.alusus";
use Srl.Console;
def i:int;
for i = 2, i < 11, i = i+1 {
  print("value of i: %d\n", i);
}
/*
value of i: 2
value of i: 3
value of i: 4
value of i: 5
value of i: 6
value of i: 7
value of i: 8
value of i: 9
value of i: 10
*/

بينما (While)


يمكنك استخدامها في أي حالة، لكن غالباً ما تستخدم الحلقة while في حال كان عدد المرات التي سيعاد فيها تنفيذ الكود (أو بشكل أدق الـمجال) غير معروف. ولها الشكل التالي:

بينما شرط {
  جمل
}
while condition {
  statements
}

وهنا نقوم بخطوة التهيئة init لعنصر التحكم بالشرط قبل أن يتم تنفيذ الحلقة، ويجب أن يتضمن متن الحلقة تحديثًا لقيمة متغيرات الشرط لكي لاندخل في حلقة لانهائية.

مثال:
نفس الكود السابق-طباعة الأرقام من 2 ل 10- لكن باستخدام حلقة بينما .

  اشمل "مـتم/طـرفية"؛
  استخدم مـتم.طـرفية؛
  عرف ع: صحيح = 2؛ // لابد من تهيئة عنصر التحكم هنا خارج متن الحلقة
  بينما ع < 11 {
    اطبع("قيمة ع: %d\ج"، ع)؛
    ع = ع + 1؛ // أيضاً لابد من تحديث قيمة عنصر التحكم وإلا سندخل في حلقة لانهائية
  }
import "Srl/Console.alusus";
use Srl.Console;
def i:int=2; // لابد من تهيئة عنصر التحكم هنا خارج متن الحلقة
while(i<11) {
  print("value of i: %d\n", i);
  i=i+1; // أيضاً لابد من تحديث قيمة عنصر التحكم وإلا سندخل في حلقة لانهائية
}

أوامر التحكم بالحلقات: اقطع (break) وأكمل (continue)


هي أوامر للتحكم بسير عمل الحلقات.

اقطع (break)
بمجرد ان تنفذ الأمر `اقطع` (break) فإنها توقف تنفيذ الـمجال (scope) بأكمله و تخرج منه و تمسحه من الذاكرة ثم تنتقل للكود الذي يليه في البرنامج. ويمكن استخدامها مع جميع أنواع الحلقات.
فعلى سبيل المثال في الكود السابق لو أردنا أن يتوقف تنفيذ الحلقة (الخروج من الحلقة) عندما نصل للرقم 7 نقوم باستخدام هذه التعليمة كالتالي:

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف ع: صحيح؛
لكل ع = 2، ع < 11، ع = ع+1 {
  إذا ع == 7 اقطع؛
  اطبع("قيمة ع: %d\ج"، ع)؛
}

/*
قيمة ع: 2
قيمة ع: 3
قيمة ع: 4
قيمة ع: 5
قيمة ع: 6
*/
import "Srl/Console.alusus";
use Srl.Console;
def i:int;
for i = 2, i < 11, i = i+1 {
  if i==7  break;
  print("value of i: %d\n", i);
}

/*
value of i: 2
value of i: 3
value of i: 4
value of i: 5
value of i: 6
*/

لاحظ أنه لم تتم طباعة باقي الأرقام لأنه عندما وصل ل 7 تحقق الشرط وتم تنفيذ الأمر اقطع.

أكمل (continue)
نستخدمها لتجاوز تنفيذ حالة معينة في الحلقة، أي نستخدمها لتجاوز جزء من كود الـمجال. فعلى سبيل المثال في الكود السابق لو أردنا أن لاتتم طباعة العدد 7:

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف ع: صحيح؛
لكل ع = 2، ع < 11، ع = ع+1 {
  إذا ع == 7 أكمل؛
  اطبع("قيمة ع: %d\ج"، ع)؛
}

/*
قيمة ع: 2
قيمة ع: 3
قيمة ع: 4
قيمة ع: 5
قيمة ع: 6
قيمة ع: 8
قيمة ع: 9
قيمة ع: 10
*/
import "Srl/Console.alusus";
use Srl.Console;
def i:int;
for i = 2, i < 11, i = i+1 {
  if i==7  continue;
  print("value of i: %d\n", i);
}

/*
value of i: 2
value of i: 3
value of i: 4
value of i: 5
value of i: 6
value of i: 8
value of i: 9
value of i: 10
*/

لاحظ أنه لم تتم طباعة الرقم 7 لأنه عندما وصل ل 7 تحقق الشرط وتم تنفيذ الأمر continue فقام المترجم بتجاهل باقي تعليمات الـمجال والعودة إلى بداية الحلقة من جديد.

ملاحظة: أمري اقطع (break) و أكمل (continue) في لغة الأسس يسمحان للمستخدم بتحديد عدد الحلقات المراد الخروج منها. على سبيل المثال لوكان لديك حلقتين متداخلتين، و تريد أن يتم الخروج من الحلقة الداخلية والخارجية عند تحقق شرط محدد، فسيكون من الأسهل استخدام هذه الفكرة. لاحظ المثال التالي:
هنا سنقوم بالخروج من الحلقة الداخلية فقط عند تحقق الشرط i==4، وبالتالي لن تتم طباعة 0 ,1.

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف س: صحيح؛
عرف ص: صحيح؛
لكل س = 0، س < 6، ++س {
  لكل ص = 0، ص < 2، ++ص {
    إذا س == 4 {
      اطبع("تجاوز\ج")؛
      اقطع؛
    }
    اطبع("%d\ج"، ص)؛
  }
  اطبع("**************\ج")؛
}

/*
0
1
**************
0
1
**************
0
1
**************
0
1
**************
تجاوز
**************
0
1
**************
*/
import "Srl/Console.alusus";
use Srl.Console;
def i:int;
def j:int;
for i = 0, i < 6, ++i {
  for j = 0, j < 2, ++j {
    if i == 4 {
      print("Skip it\n")
      break;
    }
    print("%d\n",j);
  }
  print("**************\n")
}

/*
0
1
**************
0
1
**************
0
1
**************
0
1
**************
Skip it
**************
0
1
**************
*/

الآن سنعدل على المثال السابق بحيث يتم الخروج من الحلقتين عند تحقق الشرط السابق.

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف س: صحيح؛
عرف ص: صحيح؛
لكل س = 0، س < 6، ++س {
  لكل ص = 0، ص < 2، ++ص {
    // هذه المرة سيتم الخروج من الحلقتين الداخلية والخارجية.
    إذا س == 4 {
      اطبع("تجاوز\ج")؛
      اقطع 2؛ // حددنا عدد الحلقات المُراد الخروج منها بحلقتين
    }
    اطبع("%d\ج"، ص)؛
  }
  اطبع("**************\ج")؛
}

/*
0
1
**************
0
1
**************
0
1
**************
0
1
**************
تجاوز
*/
import "Srl/Console.alusus";
use Srl.Console;
def i:int;
def j:int;
for i = 0, i < 6, ++i {
  for j = 0, j < 2, ++j {
    // هذه المرة سيتم الخروج من الحلقتين الداخلية والخارجية.
    if i == 4 {
      print("Skip it\n")
      break 2; // حددنا عدد الحلقات المُراد الخروج منها بحلقتين
    }
    print("%d\n",j);
  }
  print("**************\n")
}

/*
0
1
**************
0
1
**************
0
1
**************
0
1
**************
Skip it
*/

نفس الفكرة بالنسبة للأمر `أكمل`، هنا سنقوم بتجاهل التعليمات المتبقية ضمن مجال الحلقة الداخلية وندخل في تكرار جديد عند تحقق الشرط j==1.

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف س: صحيح؛
عرف ص: صحيح؛
لكل س = 0، س < 6، ++س {
  لكل ص = 0، ص < 3، ++ص {
    إذا ص == 1 {
      اطبع("تجاوز\ج")؛
      أكمل؛
    }
    اطبع("%d\ج"، ص)؛
  }
  اطبع("**************\ج")؛
}

/*
0
تجاوز
2
**************
0
تجاوز
2
**************
0
تجاوز
2
**************
0
تجاوز
2
**************
0
تجاوز
2
**************
0
تجاوز
2
**************
*/
import "Srl/Console.alusus";
use Srl.Console;
def i:int;
def j:int;
for i = 0, i < 6, ++i{
  for j = 0, j < 3, ++j{
    if j == 1 {
      print("Skip it\n")
      continue;
    }
    print("%d\n",j);
  }
  print("**************\n")
}

/*
0
Skip it
2
**************
0
Skip it
2
**************
0
Skip it
2
**************
0
Skip it
2
**************
0
Skip it
2
**************
0
Skip it
2
**************
*/

الآن سنعدل على الكود السابق، بحيث نقوم باستخدام `أكمل` للانتقال إلى التكرار التالي في الحلقة الخارجية:

اشمل "مـتم/طـرفية"؛
استخدم مـتم.طـرفية؛
عرف س: صحيح؛
عرف ص: صحيح؛
لكل س = 0، س < 6، ++س {
  لكل ص = 0، ص < 3، ++ص {
    إذا ص == 1 {
      اطبع("تجاوز\ج")؛
      أكمل 2؛
    }
    اطبع("%d\ج"، ص)؛
  }
  اطبع("**************\ج")؛
}

/*
0
تجاوز
0
تجاوز
0
تجاوز
0
تجاوز
0
تجاوز
0
تجاوز
*/
import "Srl/Console.alusus";
use Srl.Console;
use Srl;
def i:int;
def j:int;
for i = 0, i < 6, ++i{
  for j = 0, j < 3, ++j{
    if j==1 {
      print("Skip it\n")
      continue 2;
    }
    print("%d\n",j);
  }
  print("**************\n")
}

/*
0
Skip it
0
Skip it
0
Skip it
0
Skip it
0
Skip it
0
Skip it
*/