كوين (الحوسبة)

إن مخرجات برنامج كوين هي نفسها تمامًا شفرة المصدر الخاصة به.

برنامج كوين هو برنامج حاسوبي لا يستقبل أي مدخلات، وينتج نسخة من شفرته المصدرية كمخرج وحيد. وتُعرف هذه البرامج في نظرية الحوسبة وأدبيات علوم الحاسوب بالمصطلحات الشائعة التالية : "البرامج ذاتية النسخ"، و"البرامج ذاتية التكاثر"، و"البرامج ذاتية النسخ".

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

اسم

صاغ دوغلاس هوفستاتر اسم "كوين" في كتابه العلمي الشهير عام 1979 بعنوان "غودل، إيشر، باخ" ، تكريماً للفيلسوف ويلارد فان أورمان كواين (1908-2000)، الذي أجرى دراسة مستفيضة عن الإشارة الذاتية غير المباشرة ، وخاصةً للتعبير التالي الذي ينتج عنه مفارقة، والمعروف باسم مفارقة كواين :

يؤدي إلى الكذب عندما يسبقه اقتباسه.

تاريخ

وضع جون فون نيومان نظرية حول الأوتوماتا ذاتية التكاثر في الأربعينيات من القرن العشرين. وفي وقت لاحق، ناقش بول براتلي وجان ميلو هذه الأوتوماتا في مقالتهما "التسلية الحاسوبية: الأوتوماتا ذاتية التكاثر" في عام 1972. [ 1 ] وقد أبدى براتلي اهتمامًا بالبرامج ذاتية التكاثر لأول مرة بعد أن شاهد أول برنامج معروف من هذا النوع مكتوب بلغة أطلس أوتوكود في إدنبرة في الستينيات من القرن العشرين من قبل هاميش ديوار ، المحاضر والباحث في جامعة إدنبرة .

يستند شرط "تنزيل المصدر" في رخصة جنو أفيرو العامة إلى فكرة الكواين. [ 2 ]

أمثلة

أقصر كوين مناسب

أقصر برنامج غير تافه في لغة برمجة رئيسية (برنامج "حقيقي") معروف حتى عام 2020 هو برنامج JavaScript ES6($=_=>`($=${$})()`)() المكون من 21 حرفًا . [ 3 ]

كوينز البناء

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

إليكم ثلاثة أمثلة صغيرة بلغة بايثون 3:

# مثال أ. chr(39) == "'". a = 'a = {}{}{} ; print(a.format(chr(39), a, chr(39)))' ; print ( a . format ( chr ( 39 ), a , chr ( 39 )))
# مثال ب. chr(39) == "'". b = 'b = %s%s%s ; print(b %% (chr(39), b, chr(39)))' ; print ( b % ( chr ( 39 ), b , chr ( 39 )))
# مثال ج. سيتم وضع علامات اقتباس تلقائية على %r. c = 'c = %r ; print(c %% c)' ; print ( c % c )

يوضح الكود الكلاسيكي التالي للغة جافا (جافا 1.5) البنية الأساسية لـ quine.

