أيقونة (لغة برمجة)

لغة البرمجة Icon هي لغة برمجة عالية المستوى تعتمد على مفهوم "التنفيذ الموجه نحو الهدف"، حيث تُرجع كل عبارة برمجية "نجاحًا" مع نتيجة، أو "فشلًا" للدلالة على عدم وجود نتيجة صحيحة. يُستخدم نجاح أو فشل العبارة لتوجيه المعالجة اللاحقة، بينما تستخدم اللغات التقليدية عادةً منطقًا منطقيًا ثنائيًا (Boolean) يكتبه المبرمج لتحقيق نفس الغاية. ولأن منطق هياكل التحكم الأساسية غالبًا ما يكون ضمنيًا في Icon، يُمكن إنجاز المهام الشائعة باستخدام شفرة برمجية أقل وضوحًا.

صُممت لغة Icon على يد رالف غريسولد بعد مغادرته مختبرات بيل ، حيث كان مساهمًا رئيسيًا في لغة SNOBOL . كانت SNOBOL لغة لمعالجة النصوص، ذات بنية تُعتبر قديمة وفقًا لمعايير أوائل سبعينيات القرن العشرين. بعد انتقاله إلى جامعة أريزونا ، واصل غريسولد تطوير مفاهيم SNOBOL الأساسية في SL5، لكنه اعتبر النتيجة غير ناجحة. أدى ذلك إلى تطوير Icon المُحدثة بشكل كبير، والتي تمزج بين الشيفرة القصيرة والغنية بالمفاهيم للغات الشبيهة بـ SNOBOL، والبنية الأكثر شيوعًا للغات المستوحاة من ALGOL مثل C أو Pascal .

على غرار اللغات التي استُلهمت منها، يُستخدم Icon بشكل أساسي في إدارة السلاسل النصية والأنماط النصية. غالبًا ما تفشل عمليات السلاسل النصية، على سبيل المثال، عند البحث عن "the" في كلمة "world". في معظم اللغات، يتطلب هذا الأمر اختبارًا وتفرعًا لتجنب استخدام نتيجة غير صالحة. في Icon، لا حاجة لمعظم هذه الاختبارات، مما يقلل من حجم التعليمات البرمجية المطلوبة. يمكن معالجة الأنماط المعقدة ببضعة أسطر من التعليمات البرمجية المختصرة، على غرار لغات أكثر تخصصًا مثل Perl ، ولكن مع الحفاظ على بنية نحوية وظيفية مألوفة لمستخدمي لغات أخرى شبيهة بلغة ALGOL.

لا تُعتبر لغة Icon لغة كائنية التوجه ، ولكن تم تطوير امتداد كائني التوجه يُدعى Idol في عام 1996، والذي أصبح فيما بعد Unicon . وقد ألهمت هذه اللغة لغات أخرى، لا سيما مولداتها البسيطة التي كان لها تأثير كبير؛ فقد كانت مولدات Icon مصدر إلهام رئيسي للغة Python . [ 3 ]

تاريخ

سنوبول

انطلق مشروع SNOBOL الأصلي ، المعروف لاحقًا باسم SNOBOL1، في خريف عام 1962 في قسم دراسات أبحاث البرمجة بمختبرات بيل . [ 4 ] جاء هذا المشروع كرد فعل على الإحباطات التي واجهها الباحثون عند محاولتهم استخدام لغة SCL لمعالجة الصيغ متعددة الحدود، والتكامل الرمزي، ودراسة سلاسل ماركوف . كانت لغة SCL، التي كتبها رئيس القسم تشيستر لي، بطيئة وذات بنية منخفضة المستوى، مما أدى إلى تراكم كميات هائلة من التعليمات البرمجية حتى في المشاريع البسيطة. بعد دراسة لغة COMIT لفترة وجيزة، قرر إيفان بولونسكي، ورالف غريسولد، وديفيد فاربر، وجميعهم أعضاء في القسم المكون من ستة أشخاص، كتابة لغتهم الخاصة لحل هذه المشكلات. [ 5 ]

بدأت الإصدارات الأولى بالعمل على جهاز IBM 7090 في أوائل عام 1963، وبحلول الصيف، تم تطويرها واستخدامها على نطاق واسع في شركة بيل. أدى ذلك مباشرةً إلى ظهور SNOBOL2، التي أضافت عددًا من الوظائف المدمجة، وإمكانية الربط بشفرة لغة التجميع الخارجية . صدرت هذه النسخة في أبريل 1964، واستُخدمت بشكل رئيسي داخل شركة بيل، ولكنها استُخدمت أيضًا في مشروع MAC . كان إدخال وظائف النظام بمثابة إشارة إلى الحاجة إلى وظائف مُعرَّفة من قِبل المستخدم، والتي كانت السمة الرئيسية لـ SNOBOL3، التي صدرت في يوليو 1964. [ 6 ]

تزامن إطلاق SNOBOL3 مع تغييرات جوهرية في قسم الحوسبة بمختبرات بيل، بما في ذلك إضافة الحاسوب المركزي الجديد GE 645 الذي كان سيتطلب إعادة كتابة SNOBOL. بدلاً من ذلك، اقترح الفريق كتابة نسخة جديدة تعمل على آلة افتراضية ، سُميت SIL اختصارًا لـ SNOBOL Intermediate Language (لغة SNOBOL الوسيطة)، مما يسمح بنقلها بسهولة إلى أي منصة قوية بما يكفي. قُبل هذا الاقتراح تحت اسم SNOBOL4 في سبتمبر 1965. وبحلول ذلك الوقت، ظهرت خطط لإصدار نسخة محسّنة بشكل ملحوظ من اللغة في أغسطس 1966. [ 7 ] استمر العمل على اللغة طوال ما تبقى من ستينيات القرن العشرين، ولا سيما إضافة نوع المصفوفة الترابطية في إصدار لاحق، والذي أطلقوا عليه اسم "الجدول".

يؤدي SL5 إلى أيقونة

غادر غريسولد مختبرات بيل ليصبح أستاذاً في جامعة أريزونا في أغسطس 1971. [ 8 ] وقدّم برنامج SNOBOL4 كأداة بحثية في ذلك الوقت. [ 9 ] وحصل على منح من المؤسسة الوطنية للعلوم لمواصلة دعم وتطوير برنامج SNOBOL. [ 10 ]

