Изменения

Перейти к: навигация, поиск

Квайны

667 байт убрано, 12:08, 23 июня 2020
Нет описания правки
{{Определение
|definition='''Квайном''' (англ. <i>''quine</i>'')<ref name=quineName/> называется программа, которая выводит свой исходный код. При этом, программа не должна использовать внешние данные (например, читать файл со своим исходным кодом)<ref name=quineExists/>.
}}
Стоит отметить, что программы, использующие для чтения своего кода файловую систему, квайнами не считаются. Например, программа на BASIC вида
<font size = "2em">
10 LIST
</font>
выводит на экран свой исходный код, поскольку команда <tex>\mathtt{LIST}</tex> просит среду исполнения вывести в консоль текущую программу (эта функция была необходима для программистов, так как код программы зачастую не мог поместиться на консоль 80x25 символов).
==Общий принцип написания квайнов==Квайн состоит из двух сегментов: <b>кода</b> и <b>данных</b>. Данные представляют собой текстовую версию кода, и, как правило, получаются из кода простым добавлением обрамляющих кавычек. Код, в свою очередь, сначала использует данные, чтобы вывести код(, содержащийся в них), а затем, просто выводит данные.Чтобы написать простой квайн на C, мы положим в данные текстовое представление кода и при выводе данных будем экранировать знаки табуляции и переносов: <nowiki>const char data [] ="#include <stdio.h>\n\nint\nmain (void)\n{\n unsigned int i;\n\n p""rintf (\"const char data [] =\");\n for ( i=0 ; data[i] ; i++ "")\n {\n if ( i%60 == 0 )\n\tprintf (\"\\n\\\"\");\n switc""h ( data[i] )\n\t{\n\tcase '\\\\':\n\tcase '\"':\n\t printf (\"\\\\%c\", d""ata[i]);\n\t break;\n\tcase '\\n':\n\t printf (\"\\\\n\");\n\t break;\n""\tcase '\\t':\n\t printf (\"\\\\t\");\n\t break;\n\tdefault:\n\t printf"" (\"%c\", data[i]);\n\t}\n if ( i%60 == 59 || !data[i+1] )\n\t""printf (\"\\\"\");\n }\n printf (\";\\n\\n\");\n for ( i=0 ; data[""i] ; i++ )\n putchar (data[i]);\n return 0;\n}\n";
#include <stdioФормально общий принцип написания квайнов содержится в доказательстве [[Теорема о рекурсии|теоремы о рекурсии]]. Далее будет рассмотрено понятие мультиквайна.h>
intmain (void){ unsigned int i;  printf ("const char data [] ="); for ( i=0 ; data[i] ; i++ ) { if ( i%60 Мультиквайны== 0 ) printf ("\n\""); switch ( data[i] ) { case '\\': case '"': printf ("\\%c", data[i]); break; case '\n': printf ("\\n"); break; case '\t': printf ("\\t"); break; default: printf ("%c", data[i]); } if ( i%60 == 59 || !data[i+1] ) printf ("\""); } printf (";\n\n"); for ( i=0 ; data[i] ; i++ ) putchar (data[i]); return 0;}</nowiki> Можно представить сегмент данных как некий шифр, который можно расшифровать двумя способами. В результате расшифровки первым способом получится строковое представление собственно сегмента данных, при расшифровке вторым способом получится строковое представление сегмента кода. Объединив результаты этих расшифровок, мы получим строку, в которой содержится весь исходный код программы. ==Связанные определения=====Интроны===
{{Определение
|definition='''Интроном''' (англ. ''intron'') <ref name=intronName/> называется часть сегмента данных, которая не используется для вывода кода, но сохраняющаяся сохраняется в процессе саморепликации квайна.
}}
Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов.
В вышеприведённый квайн можно легко добавить интрон, написав перед объявлением функции
<nowiki>const unsigned char intron[] = "--Hello! I am an intron!---";</nowiki>
и добавив в код (а значит, и модифицировав данные) строчки для вывода интрона.
Интроны активно используются при создании мульти-квайнов.
 