public class Quine { public static void main ( String [] args ) { char q = 34 ; // علامة اقتباس String [] l = { // مصفوفة من التعليمات البرمجية المصدرية "public class Quine {" , " public static void main(String[] args) {" , " char q = 34; // علامة اقتباس" , " String[] l = { // مصفوفة من التعليمات البرمجية المصدرية" , " " , " };" , " for (int i = 0; i < 4; i++) { // طباعة التعليمات البرمجية الافتتاحية" , " System.out.println(l[i]);" , " }" , " for (int i = 0; i < l.length; i++) { // طباعة مصفوفة السلاسل النصية" , " System.out.printf(\"%s%c%s%c,%n\", l[4], q, l[i], q);" , " }" , " for (int i = 5; i < l.length; i++) { // طباعة هذا الكود" , " System.out.println(l[i]);" , " }" , " }" , "}" , }; for ( int i = 0 ; i < 4 ; i ++ ) { // طباعة كود البداية System . out . println ( l [ i ] ); } for ( int i = 0 ; i < l . length ; i ++ ) { // طباعة مصفوفة السلاسل النصية System . out . printf ( "%s%c%s%c,%n" , l [ 4 ] , q , l [ i ] , q ); } for ( int i = 5 ; i < l . length ; i ++ ) { // طباعة هذا الكود System .out.println ( l [أنا ] } } }

يحتوي الكود المصدري على مصفوفة نصية من نفسه، والتي يتم إخراجها مرتين، مرة داخل علامات اقتباس.

تم اقتباس هذا الكود من منشور أصلي على موقع c2.com، حيث نشره المؤلف، جيسون ويلسون، كنسخة مبسطة من كوين، بدون تعليقات جافا. [ 4 ]

بعد إدخال ميزة كتل النصوص في Java 15، [ 5 ] أصبح من الممكن الحصول على نسخة أكثر قابلية للقراءة وأبسط: [ 6 ]

public class Quine { public static void main ( String [] args ) { String textBlockQuotes = new String ( new char [] { '"' , '"' , '"' }); char newLine = 10 ; String source = """ public class Quine {  public static void main(String[] args) {  String textBlockQuotes = new String(new char[]{'"', '"', '"'});  char newLine = 10;  String source = "%s%s%s%s";  System.out.print(source.formatted(textBlockQuotes, newLine, source, textBlockQuotes));  } } """ ; System . out . print ( source . formatted ( textBlockQuotes , newLine , source , textBlockQuotes )); } }

هذا مثال على نسخة حديثة من كود Java 25:

void main () { String s = """  void main() {  String s = %c%c%c  %s%c%c%c; IO.print(s.formatted(34, 34, 34, s, 34 , 34 , 34  ));  }""" ; IO.print ( s.formatted ( 34 , 34 , 34 , s , 34 , 34 , 34 )) ; }

يمكن تنفيذ الكود أعلاه ببساطة عن طريق إسقاط محتواه في أي ملف بامتداد .java ، مثل " App.java "، ثم تنفيذه باستخدام " java App.java ".

تُستخدم الفكرة نفسها في استعلام SQL التالي :

حدد استبدال ( استبدال ( 'حدد استبدال(استبدال("$",CHAR(34),CHAR(39)),CHAR(36),"$") كـ Quine' , CHAR ( 34 ), CHAR ( 39 )), CHAR ( 36 ), 'حدد استبدال(استبدال("$",CHAR(34),CHAR(39)),CHAR(36),"$") كـ Quine' ) كـ Quine

تقييم كوينز

تتمتع بعض لغات البرمجة بالقدرة على تقييم سلسلة نصية كبرنامج. ويمكن لبرامج كوين الاستفادة من هذه الميزة. على سبيل المثال، برنامج كوين هذا المكتوب بلغة روبي :

eval s = "print 'eval s=';p s"

يمكن للغة Lua أن تفعل ما يلي:

s = "print(string.format('s=%c%s%c; load(s)()',34,s,34))" ; load ( s )()

في بايثون 3.8:

exec ( s := 'print("exec(s:= %r )" %s )' )

"الغش" كوينز

التقييم الذاتي

في العديد من لغات البرمجة الوظيفية، بما في ذلك لغة Scheme وغيرها من لغات Lisp ، واللغات التفاعلية مثل APL ، تُقيّم الأرقام ذاتيًا. في لغة TI-BASIC ، إذا أعاد السطر الأخير من البرنامج قيمة، تُعرض هذه القيمة على الشاشة. لذلك، في هذه اللغات، ينتج عن برنامج يتكون من رقم واحد فقط رمز quine بحجم بايت واحد. ولأن هذا النوع من الرموز لا يُبنى ذاتيًا، يُعتبر غالبًا غشًا.

1

كوينز فارغة

في بعض اللغات، وخاصة لغات البرمجة النصية ، يُعد ملف المصدر الفارغ نقطة ثابتة في اللغة، فهو برنامج صالح لا يُنتج أي مخرجات. [ أ ]

فاز برنامج فارغ كهذا، قُدِّمَ تحت مسمى "أصغر برنامج ذاتي التكاثر في العالم"، بجائزة "أسوأ انتهاك للقواعد" في المسابقة الدولية لشفرة C المبهمة . [ 7 ] لم يكن البرنامج بلغة C صالحة (يفتقر إلى main()دالة) ولم يُجمَّع فعليًا، بل كان مرفقًا بأداة Makefileتُستخدم cpلنسخ الملف الفارغ إلى ملف آخر، يُنفَّذ كبرنامج نصي شل لطباعة لا شيء. [ 8 ]

فحص شفرة المصدر

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

#!/bin/sh # كوين غير صالح. # قراءة الملف المُنفَّذ من القرص غش. cat $0

صيغة أقصر، تستغل سلوك توجيهات shebang :

#!/bin/cat

وتشمل التقنيات المشكوك فيها الأخرى استخدام رسائل المترجم؛ على سبيل المثال، في بيئة GW-BASIC ، سيؤدي إدخال "Syntax Error" إلى استجابة المفسر بـ "Syntax Error".

يمكن أيضًا إخراج كود Quine بشكل مرئي، على سبيل المثال يتم استخدامه لتصور المنطقة المحايدة في Yars' Revenge ، جنبًا إلى جنب مع السكرين النحوي ، لإخفاء الكود المصدري.

برامج أوربوروس

يمكن توسيع مفهوم الكواين ليشمل مستويات متعددة من التكرار، مما يؤدي إلى ظهور " برامج الأوربوروس " أو "تتابعات الكواين". يجب عدم الخلط بين هذا المفهوم والكواينات المتعددة .

مثال

يقوم برنامج Java هذا بإخراج مصدر برنامج C++ الذي يقوم بدوره بإخراج كود Java الأصلي.

استيراد std ؛int main ( int argc , char * argv []) { char q = 34 ; std :: array < std :: string , 36 > l = { " " , "=============<<<<<<<< كود C++ >>>>>>>>=============" , "import std;" "" , "int main(int argc, char* argv[]) {" , " char q = 34;" , " std::array<std::string> l = {" , " };" , " for (int i = 19; i <= l.size(); ++i) {" , " std::println( \" {} \" , l[i]);" ، " }" ، " for (int i = 0; i <= l.size(); ++i)" ، " std::println( \" {}{}{}{}, \" , l[0], q, l[i], q);" ، " }" ، " for (int i = 2; i <= 17; ++i)" ، " std::println( \" {} \" , l[i]);" ، " }" ، " return 0;" ، "}" ، "=============<<<<<<<< كود جافا >>>>>>>>=============" ، "public class Quine {" ، " public static void main(String[] args) {" ، " char q = 34;" ، "String[] l = {" , " };" , " for (int i = 2; i <= 17; ++i)" , "System.out.println(l[i]);" , " }" , " for (int i = 0; i < l.length; ++i) {" , "System.out.printf( \" %s%c%s%c,%n \" , l[0], q, l[i], q);" , " }" , " for (int i = 18; i <= l.length; ++i) {" , "System.out.println(l[i]);" , " }" , " }" , "}" ,} ; for ( int i = 19 ; i <= l.size ( ); ++ i ) std :: println ( "{}" , l [ i ]);; }for ( int i = 0 ; i <= l.size (); ++i) std :: println ( " { } { } {}{}," , l [ 0 ], q , l [ i ], q ); } for ( int i = 2 ; i <= 17 ; ++ i ) std :: println ( "{}" , l [ i ]);; } return 0 ; }
public class Quine { public static void main ( String [] args ) { char q = 34 ; String [] l = { " " , "=============<<<<<<<< كود C++ >>>>>>>>=============" , "import std;" , "" , "int main(int argc, char* argv[]) {" , " char q = 34;" , " std::array<std::string> l = {" , " };" , " for (int i = 19; i <= l.size(); ++i) {" , " std::println(\"{}\", l[i]);" ، " for (int i = 0; i <= l.size(); ++i) {" ، " std::println(\"{}{}{}{},\", l[0], q, l[i], q);" ، " for (int i = 2; i <= 17; ++i) {" ، " std::println(\"{}\", l[i]);" ، " }" ، " return 0;" ، "}" ، "=============<<<<<<<< كود جافا >>>>>>>>=============" ، "public class Quine {" ، " public static void main(String[] args) {" ، " char q = 34;" ، " String[] l = {" ، " };" ، " for (int i = 2; i <= 17; ++i)" ، " System.out.println(l[i]);" ، " for (int i = 0; i < l.length; ++i)" ، " System.out.printf(\"%s%c%s%c,%n\", l[0], q, l[i], q);" ، " for (int i = 18; i <= l.length; ++i) {" ، " System.out.println(l[i]);" ، " }" " }" ، "}" ، }; for ( int i = 2 ; i <= 17 ; ++ i ) { System . out .println ( l [ i ] ); } for ( int i = 0 ; i < l.length ; ++ i ) { System.out.printf ( " % s%c%s%c , % n " , l [0 ] , q , l [ i ] , q ); } for ( int i = 18 ; i <= l . length ; ++ i ) { System . out . println ( l [ i ] ); } } }