باعتبارها لغة طُوّرت في أوائل الستينيات، تحمل بنية لغة سنوبول سمات لغات برمجة مبكرة أخرى مثل فورتران وكوبول . وعلى وجه الخصوص، تعتمد اللغة على الأعمدة، حيث كانت العديد من هذه اللغات تُدخل باستخدام بطاقات مثقبة يكون فيها تخطيط الأعمدة طبيعيًا. بالإضافة إلى ذلك، كانت هياكل التحكم تعتمد بشكل شبه كامل على التفرع حول التعليمات البرمجية بدلاً من استخدام الكتل ، التي أصبحت ميزة أساسية بعد ظهور لغة ألغول 60. وبحلول الوقت الذي انتقل فيه إلى أريزونا، كانت بنية سنوبول 4 قديمة للغاية. [ 11 ]

بدأ غريسولد جهوده لتطبيق مفهوم النجاح/الفشل الأساسي في لغة سنوبول باستخدام هياكل التحكم التقليدية في التدفق مثل if/then. أصبح هذا SL5، اختصارًا لـ "SNOBOL Language 5"، لكن النتيجة لم تكن مُرضية. [ 11 ] في عام 1977، عاد إلى اللغة للنظر في إصدار جديد. تخلى عن نظام الدوال القوي للغاية الذي تم تقديمه في SL5، واستبدله بمفهوم أبسط للتعليق/الاستئناف، وطوّر مفهومًا جديدًا للغة التي ستخلف SNOBOL4 بشكل طبيعي، وذلك وفقًا للمبادئ التالية؛ [ 11 ]

  • الأساس الفلسفي والدلالي للعبة SNOBOL4
  • الأساس النحوي SL5
  • ميزات SL5، باستثناء آلية الإجراء العامة

كانت اللغة الجديدة تُعرف في البداية باسم SNOBOL5، ولكن نظرًا لاختلافها الكبير عن SNOBOL في كل شيء عدا المفهوم الأساسي، فقد رُغب في اختيار اسم جديد. بعد التفكير في استخدام "s" كنوع من التكريم للغة "C"، تم التخلي عن هذا الاقتراح في النهاية بسبب مشاكل طباعة المستندات التي تستخدم هذا الاسم. تم اقتراح سلسلة من الأسماء الجديدة ثم التخلي عنها؛ مثل Irving وbard و"TL" اختصارًا لـ "The Language" (اللغة). في ذلك الوقت، بدأ مركز أبحاث زيروكس بارك (Xerox PARC) بنشر معلومات حول عمله على واجهات المستخدم الرسومية، وبدأ مصطلح "icon" (أيقونة) بالدخول إلى قاموس الحاسوب. تم اتخاذ قرار بتغيير الاسم مبدئيًا إلى "icon" قبل اختيار "Icon" (أيقونة) في النهاية. [ 11 ] [ أ ]

لغة

بناء الجملة الأساسي

لغة Icon مشتقة من فئة ALGOL من لغات البرمجة الهيكلية ، وبالتالي فإن تركيبها النحوي مشابه للغة C أو باسكال . تُعدّ Icon الأقرب إلى باسكال، حيث تستخدم :=تركيبًا نحويًا للتعيينات، والكلمة procedureالمفتاحية، وتركيبًا نحويًا مشابهًا. من ناحية أخرى، تستخدم Icon أقواسًا على غرار لغة C لهيكلة مجموعات التنفيذ، وتبدأ البرامج بتشغيل إجراء يُسمى main. [ 13 ]

تتشابه لغة Icon في العديد من الخصائص مع معظم لغات البرمجة النصية (وكذلك لغتي SNOBOL وSL5 اللتين استُمدت منهما): فلا حاجة لتعريف المتغيرات، ويتم تحويل الأنواع تلقائيًا، ويمكن تحويل الأرقام إلى سلاسل نصية والعكس تلقائيًا. [ 14 ] ومن الخصائص الأخرى الشائعة في العديد من لغات البرمجة النصية، ولكن ليس جميعها، غياب رمز إنهاء السطر؛ ففي لغة Icon، تُنهى الأسطر التي لا تنتهي بفاصلة منقوطة بفاصلة منقوطة ضمنيًا إذا كان ذلك منطقيًا. [ 15 ]

تُعدّ الإجراءات اللبنات الأساسية لبرامج Icon. على الرغم من استخدامها لتسمية Pascal، إلا أنها تعمل بشكل أشبه بدوال C ويمكنها إرجاع قيم؛ ولا توجد functionكلمة مفتاحية في Icon. [ 16 ]

الإجراء doSomething ( aString ) write ( aString ) end

التنفيذ الموجه نحو تحقيق الأهداف

كان أحد المفاهيم الأساسية في لغة سنوبول هو أن دوالها تُرجع قيمتي "النجاح" أو "الفشل" كقيم أساسية للغة بدلاً من استخدام الأرقام السحرية أو غيرها من التقنيات. [ 17 ] [ 18 ]

على سبيل المثال، تُعدّ الدالة التي تُعيد موضع سلسلة فرعية داخل سلسلة أخرى إجراءً شائعًا في معظم أنظمة تشغيل اللغات . في جافا سكريبت، يُمكن إيجاد موضع كلمة "World" داخل برنامج "Hello, World!" باستخدام الدالة `return` ، والتي تُعيد القيمة 7 في المتغير `<string> `. أما إذا طُلب من المستخدم إيجاد موضع كلمة "World" داخل سلسلة أخرى، فسيفشل البرنامج، لأن مصطلح البحث غير موجود في السلسلة. في جافا سكريبت، كما هو الحال في معظم اللغات، يُشار إلى ذلك بإرجاع قيمة سحرية، وهي -1 في هذه الحالة. [ 19 ]position="Hello, World".indexOf("World")positionposition="Hello, World".indexOf("Goodbye")

في لغة SNOBOL، يُرجع هذا النوع من الفشل قيمة خاصة &fail. تعتمد صيغة SNOBOL مباشرةً على نجاح العملية أو فشلها، حيث تنتقل إلى أقسام محددة من الكود دون الحاجة إلى كتابة اختبار منفصل. على سبيل المثال، يطبع الكود التالي عبارة "Hello, world!" خمس مرات: [ 20 ]

