Квайны — различия между версиями

Материал из Викиконспекты
Перейти к: навигация, поиск
м (Интроны)
Строка 2: Строка 2:
 
|definition='''Квайном''' (англ. ''quine'')<ref name=quineName/> называется программа, которая выводит свой исходный код. При этом, программа не должна использовать внешние данные (например, читать файл со своим исходным кодом).
 
|definition='''Квайном''' (англ. ''quine'')<ref name=quineName/> называется программа, которая выводит свой исходный код. При этом, программа не должна использовать внешние данные (например, читать файл со своим исходным кодом).
 
}}
 
}}
 
==Общий принцип написания квайнов==
 
 
Квайн состоит из двух сегментов: <b>кода</b> и <b>данных</b>. Данные представляют собой текстовую версию кода, и, как правило, получаются из кода простым добавлением обрамляющих кавычек. Код, в свою очередь, сначала использует данные, чтобы вывести код(содержащийся в них), а затем, просто выводит данные.
 
Квайн состоит из двух сегментов: <b>кода</b> и <b>данных</b>. Данные представляют собой текстовую версию кода, и, как правило, получаются из кода простым добавлением обрамляющих кавычек. Код, в свою очередь, сначала использует данные, чтобы вывести код(содержащийся в них), а затем, просто выводит данные.
  
Строка 10: Строка 8:
 
==Интроны==
 
==Интроны==
 
{{Определение
 
{{Определение
|definition='''Интроном''' (англ. ''intron'') называется часть сегмента данных, которая не используется для вывода кода, но сохраняющаяся в процессе саморепликации квайна.
+
|definition='''Интроном''' (англ. ''intron'')<ref name=intronName/> называется часть сегмента данных, которая не используется для вывода кода, но сохраняющаяся в процессе саморепликации квайна.
 
}}
 
}}
Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов.
 
 
 
==Мульти-квайны==
 
==Мульти-квайны==
 
{{Определение
 
{{Определение
Строка 19: Строка 15:
 
*при обычном запуске она выводит свой исходный код,
 
*при обычном запуске она выводит свой исходный код,
 
*при запуске с особым аргументом она выводит исходный код своего "брата" на другом языке программирования.
 
*при запуске с особым аргументом она выводит исходный код своего "брата" на другом языке программирования.
Её брат делает то же самое: выводит свой код при запуске без аргументов и выводит код оригинальной программы при запуске с переданным спец. аргументом.
+
Её брат делает то же самое: выводит свой код при запуске без аргументов и выводит код оригинальной программы при запуске с переданным специальным аргументом.
 
}}
 
}}
 
{{Определение
 
{{Определение
Строка 32: Строка 28:
 
|proof= Докажем утверждение для би-квайна, для большего количества языков доказательство будет выглядеть аналогично.
 
|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>. И наконец, зафиксируем как параметр первой исходник второй и наоборот.  
+
Рассмотрим программу с двумя параметрами на языке <tex>L_1</tex>, которая выводит первый параметр при обычном запуске и второй - при запуске со спец. аргументом. По [[Теорема о рекурсии|теореме о рекурсии]] мы можем зафиксировать первый параметр и сказать, что он будет равен исходному коду нашей программы. Таким образом, мы получим программу с одним параметром, которая выводит свой код при запуске без аргументов и выводит параметр при запуске со спец. аргументом. Проделаем то же самое для программы на языке <tex>L_2</tex>. И наконец, зафиксируем как параметр первой исходный код второй и наоборот.  
 
}}
 
}}
  
 
===Принцип написания===
 
===Принцип написания===
 
Будем следовать доказательству и напишем мульти-квайн для двух языков. Далее покажем, как добавить новый язык.
 