تم إنتاج مثل هذه البرامج بأطوال دورات مختلفة:

مولتي كوينز

يصف ديفيد مادور، مبتكر Unlambda ، multiquines على النحو التالي: [ 17 ]

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

البرنامج متعدد اللغات الذي يتكون من لغتين (أو ثنائي اللغات) سيكون برنامجًا يقوم بما يلي:

  • عند التشغيل، يكون كوين في اللغة X.
  • عند تزويدها بوسيطة سطر أوامر محددة من قبل المستخدم، ستطبع برنامجًا ثانيًا بلغة Y.
  • بالنظر إلى البرنامج الثاني المكتوب بلغة Y، فعند تشغيله بشكل طبيعي، سيكون أيضًا برنامجًا من نوع كوين مكتوبًا بلغة Y.
  • إذا تم إعطاء البرنامج الثاني بلغة Y، وتم تزويده بوسيطة سطر أوامر محددة من قبل المستخدم، فسيتم إنتاج البرنامج الأصلي بلغة X.

ويمكن اعتبار برنامج biquine بمثابة مجموعة من برنامجين، كلاهما قادر على طباعة أي من الاثنين، اعتمادًا على وسيط سطر الأوامر المقدم.

نظرياً، لا يوجد حد لعدد اللغات في برنامج متعدد اللغات. تم إنتاج برنامج متعدد اللغات (أو خماسي اللغات) مكون من 5 أجزاء باستخدام لغات بايثون ، وبيرل ، وسي ، ونيو ليسب ، وإف شارب [ 18 ] ، كما يوجد برنامج متعدد اللغات مكون من 25 لغة. [ 19 ]

