Квайны — различия между версиями
| Строка 20: | Строка 20: | ||
==Общий принцип написания квайнов== | ==Общий принцип написания квайнов== | ||
| − | Квайн состоит из двух | + | Квайн состоит из двух сегментов: <b>кода</b> и <b>данных</b>. Данные представляют собой текстовую версию кода, и, как правило, получаются из кода простым добавлением обрамляющих кавычек. Код, в свою очередь, сначала использует данные, чтобы вывести код(содержащийся в них), а затем, просто выводит данные. |
Чтобы написать простой квайн на C, мы положим в данные текстовое представление кода и при выводе данных будем экранировать знаки табуляции и переносов: | Чтобы написать простой квайн на C, мы положим в данные текстовое представление кода и при выводе данных будем экранировать знаки табуляции и переносов: | ||
<nowiki>const char data [] = | <nowiki>const char data [] = | ||
| Строка 71: | Строка 71: | ||
===Интроны=== | ===Интроны=== | ||
{{Определение | {{Определение | ||
| − | |definition='''Интроном''' (intron) называется часть данных, которая не используется для вывода кода, но сохраняющаяся в процессе саморепликации квайна. | + | |definition='''Интроном''' (intron) называется часть сегмента данных, которая не используется для вывода кода, но сохраняющаяся в процессе саморепликации квайна. |
}} | }} | ||
Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов. | Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов. | ||
| Строка 99: | Строка 99: | ||
Рассмотрим программу с двумя параметрами на языке <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>. И наконец, зафиксируем как аргумент первой исходник второй и наоборот. | Рассмотрим программу с двумя параметрами на языке <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>. И наконец, зафиксируем как аргумент первой исходник второй и наоборот. | ||
}} | }} | ||
| − | Таким образом, следуя нашему доказательству, чтобы написать мульти-квайн мы будем использовать интроны. У нас есть <tex>r</tex> программ, т.е. <tex>r</tex> | + | Таким образом, следуя нашему доказательству, чтобы написать мульти-квайн мы будем использовать интроны. У нас есть <tex>r</tex> программ, т.е. <tex>r</tex> сегментов кода (на каждом языке); кроме того, каждая из <tex>r</tex> программ имеет в дополнение к сегменту кода <tex>r</tex> сегментов данных, каждая из которых представляет собой код на определённом языке (т.е. <tex>r-1</tex> интрон + сегмент данных программы). Когда программу <tex>i</tex> (имеющую сегмент кода под номером <tex>i</tex> на языке <tex>L_i</tex>) просят вывести исходный код программы <tex>j</tex>, она использует один из своих интронов, чтобы вывести сегмент кода программы <tex>j</tex>, а затем использует все интроны и свой сегмент данных для вывода сегмента данных программы <tex>j</tex>. |
== Ссылки == | == Ссылки == | ||
* [http://www.madore.org/~david/computers/quine.html Quines (self-replicating programs)] | * [http://www.madore.org/~david/computers/quine.html Quines (self-replicating programs)] | ||
Версия 21:02, 3 января 2015
| Определение: |
| Квайном (куайном, quine) называется программа, которая выводит свой исходный код. При этом, программа не должна использовать внешние данные (например, читать файл со своим исходным кодом). |
Содержание
Происхождение названия
Название "квайн" было предложено Дугласом Хофштадтером, в его известной книге "Гёдель, Эшер, Бах: Эта бесконечная гирлянда" в честь американского логика и философа Уилларда Ван Ормана Квайна, который углублённо изучал явление косвенного самоупоминания. в частности, это явление можно проиллюстрировать следующим парадоксальным утверждением, известном как парадокс Квайна:
| Теорема (парадокс Квайна): |
"Становится ложным, когда добавляется к собственной цитате" становится ложным, когда добавляется к собственной цитате. |
Доказательство существования
| Теорема (о существовании квайнов): |
На любом языке программирования можно написать квайн |
| Доказательство: |
| Рассмотрим функцию , которая по данной программе печатает её исходный код. Очевидно, она вычислима. По теореме о неподвижной точке существует такая программа , что и ведут себя одинаково, то есть печатают свой код. Таким образом, печатает код , т.е. является квайном. |
Общий принцип написания квайнов
Квайн состоит из двух сегментов: кода и данных. Данные представляют собой текстовую версию кода, и, как правило, получаются из кода простым добавлением обрамляющих кавычек. Код, в свою очередь, сначала использует данные, чтобы вывести код(содержащийся в них), а затем, просто выводит данные. Чтобы написать простой квайн на C, мы положим в данные текстовое представление кода и при выводе данных будем экранировать знаки табуляции и переносов:
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>
int
main (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;
}
Связанные определения
Интроны
| Определение: |
| Интроном (intron) называется часть сегмента данных, которая не используется для вывода кода, но сохраняющаяся в процессе саморепликации квайна. |
Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов. В вышеприведённый квайн можно легко добавить интрон, написав перед объявлением функции
const unsigned char intron[] = "--Hello! I am an intron!---";
и добавив в код (а значит, и модифицировав данные) строчки для вывода интрона. Интроны активно используются при создании мульти-квайнов.
Мульти-квайны
| Определение: |
Би-квайном (bi-quine) называется программа, которая делает одно из двух:
|
| Определение: |
| -квайном называется программа, способная вывести исходный код программ на других языках программирования в зависимости от переданного ей аргумента, а так же свой исходный код при вызове без аргументов. |
Заметим, что требование, чтобы программы были на разных языках программирования важно, т.к. иначе все программы смогут иметь один и тот же код.
| Теорема (о существовании мульти-квайнов): |
На любом языке программирования можно написать мульти-квайн |
| Доказательство: |
|
Докажем утверждение для би-квайна, для большего количества языков доказательство будет выглядеть аналогично. Рассмотрим программу с двумя параметрами на языке , которая выводит первый параметр при обычном запуске и второй - при запуске со спец. аргументом. По теореме о неподвижной точке мы можем зафиксировать первый параметр и сказать, что он будет равен исходному коду нашей программы. Таким образом, мы получим программу с одним параметром, которая выводит свой код при запуске без аргументов и выводит параметр при запуске со спец. аргументом. Проделаем то же самое для программы на языке . И наконец, зафиксируем как аргумент первой исходник второй и наоборот. |
Таким образом, следуя нашему доказательству, чтобы написать мульти-квайн мы будем использовать интроны. У нас есть программ, т.е. сегментов кода (на каждом языке); кроме того, каждая из программ имеет в дополнение к сегменту кода сегментов данных, каждая из которых представляет собой код на определённом языке (т.е. интрон + сегмент данных программы). Когда программу (имеющую сегмент кода под номером на языке ) просят вывести исходный код программы , она использует один из своих интронов, чтобы вывести сегмент кода программы , а затем использует все интроны и свой сегмент данных для вывода сегмента данных программы .