Будем следовать доказательству и напишем мульти-квайн для двух языков. Далее покажем, как добавить новый язык.
# напишем для каждого языка "полу-квайн": <tex>P(p,arg):
+
* напишем для каждого языка "полу-квайн":
\left\{
+
<table>
\begin{array}{l l}
+
<tr>
P(p,"shazam!") \rightarrow print(p); \\
+
<td><center><tex>P_1(p,arg)</tex></center></td>
                P(p,null) \rightarrow print(P.getSrc());
+
<td><center><tex>P_2(p,arg)</tex></center></td>
\end{array}
+
</tr>
\right.
+
<tr>
</tex>
+
<td><code><font size = "2em">
# добавим код каждой из программ интроном в код другой
+
if (arg == "print second!")
# модифицируем каждую из программ, чтобы вместо <tex>p</tex> она выводила интрон: <tex>P(arg):
+
    print(p)
\left\{
+
else
\begin{array}{l l}
+
    print(getSrc())
P("shazam!") \rightarrow print(intron); \\
+
</font></code></td>
                P(null) \rightarrow print(P.getSrc());
+
<td><code><font size = "2em">
\end{array}
+
  if (arg == "print first!")
\right.
+
    print(p)
</tex>
+
else
 +
    print(getSrc())  
 +
</font></code></td>
 +
</tr>
 +
</table>
 +
* добавим код каждой из программ интроном в код другой
 +
* модифицируем каждую из программ, чтобы вместо <tex>p</tex> она выводила интрон:  
 +
<table>
 +
<tr>
 +
<td><center><tex>P_1(arg)</tex></center></td>
 +
<td><center><tex>P_2(arg)</tex></center></td>
 +
</tr>
 +
<tr>
 +
<td><code><font size = "2em">
 +
if (arg == "print second!")
 +
    print(p2_intron)
 +
else
 +
    print(getSrc())
 +
</font></code></td>
 +
<td><code><font size = "2em">
 +
  if (arg == "print first!")
 +
    print(p1_intron)
 +
else
 +
    print(getSrc())  
 +
</font></code></td>
 +
</tr>
 +
</table>
 
Теперь добавим третий язык:
 
Теперь добавим третий язык:
# напишем для него "полу-квайн", но уже с двумя параметрами и тремя возможными выводами:<tex>P_3(p,arg):  
+
* напишем для него "полу-квайн", но уже с двумя параметрами и тремя возможными выводами:
\left\{
+
<code><font size = "2em">
\begin{array}{l l}
+
<tex>P_3(p1,p2,arg)</tex>:
P_3(p1,p2,"shazam!") \rightarrow print(p1);  \\
+
    if (arg == "print first!")
                P_3(p1,p2,"cadabra!") \rightarrow print(p2); \\
+
        print(p1)
                P_3(p1,p2,null) \rightarrow print(P_3.getSrc());
+
    elseif (arg == "print second!")
\end{array}
+
        print(p2)
\right.
+
    else
</tex>
+
        print(getSrc())  
# добавим третье условие в два уже существующих квайна: <tex>P(p,arg):
+
</font></code>
\left\{
+
* добавим третье условие в два уже существующих квайна:  
\begin{array}{l l}
+
<table>
P(p,"shazam!") \rightarrow print(intron); \\
+
<tr>
                P(p,"cadabra!") \rightarrow print(p); \\
+
<td><center><tex>P_1(p,arg)</tex></center></td>
                P(p,null) \rightarrow print(P.getSrc());
+
<td><center><tex>P_2(p,arg)</tex></center></td>
\end{array}
+
</tr>
\right.
+
<tr>
</tex>
+
<td><code><font size = "2em">
# подставим код первых двух интронами в третью, а код третьей - вторым интроном в каждую из двух первых:
+
if (arg == "print second!")
<tex>P(arg):
+
    print(p2_intron)
\left\{
+
  elseif (arg == "print third!")
\begin{array}{l l}
+
    print(p)
P("shazam!") \rightarrow print(intron1); \\
+
else
                P("cadabra!") \rightarrow print(intron2); \\
+
    print(getSrc())
                P(null) \rightarrow print(P.getSrc());
+
</font></code></td>
\end{array}
+
<td><code><font size = "2em">
\right.
+
if (arg == "print first!")
</tex>
+
    print(p1_intron)
 +
elseif (arg == "print third!")
 +
    print(p)
 +
else
 +
    print(getSrc())
 +
</font></code></td>
 +
</tr>
 +
</table>
 +
* подставим код первых двух интронами в третью, а код третьей - вторым интроном в каждую из двух первых:
 +
<table>
 +
<tr>
 +
<td><center><tex>P_1(arg)</tex></center></td>
 +
<td><center><tex>P_2(arg)</tex></center></td>
 +
<td><center><tex>P_3(arg)</tex></center></td>
 +
</tr>
 +
<tr>
 +
<td><code><font size = "2em">
 +
if (arg == "print second!")
 +
    print(p2_intron)
 +
elseif (arg == "print third!")
 +
    print(p3_intron)
 +
else
 +
    print(getSrc())
 +
</font></code></td>
 +
<td><code><font size = "2em">
 +
if (arg == "print first!")
 +
    print(p1_intron)
 +
elseif (arg == "print third!")
 +
    print(p3_intron)
 +
  else
 +
    print(getSrc())
 +
</font></code></td>
 +
<td><code><font size = "2em">
 +
if (arg == "print first!")
 +
    print(p1_intron)
 +
elseif (arg == "print second!")
 +
    print(p2_intron)
 +
else
 +
    print(getSrc())
 +
</font></code></td>
 +
</tr>
 +
</table>
  
 
== Примечания ==
 
== Примечания ==
 
<references>
 
<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=quineName>Название "квайн" было предложено [http://ru.wikipedia.org/wiki/Хофштадтер,_Дуглас Дугласом Хофштадтером], в его известной книге "Гёдель, Эшер, Бах: Эта бесконечная гирлянда" в честь американского логика и философа  [http://ru.wikipedia.org/wiki/Куайн,_Уиллард_Ван_Орман Уилларда Ван Ормана Квайна], который углублённо изучал явление [http://en.wikipedia.org/wiki/Indirect_self-reference косвенного самоупоминания].</ref>
 +
<ref name=intronName>Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов.</ref>
 
</references>
 
</references>
  
 
== Источники информации ==
 
== Источники информации ==
* [http://www.madore.org/~david/computers/quine.html Madore.org - Quines (self-replicating programs)]
+
* [http://www.madore.org/~david/computers/quine.html Madore.org &mdash; Quines (self-replicating programs)]
* [http://habrahabr.ru/post/186782/ Хабрахабр - Эстафета из 50 квайнов]
+
* [http://habrahabr.ru/post/186782/ Хабрахабр &mdash; Эстафета из 50 квайнов]
* [http://habrahabr.ru/post/188378/ Хабрахабр - Мультиязыковые квайны]
+
* [http://habrahabr.ru/post/188378/ Хабрахабр &mdash; Мультиязыковые квайны]
* [http://habrahabr.ru/post/128191/ Хабрахабр - Как писать квайны]
+
* [http://habrahabr.ru/post/128191/ Хабрахабр &mdash; Как писать квайны]
  
 
[[Категория: Теория формальных языков]]
 
[[Категория: Теория формальных языков]]
 
[[Категория: Теория вычислимости]]
 
[[Категория: Теория вычислимости]]

Версия 16:09, 6 января 2015

Определение:
Квайном (англ. quine)[1] называется программа, которая выводит свой исходный код. При этом, программа не должна использовать внешние данные (например, читать файл со своим исходным кодом).

Квайн состоит из двух сегментов: кода и данных. Данные представляют собой текстовую версию кода, и, как правило, получаются из кода простым добавлением обрамляющих кавычек. Код, в свою очередь, сначала использует данные, чтобы вывести код(содержащийся в них), а затем, просто выводит данные.

Формально общий принцип написания квайнов содержится в доказательстве теоремы о рекурсии. Далее будет рассмотрено понятие мульти-квайна.

Интроны

Определение:
Интроном (англ. intron)[2] называется часть сегмента данных, которая не используется для вывода кода, но сохраняющаяся в процессе саморепликации квайна.

Мульти-квайны

Определение:
Би-квайном (англ. bi-quine) называется программа, которая делает одно из двух:
  • при обычном запуске она выводит свой исходный код,
  • при запуске с особым аргументом она выводит исходный код своего "брата" на другом языке программирования.
Её брат делает то же самое: выводит свой код при запуске без аргументов и выводит код оригинальной программы при запуске с переданным специальным аргументом.


Определение:
[math]R[/math]-квайном (англ. [math]R[/math]-quine) называется программа, способная вывести исходный код [math]R-1[/math] программ на других языках программирования в зависимости от переданного ей аргумента, а так же свой исходный код при вызове без аргументов.

Заметим, что требование, чтобы программы были на разных языках программирования важно, т.к. иначе все программы смогут иметь один и тот же код.

Теорема (о существовании мульти-квайнов):
На любом языке программирования можно написать мульти-квайн
Доказательство:
[math]\triangleright[/math]

Докажем утверждение для би-квайна, для большего количества языков доказательство будет выглядеть аналогично.

Рассмотрим программу с двумя параметрами на языке [math]L_1[/math], которая выводит первый параметр при обычном запуске и второй - при запуске со спец. аргументом. По теореме о рекурсии мы можем зафиксировать первый параметр и сказать, что он будет равен исходному коду нашей программы. Таким образом, мы получим программу с одним параметром, которая выводит свой код при запуске без аргументов и выводит параметр при запуске со спец. аргументом. Проделаем то же самое для программы на языке [math]L_2[/math]. И наконец, зафиксируем как параметр первой исходный код второй и наоборот.
[math]\triangleleft[/math]

Принцип написания

Будем следовать доказательству и напишем мульти-квайн для двух языков. Далее покажем, как добавить новый язык.

  • напишем для каждого языка "полу-квайн":
[math]P_1(p,arg)[/math]
[math]P_2(p,arg)[/math]
if (arg == "print second!")
    print(p)
else
    print(getSrc()) 
if (arg == "print first!")
    print(p)
else
    print(getSrc()) 
  • добавим код каждой из программ интроном в код другой
  • модифицируем каждую из программ, чтобы вместо [math]p[/math] она выводила интрон:
[math]P_1(arg)[/math]
[math]P_2(arg)[/math]
if (arg == "print second!")
    print(p2_intron)
else
    print(getSrc()) 
if (arg == "print first!")
    print(p1_intron)
else
    print(getSrc()) 

Теперь добавим третий язык:

  • напишем для него "полу-квайн", но уже с двумя параметрами и тремя возможными выводами:

[math]P_3(p1,p2,arg)[/math]:
    if (arg == "print first!")
        print(p1)
    elseif (arg == "print second!")
        print(p2)
    else
        print(getSrc()) 

  • добавим третье условие в два уже существующих квайна:
[math]P_1(p,arg)[/math]
[math]P_2(p,arg)[/math]
if (arg == "print second!")
    print(p2_intron)
elseif (arg == "print third!")
    print(p)
else
    print(getSrc())
if (arg == "print first!")
    print(p1_intron)
elseif (arg == "print third!")
    print(p)
else
    print(getSrc())
  • подставим код первых двух интронами в третью, а код третьей - вторым интроном в каждую из двух первых:
[math]P_1(arg)[/math]
[math]P_2(arg)[/math]
[math]P_3(arg)[/math]
if (arg == "print second!")
    print(p2_intron)
elseif (arg == "print third!")
    print(p3_intron)
else
    print(getSrc())
if (arg == "print first!")
    print(p1_intron)
elseif (arg == "print third!")
    print(p3_intron)
else
    print(getSrc())
if (arg == "print first!")
    print(p1_intron)
elseif (arg == "print second!")
    print(p2_intron)
else
    print(getSrc())

Примечания

  1. Название "квайн" было предложено Дугласом Хофштадтером, в его известной книге "Гёдель, Эшер, Бах: Эта бесконечная гирлянда" в честь американского логика и философа Уилларда Ван Ормана Квайна, который углублённо изучал явление косвенного самоупоминания.
  2. Название пришло из биологии, где интронами называются части ДНК, не участвующие в синтезе протеинов.

Источники информации