متعدد اللغات

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

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

مقاوم للإشعاع

الكود المُحصّن ضد الإشعاع هو كود يمكن حذف أي حرف منه مع استمرار إنتاج البرنامج الأصلي دون أي حرف مفقود. وبطبيعة الحال، تكون هذه الأكواد أكثر تعقيدًا من الأكواد العادية، كما يتضح من المثال التالي في لغة روبي : [ 20 ]

eval = 'eval$q=%q(puts %q(10210/ #{ 1 1 if 1 == 21 } }/.i rescue##/1 1"[13,213].max_by{|s|s.size}#"##").gsub(/\d/){["= \47 eval$q=%q( #$q )# \47 ## \47",:eval,:instance_,"||=9"][eval$&]} exit)#' ##'instance_eval = 'eval$q=%q(puts %q(10210/ #{ 1 1 if 1 == 21 } }/.i rescue##/1 1"[13,213].max_by{|s|s.size}#"##").gsub(/\d/){["= \47 eval$q=%q( #$q )# \47 ## \47",:eval,:instance_,"||=9"][eval$&]} exit)#' ##'/ #{ eval eval if eval == instance_eval } }/ . i rescue ##/eval eval "[eval||=9,instance_eval||=9].max_by{|s|s.size}#" ##"

الجيب

باستخدام تقنيات البرمجة العلائقية ، من الممكن توليد quines تلقائيًا عن طريق تحويل المفسر (أو ما يعادله، المترجم ووقت التشغيل) للغة إلى برنامج علائقي، ثم حل نقطة ثابتة . [ 21 ]

المتغيرات

هاشكواينز

ملف التجزئة (hashquine) هو ملف يحتوي على تجزئة تشفيرية خاصة به. وهو مشابه لملف التجزئة (quine) ولكنه يعمل بشكل مختلف. فملف التجزئة هو برنامج يُنتج مصدره الخاص كمخرج، بينما ملف التجزئة عادةً ما يكون ملفًا ثابتًا، مثل صورة أو ملف ثنائي، تم إنشاؤه بحيث تظهر تجزئة التشفير الخاصة به (على سبيل المثال SHA-256) داخل الملف نفسه.

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

لا تقوم كائنات التجزئة (Hashquines) بتنفيذ أو طباعة أي شيء. إنها توضح النقاط الثابتة في دوال التجزئة المشفرة، وتُعتبر مفهومًا مشابهًا للكائنات (quines) وليست نوعًا منها بالمعنى البرمجي الدقيق.