* برنامج سنوبول لطباعة "Hello World" I = 1 LOOP OUTPUT = "Hello, world!" I = I + 1 LE ( I , 5 ) : S ( LOOP ) END

لتنفيذ الحلقة، يتم استدعاء عامل المقارنة "أصغر من أو يساوي" LEعلى متغير الفهرس I، وإذا Sنجح، أي أن I أقل من 5، فإنه ينتقل إلى التسمية المسماة LOOPويستمر. [ 20 ]

حافظت لغة Icon على مفهوم التحكم في التدفق بناءً على النجاح أو الفشل، لكنها طورتها بشكل أكبر. تمثل أحد التغييرات في استبدال GOTOالتفرعات المُصنّفة بهياكل مُوجّهة نحو الكتل، تماشيًا مع أسلوب البرمجة الهيكلية الذي اجتاح صناعة الحوسبة في أواخر الستينيات. [ 11 ] أما التغيير الثاني، فكان السماح بتمرير "الفشل" عبر سلسلة الاستدعاءات، بحيث تنجح أو تفشل الكتل بأكملها. يُعد هذا مفهومًا أساسيًا في لغة Icon. فبينما يتطلب الأمر في اللغات التقليدية تضمين شيفرة لاختبار النجاح أو الفشل بناءً على المنطق البولياني ، ثم التفرع بناءً على النتيجة، فإن هذه الاختبارات والتفرعات مُتأصلة في شيفرة Icon ولا تتطلب كتابة صريحة. [ 21 ]

على سبيل المثال، لنفترض هذا الجزء من الكود المكتوب بلغة جافا . يستدعي هذا الكود read()الدالة لقراءة حرف من ملف (مفتوح مسبقًا)، ثم يُسند النتيجة إلى المتغير a، ثم writeيُنسخ قيمة المتغير aإلى ملف آخر. والنتيجة هي نسخ ملف إلى آخر. readستنفد الدالة في النهاية من الأحرف المتاحة للقراءة من الملف، ربما في أول استدعاء لها، مما سيجعل المتغير aفي حالة غير محددة، وقد يتسبب writeفي حدوث استثناء مؤشر فارغ . لتجنب ذلك، readتُعيد الدالة القيمة الخاصة EOF(نهاية الملف) في هذه الحالة، الأمر الذي يتطلب اختبارًا صريحًا لتجنب writeحدوث هذا الاستثناء.

بينما (( a = read ()) != EOF ) { اكتب ( a ); }

على النقيض من ذلك، في لغة Icon، read()تُرجع الدالة سطرًا نصيًا أو &failلا &failتُعتبر مجرد نظير لـ EOF، إذ يُفهم صراحةً في اللغة أنها تعني "إيقاف المعالجة" أو "تنفيذ حالة الفشل" حسب السياق. الكود المكافئ في Icon هو: [ 18 ]

بينما a := read () do write ( a )

هذا يعني: "طالما أن عملية القراءة ناجحة، يتم استدعاء عملية الكتابة، وإلا يتم التوقف". [ 18 ] لا حاجة لتحديد اختبار مقابل الرقم السحري كما في مثال جافا، فهذا ضمني، وبالتالي يتم تبسيط الكود الناتج. ولأن النجاح والفشل يُمرران عبر سلسلة الاستدعاءات، يمكن تضمين استدعاءات الدوال داخل بعضها البعض، وتتوقف هذه الاستدعاءات عند فشل استدعاء الدالة المتداخلة . على سبيل المثال، يمكن اختصار الكود أعلاه إلى: [ 22 ]

بينما تكتب ( تقرأ ())

في هذه النسخة، إذا readفشلت الاستدعاءات، writeتتوقف العملية while. [ 22 ] تعتمد جميع بنيات التفرع والحلقات في Icon على نجاح أو فشل الكود الموجود بداخلها، وليس على اختبار منطقي عشوائي يُقدمه المبرمج. ifتُنفذ thenالكتلة إذا أعاد "الاختبار" قيمة، وتُنفذ elseالكتلة أو تنتقل إلى السطر التالي إذا أعاد قيمة خاطئة &fail. وبالمثل، whileتستمر في استدعاء كتلتها حتى تتلقى فشلاً. يُشير Icon إلى هذا المفهوم باسم التنفيذ الموجه نحو الهدف . [ 23 ]

من المهم التمييز بين مفهومي النجاح والفشل ومفهوم الاستثناء ؛ فالاستثناءات هي حالات غير اعتيادية، وليست نتائج متوقعة. أما حالات الفشل في لغة Icon فهي نتائج متوقعة؛ فالوصول إلى نهاية الملف حالة متوقعة وليست استثناءً. لا تحتوي لغة Icon على معالجة استثناءات بالمعنى التقليدي، مع أن كلمة fail تُستخدم غالبًا في حالات شبيهة بالاستثناءات. على سبيل المثال، إذا كان الملف المراد قراءته غير موجود، فإن الدالة readfail تفشل دون الإشارة إلى حالة خاصة. [ 18 ] في اللغة التقليدية، لا توجد طريقة طبيعية للإشارة إلى هذه "الشروط الأخرى"؛ قد تُستخدم أرقام سحرية إضافية، ولكن في الغالب تُستخدم معالجة الاستثناءات "لإطلاق" قيمة. على سبيل المثال، لمعالجة ملف مفقود في كود Java، قد نرى:

