Как написать самовоспроизводящийся код (печатает источник на exec)?
Я видел много C/с++ решения этой проблемы, где мы должны написать программу, которая при выполнении печатает свой собственный источник.
некоторые решения --
http://www.cprogramming.com/challenges/solutions/self_print.html
Quine Page решение на многих языках
в сети есть еще много решений, отличающихся друг от друга. Интересно, как мы подходим к такому проблема в том, что происходит в голове того, кто ее решает. Дайте мне некоторое представление об этой проблеме... В то время как решения на интерпретируемых языках, таких как perl, php, ruby и т. д., могут быть легкими... я хотел бы знать, как можно разработать его на скомпилированных языках...
13 ответов
помимо cheating1 нет никакой разницы между скомпилированными и интерпретируемыми языками.
общий подход к quines довольно легко. Во-первых, как бы ни выглядела программа, в какой-то момент она должна что-то напечатать:
print ...
однако, что он должен печатать? Себя. Поэтому необходимо распечатать команду "print":
print "print ..."
что он должен печатать дальше? Ну, а тем временем программа росла, поэтому ей нужно распечатать строку, начинающуюся с "печать" тоже:
print "print \"print ...\""
теперь программа снова выросла, так что снова больше печатать:
print "print \"print \\"...\\"\""
и так далее. С каждым добавленным кодом появляется все больше кода для печати. Этот подход ведет в никуда., но в нем обнаруживается интересная закономерность: Строка "print \ "" повторяется снова и снова. Было бы неплохо поставить повторяющуюся часть в переменную:
a = "print \"" print a
однако программа только что изменилась, так что нам нужно приспособиться. a:
a = "a = ...\nprint a" print a
когда мы теперь пытаемся заполнить "...", мы сталкиваемся с теми же проблемами, что и раньше. В конечном счете, мы хотим написать что-то вроде этого:
a = "a = " + (quoted contents of a) + "\nprint a" print a
но это невозможно,
потому что даже если бы у нас была такая функция quoted()
для закавычить,
есть еще проблема, которую мы определяем a
в:
a = "a = " + quoted(a) + "\nprint a" print a
таким образом, единственное, что мы можем сделать, это поместить держатель места в a
:
a = "a = @\nprint a" print a
и это все трик!
Все остальное теперь ясно.
Просто замените держатель места
с цитируемым содержанием a
:
a = "a = @\nprint a" print a.replace("@", quoted(a))
так как мы изменили код, нам нужно настроить строку:
a = "a = @\nprint a.replace(\"@\", quoted(a))" print a.replace("@", quoted(a))
и это все! Все quines на всех языках работает (кроме обманщиков).
Ну, вы должны убедиться, что вы заменяете только первое появление владельца места. И если вы используете держатель второго места, вы можете избежать необходимости цитировать строка.
но это незначительные проблемы
и легко решить.
Если факт реализации quoted()
и replace()
являются единственными деталями, в которых различные куины действительно отличаются.
1, заставляя программу читать исходный файл
существует несколько различных стратегий написания Квинса. Очевидным является то, чтобы просто написать код, который открывает код и распечатывает его. Но более интересные включают языковые функции, которые позволяют самостоятельно внедрять, например, функцию %s-style printf на многих языках. Вы должны выяснить, как встроить что-то, чтобы оно в конечном итоге разрешило запрос на внедрение. Я подозреваю, что, как и палиндромы, много проб и ошибок.
обычный подход (когда вы не можете обмануть*) - написать что-то, что кодирует его источник в Строковой константе, а затем печатает эту константу дважды: один раз как строковый литерал и один раз как код. Это обходит "каждый раз, когда я пишу строку кода, я должен написать другую, чтобы распечатать ее!" проблема.
'обман' включает в себя: - Использование интерпретируемого языка и просто загрузка источника и его печать - 0-байтовые длинные файлы, которые действительны на некоторых языках, таких как С.
для удовольствия я придумал одну схему, которой я очень гордился около 5 минут, пока не обнаружил, что был обнаружен раньше. В любом случае, есть небольшая модификация "правил" игры, чтобы лучше рассчитывать на двойственность данных и кода в Lisp: вместо того, чтобы печатать источник программы, это S-выражение, которое возвращает себя:
((lambda (x) (list x `',x)) '(lambda (x) (list x `',x)))
на на Википедии имеет ту же концепцию, но с немного другой (более подробный) механизм цитирования. Но мне моя нравится больше.
одна идея подумать о кодировании и как дать что-то двойное значение, чтобы его можно было использовать для вывода чего-то в нескольких формах. Существует также cavaet, что этот тип проблемы поставляется с ограничениями, чтобы сделать его сложнее, поскольку без каких-либо правил, кроме вывода самой программы, пустая программа является решением.
вы можете найти довольно много решений для этого здесь: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);
}
?>
в 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."
Я сделал пример 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()