Как написать самовоспроизводящийся код (печатает исходный код на exec)?

Я видел множество решений этой проблемы на основе C/C++, где мы должны написать программу, которая после выполнения печатает свой собственный источник.

некоторые решения -

http://www.cprogramming.com/challenges/solutions/self_print.html

Решение Quine Page на многих языках

В сети есть еще много решений, каждое из которых отличается от другого. Интересно, как мы подходим к такой проблеме, что идет в голову тому, кто ее решает. Дайте мне некоторое представление об этой проблеме... Хотя решения в интерпретируемых языках, таких как perl, php, ruby ​​и т. Д., Могут быть простыми... я хотел бы знать, как можно разработать его на скомпилированных языках...

11 ответов

Решение

Помимо обмана… нет никакой разницы между компилируемыми и интерпретируемыми языками.

Общий подход к кваи довольно прост. Во-первых, какой бы ни была программа, в какой-то момент она должна что-то напечатать:

Распечатать...

Однако, что это должно напечатать? Сам. Так что нужно распечатать команду "печать":

печать "печать..."

Что должно быть напечатано дальше? Ну, в то время как программа росла, поэтому она должна напечатать строку, начинающуюся также с "print":

печать "печать \" печать... \ ""

Теперь программа снова выросла, так что есть еще что напечатать:

печать "печать \" печать \\\ "... \\\" \ ""

И так далее. С каждым добавленным кодом появляется больше кода для печати. Этот подход ни к чему не приводит, но он обнаруживает интересную закономерность: строка "print \" повторяется снова и снова. Было бы неплохо поместить повторяющуюся часть в переменную:

a = "print \" "
распечатать

Однако программа просто изменилась, поэтому нам нужно настроить:

a = "a =... \ nprint a"
распечатать

Когда мы сейчас пытаемся заполнить "...", мы сталкиваемся с теми же проблемами, что и раньше. В конечном итоге мы хотим написать что-то вроде этого:

a = "a =" + (цитируемое содержимое a) + "\nprint a"
распечатать

Но это невозможно, потому что даже если бы у нас была такая функция quoted() для цитирования, есть еще проблема, которую мы определяем a с точки зрения самого себя:

a = "a =" + quoted (a) + "\nprint a"
распечатать

Таким образом, единственное, что мы можем сделать, это поместить заполнитель в a:

a = "a = @ \ nprint a"
распечатать

И в этом весь трюк! Все остальное теперь понятно. Просто замените заполнитель цитируемым содержанием a:

a = "a = @ \ nprint a"
print a.replace ("@", цитата (а))

Поскольку мы изменили код, нам нужно настроить строку:

a = "a = @ \ nprint a.replace (\" @ \ ", quoted (a))"
print a.replace ("@", цитата (а))

И это все! Все квины на всех языках работают таким образом (кроме мошеннических).

Что ж, вы должны убедиться, что вы заменили только первый случай использования заполнителя. И если вы используете второе место, вы можете избежать цитирования строки.

Но это мелкие проблемы, которые легко решить. Если факт, реализация quoted() а также replace()являются единственными деталями, в которых различные цитрусовые действительно отличаются.


Making заставив программу прочитать исходный файл

Есть несколько разных стратегий написания цитат. Очевидным является просто написать код, который открывает код и печатает его. Но более интересные из них включают языковые функции, которые допускают самостоятельное встраивание, такие как функция% s в стиле printf во многих языках. Вы должны выяснить, как встраивать что-то, чтобы оно в конечном итоге разрешалось встраивать запрос. Я подозреваю, как и палиндромы, много проб и ошибок.

Пара учебных пособий по квинам: здесь и здесь.

Также вы можете изучить, как работает игра Core Wars. Я думаю, это был бы хороший пример.

Для забавы я придумал один в Схеме, которым я очень гордился около 5 минут, пока не обнаружил, что он был обнаружен ранее. В любом случае, есть небольшие изменения в "правилах" игры для лучшего учета двойственности данных и кода в Лиспе: вместо распечатки исходного кода программы это S-выражение, которое возвращает себя:

((lambda (x) (list x `',x)) '(lambda (x) (list x `',x)))

Тот, что в Википедии, имеет ту же концепцию, но с немного другим (более подробным) механизмом цитирования. Мне больше нравится мой, хотя.

Сайт с множеством примеров:
http://www.nyx.net/~gthompso/quine.htm

Обычный подход (когда вы не можете обмануть *) состоит в том, чтобы написать что-то, что кодирует его источник в строковой константе, затем распечатывает эту константу дважды: один раз как строковый литерал и один раз как код. Это звучит так: "Каждый раз, когда я пишу строку кода, я должен написать другую, чтобы распечатать ее!" проблема.

"Обман" включает в себя: - использование интерпретированного языка и простую загрузку источника и его печать - файлы длиной 0 байт, которые допустимы в некоторых языках, таких как C.

В Python вы можете написать:

s='c=chr(39);print"s="+c+s+c+";"+s';c=chr(39);print"s="+c+s+c+";"+s

вдохновлен этим псевдокодом самопечати:

Print the following line twice, the second time with quotes.
"Print the following line twice, the second time with quotes."

Вы можете найти немало решений здесь: http://forums.thedailywtf.com/forums/p/5232/147528.aspx

Как насчет чтения и печати вашего исходного кода? Это совсем не сложно! Вот один в php:

<?php
{
header("Content-Type: text/plain");
    $f=fopen("5.php","r");
    while(!feof($f))
    {
        echo fgetc($f);
    } 
    fclose($f);
}
?>

Одна идея подумать о кодировании и о том, как придать что-то двойное значение, чтобы его можно было использовать для вывода чего-либо в нескольких формах. Есть также кавет, что этот тип проблемы идет с ограничениями, чтобы усложнить его, поскольку без каких-либо правил, кроме самой программы, пустая программа является решением.

Я сделал пример AS3 для тех, кто заинтересован в этом

var program = "var program = @; function main(){trace(program.replace('@', 

String.fromCharCode(34) + program + String.fromCharCode(34)))} main()"; 
function main(){
   trace(program.replace('@', String.fromCharCode(34) + program + String.fromCharCode(34)))
}
main()

В bash это действительно просто

сенсорный тест; chmod oug+x test; ./контрольная работа

Пустой файл, пустой вывод

В рубине:

помещает File.read(_ _ FILE _ _)

Другие вопросы по тегам