حاول { بينما (( a = read ()) != EOF ) { اكتب ( a ); } } أمسك ( استثناء e ) { // حدث خطأ آخر، استخدم هذا المسك للخروج من الحلقة }

تتطلب هذه الحالة مقارنتين: الأولى لنهاية الملف (EOF) والثانية لجميع الأخطاء الأخرى. ولأن لغة جافا لا تسمح بمقارنة الاستثناءات كعناصر منطقية، كما هو الحال في لغة Icon، try/catchيجب استخدام الصيغة المطولة بدلاً من ذلك. كما أن كتل try تُؤثر سلبًا على الأداء حتى في حال عدم حدوث أي استثناء، وهو عبء مُوزع تتجنبه لغة Icon عادةً.

تستخدم لغة Icon نفس آلية التوجيه نحو الهدف لإجراء اختبارات منطقية تقليدية، مع وجود اختلافات طفيفة. فالمقارنة البسيطة مثل هذه لا تعني "إذا كانت نتيجة تقييم التعبير الشرطي صحيحة أو تُرجع قيمة صحيحة" كما هو الحال في معظم اللغات؛ بل تعني شيئًا أقرب إلى "إذا نجح التعبير الشرطي ولم يفشل". في هذه الحالة، ينجح عامل المقارنة إذا كانت المقارنة صحيحة. يستدعي عامل المقارنة شرطه إذا نجح التعبير، ويستدعي إما الشرط (إن وُجد) أو السطر التالي إذا فشل. والنتيجة مشابهة لشرط if/then التقليدي في لغات أخرى، حيث يُنفذ الشرط إذا كانت قيمة أصغر من . ويكمن الاختلاف الدقيق في إمكانية وضع نفس تعبير المقارنة في أي مكان، على سبيل المثال:ifa<bthenwrite("a is smaller than b")<ifthenelseifthenab

اكتب ( أ < ب )

يتمثل فرق آخر في أن المعامل يُعيد وسيطه الثاني إذا نجح، وهو ما سيؤدي في هذا المثال إلى كتابة <قيمة إذا كانت أكبر من ، وإلا فلن تُكتب أي قيمة. ولأن هذا ليس اختبارًا بحد ذاته ، بل معامل يُعيد قيمة، فيمكن ربط هذه المعاملات معًا، مما يسمح بأشياء مثل [ 22 ] ، وهو نوع شائع من المقارنة يجب كتابته في معظم اللغات على شكل اقتران بين متباينتين مثل .baif a < b < cif (a < b) && (b < c)

من الجوانب الأساسية للتنفيذ الموجه نحو الهدف أن البرنامج قد يضطر إلى الرجوع إلى حالة سابقة في حال فشل إجراء ما، وهي مهمة تُعرف بالتراجع . على سبيل المثال، لنفترض وجود كود يُعيّن قيمة متغير إلى موقع بداية، ثم يُجري عمليات قد تُغيّر هذه القيمة - وهذا شائع في عمليات مسح السلاسل النصية، حيث يُحرّك المؤشر عبر السلسلة أثناء المسح. إذا فشل الإجراء، فمن المهم أن تُعيد أي قراءة لاحقة لهذا المتغير الحالة الأصلية، وليس الحالة التي كان يُعالج بها داخليًا. لهذه المهمة، توفر مكتبة Icon عامل التعيين العكسي<- ، وعامل التبادل العكسي . <->على سبيل المثال، لنفترض وجود كود يحاول العثور على سلسلة نمطية ضمن سلسلة نصية أكبر:

{ ( i := 10 ) & ( j := ( i < find ( pattern , inString ))) }

يبدأ هذا الكود بالانتقال iإلى 10، وهو موقع البداية للبحث. مع ذلك، إذا findفشلت هذه الخطوة، فسيفشل الجزء بأكمله، مما يؤدي إلى بقاء قيمة المتغير iعند 10 كأثر جانبي غير مرغوب فيه . يشير استبدال بـ إلى أنه يجب إعادة تعيين قيمة إلى قيمتها السابقة في حال فشل الجزء. يوفر هذا نظيرًا للذرية في التنفيذ.i := 10i <- 10i

مولدات كهربائية

قد تُرجع التعبيرات في لغة Icon قيمةً واحدة، فعلى سبيل المثال، 5 > xسيتم تقييم التعبير وإرجاع قيمة x إذا كانت قيمة x أقل من 5، وإلا فسيفشل التعبير ولن يُرجع أي قيمة. تتضمن لغة Icon أيضًا مفهوم الإجراءات التي لا تُرجع نتيجة النجاح أو الفشل فورًا ، بل تُرجع قيمًا جديدة في كل مرة يتم استدعاؤها. تُعرف هذه الإجراءات باسم المولدات ، وهي جزء أساسي من لغة Icon. في لغة Icon، يُنتج تقييم التعبير أو الدالة سلسلة نتائج . تحتوي سلسلة النتائج على جميع القيم الممكنة التي يمكن أن يُولدها التعبير أو الدالة. عندما تُستنفد سلسلة النتائج، يفشل التعبير أو الدالة.

تسمح لغة Icon لأي إجراء بإرجاع قيمة واحدة أو عدة قيم، ويتم التحكم في ذلك باستخدام الكلمات المفتاحية fail` <id>` و`<id return>` و`<id suspend>`. الإجراء الذي يفتقر إلى أي من هذه الكلمات المفتاحية يُرجع `<id>` &fail، وهو ما يحدث عندما يصل تنفيذ endالإجراء إلى نهايته. على سبيل المثال:

الإجراء f ( x ) إذا كان x > 0 ، فأرجع 1 .

f(5)ستُعيد الدالة الأولى القيمة 1، بينما f(-1)ستُعيد الدالة الثانية قيمةً أخرى &fail. قد يؤدي هذا إلى سلوك غير متوقع، فعلى سبيل المثال، write(f(-1))لن تُخرج الدالة الأولى أي شيء لأن fالدالة الثانية تفشل وتُوقف عمل الدالة الأولى write. [ 24 ]

يُستخدم تحويل إجراء إلى مولد باستخدام الكلمة suspendالمفتاحية `return`، والتي تعني "إرجاع هذه القيمة، وعند استدعائها مرة أخرى، بدء التنفيذ من هذه النقطة". وبهذا المعنى، يُشبه الأمر مزيجًا من المفهوم staticفي لغة C و ` return. على سبيل المثال: [ 18 ]

الإجراء ItoJ ( i , j ) بينما i <= j do { suspend i i +:= 1 } fail end

يُنشئ مولدًا يُعيد سلسلة من الأرقام تبدأ من iوتنتهي بـ j، ثم يُعيد القيمة &failبعد ذلك. [ ب ] يُوقف suspend iالتنفيذ ويُعيد قيمة iدون إعادة ضبط أي من الحالة. عند استدعاء نفس الدالة مرة أخرى، يستأنف التنفيذ من تلك النقطة بالقيم السابقة. في هذه الحالة، يؤدي ذلك إلى تنفيذ i +:= 1، ثم العودة إلى بداية كتلة while، ثم إعادة القيمة التالية والتوقف مرة أخرى. يستمر هذا حتى i <= jيفشل، وعندها يخرج من الكتلة ويستدعي fail. هذا يسمح بإنشاء المُكرِّرات بسهولة. [ 18 ]

نوع آخر من مولدات الطاقة هو المولد الكهربائي ، الذي يشبه في شكله ووظيفته orعامل التشغيل المنطقي. على سبيل المثال:

إذا كان y < ( x | 5 ) فاكتب ( " y=" , y )

يبدو هذا وكأنه يقول "إذا كانت y أصغر من x أو 5، فإن..."، ولكنه في الواقع اختصار لمولد يُعيد قيمًا حتى يصل إلى نهاية القائمة. تُمرر قيم القائمة إلى العمليات، في هذه الحالة، <. لذا، في هذا المثال، يختبر النظام أولًا y < x، فإذا كانت x أكبر من y، يُعيد قيمة x، وينجح الاختبار، وتُكتب قيمة y في الشرط then. أما إذا لم تكن x أكبر من y، فإنه يفشل، ويستمر المولد في تنفيذ y < 5. إذا نجح هذا الاختبار، تُكتب y. إذا لم تكن y أصغر من x أو 5، فإن المولد ينفد من الاختبارات ويفشل، ifويفشل الشرط، writeولا يُنفذ الشرط. بالتالي، ستظهر قيمة y على وحدة التحكم إذا كانت أصغر من x أو 5، وبذلك يتحقق الغرض من القيمة المنطقية or. لن تُستدعى الدوال إلا إذا نجح تقييم مُعاملاتها، لذا يمكن اختصار هذا المثال إلى:

اكتب ( "y=" , ( x | 5 ) > y )

داخليًا، لا يقتصر دور المولد على كونه مجرد مولد or، بل يمكن استخدامه أيضًا لإنشاء قوائم قيم عشوائية. ويمكن استخدام ذلك للتكرار على قيم عشوائية، مثل:

كل i : = ( 1 | 3 | 4 | 5 | 10 | 11 | 23 ) اكتب ( i )

بما أن قوائم الأعداد الصحيحة شائعة في العديد من سياقات البرمجة، فإن مكتبة Icon تتضمن أيضًا toالكلمة المفتاحية لإنشاء مولدات أعداد صحيحة مخصصة :

لكل قيمة k من 1 إلى 10 ، اكتب ( k )

والتي يمكن اختصارها:

كل كتابة ( من 1 إلى 10 )

لا يتم تحديد نوع الأيقونة بشكل صارم، لذا يمكن أن تحتوي قوائم المبدلات على أنواع مختلفة من العناصر:

كل i := ( 1 | "hello" | x < 5 ) do write ( i )

يكتب هذا 1 و"مرحباً" وربما 5 اعتمادًا على قيمة x.

وبالمثل، يتم استخدام عامل الربط ، &بطريقة مشابهة لعامل منطقي and: [ 25 ]

كل x := ItoJ ( 0 , 10 ) & x % 2 == 0 do write ( x )

يستدعي هذا الكود ItoJقيمة ابتدائية تساوي صفرًا، ثم يُسندها إلى x. بعد ذلك، يُنفذ الجزء الأيمن من عملية الربط، وبما أن قيمة x تساوي صفرًا، فإنه يطبعها. ثم يستدعي المولد مرة أخرى، فيُسند القيمة 1 إلى x، مما يؤدي إلى فشل الجزء الأيمن من العملية، فلا يطبع شيئًا. والنتيجة هي قائمة بجميع الأعداد الزوجية من 0 إلى 10. [ 25 ]x % 2ItoJ

يُعدّ مفهوم المولدات مفيدًا وقويًا للغاية عند استخدامه مع عمليات السلاسل النصية، وهو أساس رئيسي لتصميم Icon. لنأخذ على سبيل المثال العملية indexOfالموجودة في العديد من لغات البرمجة؛ حيث تبحث هذه الدالة عن سلسلة نصية داخل سلسلة نصية أخرى، وتعيد فهرس موقعها، أو رقمًا سحريًا إذا لم يتم العثور عليها. على سبيل المثال:

s = "العالم مسرح كبير، والرجال والنساء فيه مجرد ممثلين" ; i = indexOf ( "the" , s ); write ( i );

سيقوم هذا بفحص السلسلة s، والعثور على أول ظهور لكلمة "the"، وإرجاع هذا الفهرس، وهو 4 في هذه الحالة. ومع ذلك، تحتوي السلسلة على نسختين من كلمة "the"، لذلك لإرجاع المثال الثاني، يتم استخدام صيغة بديلة:

j = indexOf ( "the" , s , i + 1 ); write ( j );

يُخبر هذا البرنامج بالبدء في المسح من الموقع 5، لذا لن يتطابق مع أول حالة وجدناها سابقًا. مع ذلك، قد لا توجد حالة ثانية لكلمة "the" - وقد لا توجد حالة أولى أيضًا - لذا indexOfيجب التحقق من القيمة المُعادة من البرنامج مقابل الرقم السحري -1 الذي يُستخدم للإشارة إلى عدم وجود تطابقات. إليك روتين كامل يطبع موقع كل حالة:

s = "العالم مسرح، والرجال والنساء فيه مجرد ممثلين" ; i = indexOf ( " the" , s ); while i != -1 { write ( i ); i = indexOf ( "the" , s , i + 1 ); }

في لغة Icon، المكافئ findهو مولد، لذا يمكن إنشاء نفس النتائج بسطر واحد:

s := "العالم كله مسرح. وكل الرجال والنساء مجرد ممثلين" every write ( find ( "the " , s ))

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

كل كتابة ( 5 < البحث عن ( "the" ، s ))

لن يتم إرجاع الموضع إلا إذا ظهرت كلمة "the" بعد الموضع 5؛ وإلا ستفشل المقارنة، ولن تتم الكتابة.

everyيشبه هذا العامل عامل التشغيل ، whileحيث يقوم بالمرور على كل عنصر يتم إرجاعه بواسطة مولد ويخرج عند الفشل: [ 24 ]

لكل k := i إلى j اكتب ( دالة ما ( k ) )

يوجد فرق جوهري بينهما every؛ whileإذ whileيُعيد تقييم النتيجة الأولى حتى تفشل، بينما everyيستجلب القيمة التالية من مُولِّد. everyفي الواقع، يُدخل القيم في الدالة بطريقة مشابهة للكتل في لغة Smalltalk . على سبيل المثال، يمكن إعادة كتابة الحلقة أعلاه على النحو التالي: [ 24 ]

اكتب كل ( دالة ما ( من i إلى j ))

في هذه الحالة، سيتم إدخال القيم من i إلى j someFunctionوكتابة عدة أسطر من المخرجات (ربما). [ 24 ]

المجموعات

تتضمن لغة Icon أنواعًا متعددة من المجموعات، منها القوائم التي يمكن استخدامها أيضًا كمجموعات وقوائم انتظار ، والجداول (المعروفة أيضًا بالخرائط أو القواميس في لغات أخرى)، والمجموعات ، وغيرها. تشير Icon إلى هذه الأنواع باسم "الهياكل" . تُعدّ المجموعات مولدات متأصلة، ويمكن استدعاؤها بسهولة باستخدام صيغة التعجب (b). على سبيل المثال:

lines := [] # إنشاء قائمة فارغة while line := read () do { # حلقة قراءة الأسطر من المدخلات القياسية push ( lines , line ) # استخدام صيغة مشابهة للمكدس لإضافة السطر إلى القائمة } while line := pop ( lines ) do { # حلقة طالما يمكن إزالة الأسطر من القائمة write ( line ) # كتابة السطر }

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

lines := [] # إنشاء قائمة فارغة while push ( lines , read ()) # إضافة عناصر حتى تصبح فارغة while write ( pop ( lines )) # الكتابة حتى تصبح فارغة

لأن مجموعة القوائم هي مولد، يمكن تبسيط ذلك أكثر باستخدام صيغة التعجب (bang):

lines := [] every push ( lines , ! &input ) every write ( ! lines )

في هذه الحالة، يتسبب رمز التعجب في writeقيام الدالة Icon بإرجاع سطر نصي واحد تلو الآخر من المصفوفة، ثم تتوقف في النهاية. &inputوهي دالة مماثلة تعتمد على المولد، readتقرأ سطرًا من المدخلات القياسية ، لذا !&inputتستمر في قراءة الأسطر حتى نهاية الملف.

بما أن Icon لا يحتوي على أنواع بيانات محددة، يمكن أن تحتوي القوائم على أي أنواع مختلفة من القيم:

aCat := [ "muffins" , "tabby" , 2002 , 8 ]

يمكن أن تتضمن العناصر هياكل أخرى. لإنشاء قوائم أكبر، تتضمن لغة Icon listمولدًا؛ حيث تُنشئ قائمة تحتوي على 10 نسخ من كلمة "word". وكما هو الحال في المصفوفات في لغات البرمجة الأخرى، تسمح Icon بالبحث عن العناصر حسب موقعها، على سبيل المثال، . كما تتضمن أيضًا خاصية تقطيع المصفوفات ، مما يسمح بإنشاء قوائم جديدة من عناصر قوائم أخرى، على سبيل المثال، تُنتج قائمة جديدة باسم aCat تحتوي على "tabby" و2002.i := list(10, "word")weight := aCat[4]aCat := Cats[2:4]

الجداول هي في الأساس قوائم ذات مفاتيح فهرسة عشوائية بدلاً من الأعداد الصحيحة:

symbols := table ( 0 ) symbols [ "there" ] := 1 symbols [ "here" ] := 2

يُنشئ هذا الكود جدولًا يستخدم الصفر كقيمة افتراضية لأي مفتاح غير معروف. ثم يُضيف عنصرين إلى الجدول، بمفتاحين هما "هناك" و"هنا"، وقيمتين 1 و2.

تُشبه المجموعات القوائم، لكنها تحتوي على عنصر واحد فقط من أي قيمة مُعطاة. تتضمن مكتبة Icon دوالًا ++لإنشاء اتحاد مجموعتين، **وتقاطعهما، --وفرقهما. كما تتضمن عددًا من مجموعات Cset المُعرّفة مُسبقًا، وهي مجموعات تحتوي على أحرف مُختلفة. يوجد أربعة أنواع قياسية من مجموعات Cset في Icon، وهي: `<Cset>`، و`<Cset>` &ucase، &lcaseو` &letters<Cset> &digits`. يُمكن إنشاء مجموعات Cset جديدة عن طريق وضع سلسلة نصية بين علامتي اقتباس مُفردتين، على سبيل المثال: `<Cset>` .vowel := 'aeiou'

الأوتار

في لغة Icon، تُعتبر السلاسل النصية قوائم من الأحرف. وباعتبارها قائمة، فهي مولدات، وبالتالي يمكن تكرارها باستخدام صيغة التعجب (bang):

يكتب الجميع ( ! "مرحباً بالعالم!" )

سيتم طباعة كل حرف من السلسلة على سطر منفصل.

يمكن استخراج أجزاء من سلسلة نصية باستخدام نطاق محدد بين قوسين. يُعيد هذا النطاق إما مؤشرًا إلى حرف واحد أو جزءًا من السلسلة. يمكن الوصول إلى السلاسل النصية من اليمين أو اليسار. تُعرَّف المواضع داخل السلسلة النصية بأنها تقع بين الأحرف 1 A 2 B 3 C ويمكن تحديدها من اليمين −3 A −2 B −1 C 0

على سبيل المثال،

"Wikipedia" [ 1 ] ==> "W" "Wikipedia" [ 3 ] ==> "k" "Wikipedia" [ 0 ] ==> "a" "Wikipedia" [ 1 : 3 ] ==> "Wi" "Wikipedia" [ - 2 : 0 ] ==> "ia" "Wikipedia" [ 2 + : 3 ] ==> "iki"

يوضح المثال الأخير استخدام الطول بدلاً من موضع النهاية

يمكن استخدام تحديد الفهرسة كقيمة قابلة للتعديل (lvalue) ضمن تعبير. ويمكن استخدام ذلك لإدراج سلاسل نصية في سلسلة نصية أخرى أو حذف أجزاء من سلسلة نصية. على سبيل المثال:

s := "abc" s [ 2 ] := "123" # قيمة s الآن هي "a123c" s := "abcdefg" s [ 3 : 5 ] := "ABCD" # قيمة s الآن هي "abABCDefg" s := "abcdefg" s [ 3 : 5 ] := "" # قيمة s الآن هي "abefg"

مسح السلاسل

ومن بين التبسيطات الأخرى للتعامل مع السلاسل النصية نظام المسح الضوئي ، الذي يتم استدعاؤه باستخدام ?، والذي يستدعي وظائف على سلسلة نصية:

s ؟ اكتب ( ابحث عن ( "the" ))

يشير الرمز إلى الجانب الأيسر من النص ?باعتباره الموضوع ، ويمرره إلى دوال السلاسل النصية. تذكر أن هذا الرمز findيأخذ وسيطين، نص البحث كمعامل أول، والسلسلة المراد البحث عنها كمعامل ثانٍ. استخدام ?المعامل الثاني ضمني ولا يتطلب تحديده من قبل المبرمج. في الحالات الشائعة عند استدعاء عدة دوال على سلسلة نصية واحدة بالتتابع، يمكن لهذا الأسلوب أن يقلل بشكل كبير من طول الكود الناتج ويحسن وضوحه. تحدد توقيعات دوال الرمز وسيط الموضوع في تعريفاتها، مما يسمح برفع هذا الوسيط بهذه الطريقة.

لا يُعدّ هذا ?مجرد اختصار برمجي ، بل يُهيئ أيضًا "بيئة مسح نصية" لأي عمليات نصية لاحقة. يعتمد هذا على متغيرين داخليين، وهما `<string>` &subjectو` <string> &pos&subjectحيث `<string>` هو مؤشر إلى النص الأصلي، بينما ` &pos<string>` هو الموضع الحالي داخله، أو المؤشر. تستخدم إجراءات معالجة النصوص المختلفة في Icon هذين المتغيرين، لذا لا يحتاج المبرمج إلى تحديدهما صراحةً. على سبيل المثال:

s := "this is a string" s ? write ( "subject=[" , &subject , "], pos=[" , &pos , "]" )

سينتج عنه:

الموضوع = [هذه سلسلة نصية]، الموضع = [1] 

يمكن استخدام الدوال المدمجة والدوال المُعرَّفة من قِبل المستخدم للتنقل داخل السلسلة النصية التي يتم مسحها ضوئيًا. جميع الدوال المدمجة مُهيأة افتراضيًا &subjectللسماح &posباستخدام صيغة المسح الضوئي. سيكتب الكود التالي جميع "الكلمات" المفصولة بمسافات في سلسلة نصية:

s := "this is a string" s ? { # إنشاء بيئة مسح السلسلة while not pos ( 0 ) do { # اختبار نهاية السلسلة tab ( many ( ' ' )) # تخطي أي فراغات word := tab ( upto ( ' ' ) | 0 ) # الكلمة التالية تصل إلى الفراغ التالي -أو- نهاية السطر write ( word ) # كتابة الكلمة } }

يُقدّم هذا المثال عددًا من الدوال الجديدة. posتُعيد الدالة `returns` القيمة الحالية لـ &pos`. قد لا يكون واضحًا للوهلة الأولى سبب الحاجة إلى هذه الدالة بدلًا من استخدام قيمة ` &posمباشرةً؛ والسبب هو أن ` &pos` متغير، وبالتالي لا يمكن أن يأخذ القيمة `` &fail، وهو ما يمكن للإجراء فعله pos. لذا، posتُوفّر الدالة `returns` غلافًا بسيطًا لـ ``، &posمما يسمح باستخدام التحكم في التدفق الموجّه نحو الهدف في Icon بسهولة دون الحاجة إلى كتابة اختبارات منطقية يدويًا لـ `` &pos. في هذه الحالة، الاختبار هو "is &pos zero"، وهو، في الترقيم الفردي لمواقع السلاسل النصية في Icon، نهاية السطر. إذا لم تكن القيمة صفرًا، posتُعيد الدالة `returns` &fail، والتي تُعكس باستخدام `` not، وتستمر الحلقة.

manyيُحدد هذا الأمر مثالًا واحدًا أو أكثر لمعامل Cset المُحدد، بدءًا من النقطة الحالية &pos. في هذه الحالة، يبحث عن مسافات، لذا فإن نتيجة هذه الدالة هي موقع أول حرف غير مسافة بعد النقطة &pos. tabينتقل الأمر &posإلى ذلك الموقع، مع احتمال وجود خطأ &failفي حالة، على سبيل المثال، manyسقوط النقطة في نهاية السلسلة. uptoيُعد هذا الأمر عكس الأمر السابق many؛ إذ يُعيد الموقع الذي يسبق مباشرةً معامل Cset المُحدد، والذي يُعيّنه المثال بعد ذلك &posباستخدام معامل آخر tab. يُستخدم التناوب أيضًا للتوقف عند نهاية السطر.

يمكن تحسين هذا المثال باستخدام مجموعة Cset أكثر ملاءمة لتقسيم الكلمات، والتي قد تشمل النقاط والفواصل وعلامات الترقيم الأخرى، بالإضافة إلى أحرف المسافات البيضاء الأخرى مثل علامات الجدولة والمسافات غير القابلة للكسر. ويمكن استخدام مجموعة Cset هذه في manyو upto.

يوضح مثال أكثر تعقيدًا دمج المولدات ومسح السلاسل النصية داخل اللغة.

الإجراء الرئيسي () s := "Mon Dec 8" s ? write ( Mdate () | "ليس تاريخًا صالحًا" ) end# تعريف دالة مطابقة تُرجع # سلسلة نصية تُطابق يومًا أو شهرًا أو يومًا من الشهر. procedure Mdate () # تعريف بعض القيم الأولية static dates static days initial { days := [ "Mon" , "Tue" , "Wed" , "Thr" , "Fri" , "Sat" , "Sun" ] months := [ "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" , "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec" ] }كل تعليق ( قيمة الإرجاع <- علامة تبويب ( مطابقة ( ! أيام )) || # مطابقة يوم = " " || # متبوع بعلامة تبويب فارغة ( مطابقة ( ! أشهر )) || # متبوع بالشهر = " " || # متبوع برقمين على الأكثر ) & ( = " " | pos ( 0 ) ) & # إما فراغ أو نهاية السلسلة قيمة الإرجاع # وأخيرًا إرجاع نهاية السلسلة# دالة مطابقة تُرجع سلسلة من n رقمًا procedure matchdigits ( n ) suspend ( v := tab ( many ( &digits )) & * v <= n ) & v end

الانتقادات

كتب لورانس ترات ورقة بحثية حول برنامج Icon، تناول فيها تطبيقاته العملية وأشار إلى عدد من جوانب القصور. من بين هذه الجوانب، عدد من القرارات العملية التي تنبع من أصولها في معالجة النصوص، ولكنها لا تبدو منطقية في مجالات أخرى. [ 24 ] ومن بينها:

يُعدّ قرار الفشل الافتراضي في نهاية الإجراءات منطقيًا في سياق المولدات، ولكنه أقل منطقية في حالة الإجراءات العامة. بالعودة إلى المثال المذكور أعلاه، write(f(-1))لن يُخرج ما هو متوقع. ومع ذلك: [ 24 ]

x := 10 ( أسطر إضافية ) x := f ( - 1 ) اكتب ( x )

سيؤدي ذلك إلى طباعة الرقم 10. هذا النوع من المشاكل ليس واضحًا على الإطلاق، فحتى في بيئة تصحيح الأخطاء التفاعلية، يتم استدعاء جميع التعليمات البرمجية، لكنها xلا تحصل أبدًا على القيمة المتوقعة. يمكن اعتبار هذا أحد "المفاجآت" التي يجب على المبرمجين الانتباه إليها في أي لغة برمجة، لكن ترات فحص مجموعة متنوعة من برامج Icon ووجد أن الغالبية العظمى من الإجراءات ليست مولدات. هذا يعني أن السلوك الافتراضي لـ Icon لا يُستخدم إلا من قِبل أقلية ضئيلة من بنياته، ومع ذلك فهو يمثل مصدرًا رئيسيًا للأخطاء المحتملة في جميع البنيات الأخرى. [ 24 ]

تتمثل إحدى المشكلات الأخرى في غياب نوع البيانات المنطقية [ c ] والمنطق المنطقي التقليدي. فبينما يعمل نظام النجاح/الفشل في معظم الحالات التي يكون الهدف النهائي فيها هو التحقق من قيمة ما، إلا أن هذا قد يؤدي إلى بعض السلوكيات غير المتوقعة في التعليمات البرمجية التي تبدو بسيطة: [ 25 ]

الإجراء الرئيسي () إذا كان c ثم { اكتب ( "مأخوذ" ) } نهاية

سيطبع هذا البرنامج "مأخوذ". والسبب هو أن الاختبار cيُرجع قيمة؛ هذه القيمة هي &null، وهي القيمة الافتراضية لجميع المتغيرات غير المُهيأة. [ 26 ]&null قيمة صالحة، لذا if cينجح الاختبار. لاختبار ذلك، يجب جعل الاختبار صريحًا c === &null(أو استخدام تعبير Icon الأكثر شيوعًا if /c then ...). افترض ترات أن هذا يُضعف من وضوح الكود ، إذ افترض خطأً أنه يختبر "هل c يساوي صفرًا" أو "هل c موجود". [ 25 ]

انظر أيضاً

ملحوظات

  1. وفقًا لمقابلة أجريت عام 1985، ذكر غريسولد أن مصطلح "أيقونة" لم يكن مستخدمًا حتى تم إصدار لغة سمول توك للجمهور بعد ذلك بفترة. وأعرب عن انزعاجه من أن المصطلح أصبح الآن يُربك الأشخاص الذين يعتقدون أن اللغة تحتوي على عناصر رسومية. [ 12 ]
  2. لا حاجة إلى استخدام "the"في هذه الحالة لأنها تسبق "the" مباشرةً. تمت إضافتها للتوضيح.failend
  3. على الرغم من ذلك، وكما يشير ترات، فإن لغة K&R C تفتقر أيضًا إلى نوع منطقي صريح وتستخدم 0 للدلالة على الخطأ وأي قيمة غير صفرية للدلالة على الصواب. [ 24 ]

مراجع

الاقتباسات

  1. تاونسند، جريج (7 سبتمبر 2025). "الإصدار v9.5.25a" . جيت هاب .
  2. "Goaldi" . GitHub .
  3. شيمينور، نيل؛ بيترز، تيم؛ هيتلاند، ماغنوس لي (18 مايو 2001). "PEP 255 - مولدات بسيطة" . مقترحات تحسين بايثون . مؤسسة برمجيات بايثون . تم الاطلاع عليه في 9 فبراير 2012 .
  4. غريسولد 1981 ، ص 601، 602.
  5. غريسولد 1981 ، ص 602.
  6. غريسولد 1981 ، ص 606.
  7. غريسولد 1981 ، ص 608.
  8. غريسولد 1981 ، ص 609.
  9. غريسولد 1981 ، ص 629.
  10. شابيرو 1985 ، ص 346.
  11. 1 2 3 4 5 Griswold & Griswold 1993 ، ص 53.
  12. شابيرو 1985 ، ص 350.
  13. غريسولد وغريسولد 2002 ، ص. xv.
  14. غريسولد وغريسولد 2002 ، ص. xvi.
  15. غريسولد وغريسولد 2002 ، ص 10.
  16. غريسولد وغريسولد 2002 ، ص. 1.
  17. غريسولد وغريسولد 2002 ، ص 4.
  18. 1 2 3 4 5 6 ترات 2010 ، ص. 74.
  19. "Array.prototype.indexOf()" . وثائق MDN على الويب . 27 يونيو 2023.
  20. لين ، روبرت (26 يوليو 2015). "SNOBOL - مقدمة" . جرب MTS .
  21. Tratt 2010 ، ص 73.
  22. 1 2 3 غريسولد 1996 ، ص. 2.1.
  23. غريسولد 1996 ، ص. 1.
  24. 1 2 3 4 5 6 7 8 ترات 2010 ، ص. 75.
  25. 1 2 3 4 Tratt 2010 ، ص. 76.
  26. غريسولد وغريسولد 2002 ، ص 128.

فهرس