===Мульти-квайны===
{{Определение
|definition='''Би-квайномБиквайном''' (bi-quineангл. ''biquine'') называется программа, которая делает одно из двух:
*при обычном запуске она выводит свой исходный код,
*при запуске с особым аргументом она выводит исходный код своего "брата" на другом языке программирования.
Её "брат " делает то же самое: выводит свой код при запуске без аргументов и выводит код оригинальной программы при запуске с переданным спец. специальным аргументом.
}}
{{Определение
|definition='''<tex>R</tex>-квайном''' (англ. <tex>R</tex>-''quine'') называется программа, способная вывести исходный код <tex>R-1</tex> программ на других языках программирования в зависимости от переданного ей аргумента, а так же также свой исходный код при вызове без аргументов.
}}
Заметим, что требование, чтобы программы были на разных языках программирования , важно, т.к. иначе все программы смогут иметь один и тот же код. 
{{
Теорема
|about=о существовании мульти-квайновмультиквайнов|statement= На любом языке программирования можно написать мульти-квайнмультиквайн.|proof= Докажем утверждение для би-квайна, для биквайна. Для большего количества языков доказательство будет выглядеть аналогично.
Рассмотрим программу с двумя параметрами на языке <tex>L_1</tex>, которая выводит первый параметр при обычном запуске и второй {{- --}} при запуске со спец. аргументом. По [http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B5%D0%BE%D1%80%D0%B5%D0%BC%D0%B0_%D0%BE_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D0%B8#.D0.A2.D0.B5.D0.BE.D1.80.D0.B5.D0.BC.D0.B0_.D0.BE_.D0.BD.D0.B5.D0.BF.D0.BE.D0.B4.D0.B2.D0.B8.D0.B6.D0.BD.D0.BE.D0.B9_.D1.82.D0.BE.D1.87.D0.BA.D0.B5 [Теорема о рекурсии|теореме о неподвижной точкерекурсии]] мы можем зафиксировать первый параметр и сказать, что он будет равен исходному коду нашей программы. Таким образом, мы получим программу с одним параметром, которая выводит свой код при запуске без аргументов и выводит параметр при запуске со спец. аргументом. Проделаем то же самое для программы на языке <tex>L_2</tex>. И , наконец, зафиксируем как параметр первой исходник программы исходный код второй и наоборот.
}}
===Принцип написания===Будем следовать доказательству и напишем мульти-квайн мультиквайн для двух языков. Далее покажем, как добавить новый язык.# * напишем для каждого языка "полу-квайнполуквайн": <table><tr><td><font size = "2em"> <tex>PP_1(p,arg)</tex>: \left\{ '''if''' (arg == "print second!") '''print'''(p) \begin{array}{l l} '''else''' P '''print'''(getSrc()) </font></td><td><font size = "2em"> <tex>P_2(p,arg)</tex>: '''if''' (arg == "shazamprint first!") \rightarrow '''print'''(p); \\ P(p,null) \rightarrow '''else''' '''print'''(P.getSrc()); \end{array}</font></td> \right.</tr></textable># добавим * подставим код каждой из программ интроном второй программы в код другойпервую:<font size = "2em"> # модифицируем каждую из программ, чтобы вместо <tex>P_1(p,arg)</tex> она выводила интрон: '''if''' (arg == "print second!") '''print'''(<tex>PP_2</tex>(p, arg).getSrc()) '''else''' '''print'''(getSrc()) </font>* применим [[Теорема о рекурсии|теорему о рекурсии]] и заменим параметр на исходный код программы: \left\{<font size = "2em"> \begin{array}{l l} <tex>P_1(arg)</tex>: P '''if''' (arg == "shazamprint second!") \rightarrow '''print'''(intron<tex>P_2</tex>(getSrc(), arg); \\ P.getSrc(null) \rightarrow ) '''else''' '''print'''(P.getSrc()); \end{array}</font> \rightВторая программа может быть получена запуском первой с нужным аргументом.</tex>
Теперь добавим третий язык:
# * напишем для него "полу-квайнполуквайн", но уже с двумя параметрами и тремя возможными выводами:<font size = "2em"> <tex>P_3(pp1,p2,arg)</tex>: \left\{ \begin{array}{l l} P_3 '''if''' (p1,p2,arg == "shazamprint first!") \rightarrow '''print'''(p1); \\ P_3 '''elseif''' (p1,p2,arg == "cadabraprint second!") \rightarrow '''print'''(p2); \\ P_3(p1,p2,null) \rightarrow '''else''' '''print'''(P_3.getSrc()); \end{array} \right.</texfont># * добавим третье условие параметр в два уже существующих квайна: <table><tr><td><font size = "2em"> <tex>PP_1(p,arg)</tex>: \left\{ '''if''' (arg == "print second!") \begin{array}{l l} P '''print'''(<tex>P_2</tex>(p,getSrc(), arg).getSrc()) '''elseif''' (arg == "shazamprint third!") \rightarrow '''print'''(p) '''else''' '''print'''(getSrc(intron); ) </font></td><td><font size = "2em"> \\ P<tex>P_2(p,arg)</tex>: '''if''' (arg == "cadabraprint first!") \rightarrow '''print'''(<tex>P_1</tex>(p, getSrc(), arg).getSrc()) '''elseif''' (arg == "print third!"); \\ P '''print'''(p,null) \rightarrow '''else''' '''print'''(P.getSrc()); \end{array}</font></td> \right.</tr></textable># * подставим код первых двух интронами в третью, а код третьей - вторым интроном в каждую из двух первых:<font size = "2em"> <tex>PP_3(p1,p2,arg)</tex>: \left\{ \begin{array}{l l} P '''if''' (arg == "shazamprint first!") \rightarrow '''print'''(<tex>P_1</tex>(p1, arg).getSrc(intron1); \\) P '''elseif''' (arg == "cadabraprint second!") \rightarrow '''print'''(intron2<tex>P_2</tex>(p2, arg); \\ P.getSrc(null) \rightarrow ) '''else''' '''print'''(P.getSrc()); \end{array} \right.</texfont>
* применим [[Теорема о рекурсии|теорему о рекурсии]] и заменим оба параметра на исходный код программы:<font size == Источники информации "2em"> <tex>P_3(arg)</tex>: '''if''' (arg =="print first!")* [http: '''print'''(<tex>P_1<//wwwtex>(getSrc(), arg).madore.orggetSrc()) '''elseif''' (arg == "print second!") '''print'''(<tex>P_2</~david/computers/quinetex>(getSrc(), arg).html Madore.org - Quines getSrc(self-replicating programs)]) '''else'''* [http://habrahabr.ru/post/186782/ Хабрахабр - Эстафета из 50 квайнов] '''print'''(getSrc()) * [http://habrahabr.ru</post/188378/ Хабрахабр - Мультиязыковые квайны]font>* [http://habrahabrДве оставшиеся программы будут выглядеть аналогично и смогут быть получены путём запуска третьей с каждым из возможных аргументов.ru/post/128191/ Хабрахабр - Как писать квайны]
== Примечания ==
<references>
<ref name=quineName>Название "квайн" было предложено [http://ru.wikipedia.org/wiki/Хофштадтер,_Дуглас Дугласом Хофштадтером], в его известной книге "Гёдель, Эшер, Бах: Эта бесконечная гирлянда" в честь американского логика и философа [http://ru.wikipedia.org/wiki/Куайн,_Уиллард_Ван_Орман Уилларда Ван Ормана Квайна], который углублённо изучал явление [http://en.wikipedia.org/wiki/Indirect_self-reference косвенного самоупоминания].</ref>
<ref name=quineExistsintronName>Из [http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D0%B5%D0%BE%D1%80%D0%B5%D0%BC%D0%B0_%D0%BE_%D1%80%D0%B5%D0%BA%D1%83%D1%80%D1%81%D0%B8%D0%B8#.D0.A2.D0.B5.D0.BE.D1.80.D0.B5.D0.BC.D0.B0_.D0.BE_.D1.80.D0.B5.D0.BA.D1.83.D1.80.D1.81.D0.B8.D0.B8 теоремы Клини о рекурсии] очевидно следуетНазвание пришло из биологии, что квайн можно написать на любом Тьюринг-полном языкегде интронами называются части ДНК, не участвующие в синтезе протеинов.</ref>
</references>
== Источники информации ==
* [http://www.madore.org/~david/computers/quine.html Madore.org &mdash; Quines (self-replicating programs)]
* [http://habrahabr.ru/post/186782/ Хабрахабр &mdash; Эстафета из 50 квайнов]
* [http://habrahabr.ru/post/188378/ Хабрахабр &mdash; Мультиязыковые квайны]
* [http://habrahabr.ru/post/128191/ Хабрахабр &mdash; Как писать квайны]
* [http://en.wikipedia.org/wiki/Quine_(computing)#Multiquines Wikipedia &mdash; Multi-quines]
[[Категория: Теория формальных языков]]
[[Категория: Теория вычислимости]]
693
правки

Навигация