انظر أيضاً

ملحوظات

  1. تشمل الأمثلة Bash و Perl و Python

مراجع

  1. براتلي، بول ؛ ميلو، جان (1972). "التسلية الحاسوبية: الأتمتة ذاتية التكاثر". البرمجيات: الممارسة والخبرة . 2 (4): 397-400 . doi : 10.1002/spe.4380020411 . S2CID 222194376 . 
  2. كون، برادلي م. (21 نوفمبر/تشرين الثاني 2007). "stet وAGPLv3" . مركز قانون حرية البرمجيات. مؤرشف من الأصل في 15 مارس/آذار 2008. تم الاطلاع عليه في 14 يونيو/حزيران 2008 .
  3. ^ ألمان بن (ديسمبر 2020). "جيثب جيست" .
  4. "برنامج كوين" . wiki.c2.com .
  5. "JEP 378: كتل النصوص" . openjdk.org . تم الاطلاع عليه بتاريخ 12 أكتوبر 2025 .
  6. "كود جافا بسيط، ذاتي النسخ، مع كتل نصية. يمكن تشغيل هذا الكود باستخدام جافا 15+ أو جافا 13+ مع علامات خاصة. الترخيص ملكية عامة، جميع الحقوق محفوظة" .
  7. نول، لاندون كورت. "1994/smr - أسوأ انتهاك للقواعد" . اللجنة الأولمبية الدولية للكريكيت . تم الاطلاع عليه بتاريخ 11 أكتوبر 2025 .
  8. "Makefile" . IOCCC.org . مؤرشف من الأصل بتاريخ 23 أبريل 2019. تم الاطلاع عليه بتاريخ 4 أبريل 2019 .
  9. دان بيبوني (5 فبراير 2008). "كواين من الدرجة الثالثة بثلاث لغات" .
  10. بروس إديجر. "اسألوا تُعطوا: برنامج ذاتي التكرار يمر بثلاثة أجيال، بايثون، باش، بيرل" . مؤرشف من الأصل بتاريخ 23 فبراير 2011. تم الاطلاع عليه بتاريخ 17 مارس 2011 .
  11. bm (1 فبراير 2011). "multiquine" .{{cite web}}: CS1 maint: deprecated archiveal service ( link )
  12. ^ دان بيبوني (30 يناير 2011). "كوين سنترال" .
  13. روسلان إبراهيموف (20 أبريل 2013). "Quine Ruby -> Java -> C# -> Python" (باللغة الروسية). مؤرشف من الأصل في 4 مارس 2016. تم الاطلاع عليه في 20 أبريل 2013 .
  14. شينيتشيرو هاماجي (10 نوفمبر 2007). "Quine by shinh (C C++ Ruby Python PHP Perl)" .(هذا الشخص أيضاً متعدد اللغات )
  15. كوما-مي (22 سبتمبر 2009). "برمجة أوروبروس باستخدام 11 لغة برمجة" . مؤرشف من الأصل في 29 أغسطس 2011. تم الاطلاع عليه في 17 مارس 2011 .
  16. يوسوكي إندو (2 نوفمبر 2021). "Quine Relay - برنامج يوروبوروس يدعم أكثر من 100 لغة برمجة" . جيت هاب .
  17. ^ ديفيد مادور. "كوينز (برامج ذاتية التكرار)" .
  18. ^ رينارد فان توندر (14 يناير 2020). "بنتاكين - 5 أجزاء متعددة" . جيثب .
  19. لو وانغ (21 مايو 2021). "Quine Chameleon#Variants" . GitHub .
  20. يوسوكي إندو. "كوين المقاوم للإشعاع" . جيت هاب . تم الاسترجاع في 24 فبراير 2014 .
  21. بيرد، ويليام إي.؛ هولك، إريك؛ فريدمان، دانيال ب. (9 سبتمبر 2012). "MiniKanren، مباشر وغير موسوم: توليد Quine عبر مترجمات علائقية (لؤلؤة البرمجة)" (ملف PDF) . وقائع ورشة العمل السنوية لعام 2012 حول لغة Scheme والبرمجة الوظيفية . Scheme '12. نيويورك، نيويورك، الولايات المتحدة الأمريكية: رابطة آلات الحوسبة. الصفحات 8-29 . doi : 10.1145/2661103.2661105 . ISBN  978-1-4503-1895-2.

للمزيد من القراءة