آيكون (لغة برمجة)
المولدات

كثيرًا ما تعطي التعبيرات في لغة Icon قيمة واحدة، على سبيل المثال، x <5 ستُقيّم وتنجح مع القيمة 5 أو تفشل. ومع ذلك، يعتمد العديد من الأمثلة التالية على حقيقة أن هناك تعبيرات عديدة لا تعطي نتيجة بالنجاح أو الفشل فورًا، حيث تعطي قيمًا في أثناء ذلك. وهذا يسري على الأمثلة ذات الصيغ every and to؛ every causes to لتواصل إعطاء قيم حتى تفشل.
هذا مفهوم رئيسي في لغة Icon، يُعرف بـ المولدات. وتؤدي المولدات كثير من وظائف الحلقة في اللغة، لكنها تفعل الكثير مباشرة؛ لا يكتب المُبرمج أي حلقة ثم يقوم بسحب القيم ومقارنتها، لكن لغة Icon ستفعل كل هذا لك.
داخل طريقة تعبير لغة Icon، يؤدي تقييم أي تعبير أو دالة إلى تسلسل نتائج. ويحتوي تسلسل النتائج على كل القيم الممكنة التي يمكن توليدها بواسطة التعبير أو الدالة. وعندما ينتهي تسلسل النتائج (على سبيل المثال، لا يوجد مزيد من القيم داخل تسلسل النتائج)، يفشل التعبير أو الدالة. ويتحقق التكرار في تسلسل النتائج إما ضمنيًا عبر التقييم الموجه بالأهداف في Icon أو صراحة عبر العبارة every.
تشتمل لغة Icon على العديد من مُنشئات المولدات. وتسمح الصيغة alternator بتوليد سلسلة من العناصر في تسلسل حتى يفشل أحدها:
1 | "hello" | x <5
يمكنه توليد "1" و"hello" و"5" إذا كان x أقل من 5. على سبيل المثال، يمكن قراءة Alternators كـ "or" في حالات عديدة:
if y <(x | 5) then write("y=", y)
سيكتب قيمة y إذا كانت أصغر من x أو 5. وداخليًا تقوم لغة Icon بفحص كل قيمة من اليسار إلى اليمين حتى ينجح أحدها أو تفرغ القائمة وتفشل. وتذكر أنه لن تُطلب الدوال إلا إذا لم تفشل الطلبات بالداخل، ولذلك يمكن تقصير هذا المثال إلى:
write("y=", (x | 5)> y)
هناك مولد بسيط آخر وهو to، حيث يقوم بتوليد قوائم من الأعداد الصحيحة؛ وسيقوم every write(1 to 10) بعمل ما يبدو عليه تمامًا. وستقوم الصيغة bang بتوليد كل عنصر قائمة؛ وسيقوم every write(!aString) بإخراج كل رمز في سلسلة في سطر جديد.
لإيضاح قوة هذا المفهوم، انظر في عمليات السلاسل. وتشتمل معظم اللغات على دالة تُعرف بـ find أو indexOf والتي تعطي موقع سلسلة داخل أخرى. ادرس:
s = "All the world's a stage. And all the men and women merely players";
i = indexOf("the", s)
ستعطي هذه التعليمة البرمجية 4، موضع الحالة الأولى للكلمة "the". وللحصول على المثال التالي للكلمة "the" يجب استخدام شكل بديل،
i = indexOf("the", s, 5)
الرقم 5 في النهاية يقول أنه ينبغي أن يبدو من الموضع 5 وما بعده. ولاستخراج كل حالات كلمة "the"، يجب استخدام حلقة...
s = "All the world's a stage. And all the men and women merely players";
i = indexOf("the", s)
while i != -1 {
write(i);
i = indexOf("the", s, i+1);
}
في لغة Icon تمثل الدالة find مولدًا، وستعطي المثال التالي من السلسلة عند كل استئناف لها قبل أن تفشل في النهاية بعد تجاوزها نهاية السلسلة. ويمكن كتابة نفس التعليمة البرمجية في لغة Icon:
s := "All the world's a stage. And all the men and women merely players"
every write(find("the",s))
ستعطي الدالة find فهرس المثال التالي لكلمة "the" عند كل استئناف لها بواسطة العبارة every، حيث في النهاية تتجاوز نهاية السلسلة وتفشل. وكما في المثال السابق، سيؤدي هذا إلى فشل الكتابة، وخروج حلقة every (أحادية السطر).
هناك بالطبع أوقات تريد فيها عمدًا البحث عن سلسلة بعد نقطة ما في إدخال، على سبيل المثال، قد تكون تفحص ملفًا نصيًا يحتوي على بيانات في أعمدة متعددة. ويصلح التنفيذ الموجه بالأهداف هنا أيضًا، ويمكن استخدامه بهذه الطريقة:
write(5 <find("the", s))
سيظهر الموضع فقط إذا ظهرت كلمة "the" بعد الموضع 5، وإلا فستفشل المقارنة، ممررة ذلك الفشل إلى write() كما سبق. يوجد «حيلة» واحدة صغيرة لهذه التعليمة البرمجية والتي تحتاج لوضعها في الاعتبار: تعطي المقارنات النتيجة اليمنى، لذلك من المهم وضع find على الجانب الأيمن من المقارنة. وإذا كان الرقم 5 على اليمين، فسيُكتب الرقم 5.
تضيف لغة Icon العديد من هياكل التحكم للتكرار الحلقي خلال المولدات. وعامل every يشبه while، ويحدث التكرار الحلقي خلال كل عنصر بواسطة مولد ويخرج عند الفشل:
every k := i to j do
write(someFunction(k))
لماذا استخدام every بدلاً من حلقة while في هذه الحالة؟ لأن while تعيد تقييم النتيجة الأولى، لكن every تقدم كل النتائج. وتقوم صيغة every فعليًا بإدخال قيم في الدالة بطريقة تشبه الكتل في لغة Smalltalk. على سبيل المثال، يمكن إعادة كتابة الحلقة السابقة بهذه الطريقة:
every write(someFunction(i to j))
بإمكان المستخدمين إنشاء مولدات جديدة بسهولة باستخدام الكلمة الأساسية suspend:
procedure findOnlyOdd(pattern, theString)
every i := find(pattern, theString) do
if i % 2 = 1 then suspend i
end
هذا المثال يتحلق خلال theString باستخدام find للبحث عن pattern. وعند العثور على واحد، وكان الموضع غريبًا، تعطي الدالة الموقع مع suspend. وبخلاف return، يقوم suspend بكتابة أين يوجد في المولدات الداخلية أيضًا، ما يتيح له معرفة أين تُرك في التكرار التالي.