May 05 2009

The King of Quines

Category: DevLucho @ 18:44

Quine не е миспелнато Queen, а програма, която извежда сама себе си и се надявам не само мен ме freak out-ва това. Все едно някой андройд да разбере, че не е човек, а машина. Почти толкова тъжно е както когато малкото роботче в AI на Спилбърг отчаяно искаше да намери феята, за да го превърне в истинско момче и майка му да го обича… драма драма.

За типичния Quine е удобно да се ползва printf-оподобни функции, които да имат еднакъв форматиращ низ и аргумент за форматирането. По този начин се получава нещо като вложено построяване на низа за печатане. Друг подход е функционалния, който е представен по-надолу (Javascript частта).

Предполагам, че все още на никой нищо не му е ясно и тъй като не мога да направя по-дълго отрицание от това, ето няколко варианта написани на някои от скриптовите езици, с които съм имал вземане-даване (популярните езици изискващи компилация имат твърде дълги Quine-ита).


Python

_='_=%r;print(_%%_)';print(_%_)

Какво прави кода: записва в променливата _ форматиращия низ, като %r значи да се изведе repr на обекта (това ще изведе текстово представяне на обекта, ако обекта е низ ще изведе и единични кавички), а %% е escape-ване на %. После се извиква print, като се форматира низът от _ сам със себе си (%).

_=’_=%r;print(_%%_)’;print(_%_) -> _=‘_=%r;print(_%%_)’;print(_%_)


Ruby

_="_=%p;puts _%%_";puts _%_

Какво прави кода: прави същото, което и горния код, но тук вместо %r имаме %p, функцията за отпечатване се казва puts и нямаме нужда от скоби за извикването на функция (обичам Ruby).


PHP

<?php $f='<?php $f=%c%s%c; printf($f,39,$f,39); ?>'; printf($f,39,$f,39); ?>

Какво прави кода: да, познахте, кода прави същото, което и предните два, с тази разлика, че php изисква допълнителен незначещ crap, който да се зарови около кода (<?…), печатащата функция е printf, която има синтаксис сходен с printf от C, а за да оградим резултата в единични кавички се изписва ascii символ 39, което както се досещате е единична кавичка.


Javascript

( function (x) { return "(" + x + ")(" + x + ")"; } )( function (x) { return "(" + x + ")(" + x + ")"; } )

Какво прави кода: тук става вече по-интересно, защото кода не прави това, което предните 3 функции правеха. Записа много прилича на Quine на Scheme и да си призная една част от него е загадка за мен (например защо като подадем като параметър на функция друга функция, получения аргумент е записа/кода на подадената функция, а не обект с адрес. Може това да е представянето, незнам). Първо и двете анонимни функции са еднакви, като втората е аргумент на първата и при изпълнение ще се запише два пъти със скоби отляво и отдясно, което е и изходния запис. Скобите са нужни, за да окаже in-place изпълнение на първата анонимна функция и че втората анонимна функция е аргумент на първата. Може да пробвате този код като го напишете в адресната лента на browser-а си (тествано с FireFox):

javascript: ( function (x) { return “(” + x + “)(” + x + “)”; } )( function (x) { return “(” + x + “)(” + x + “)”; } )


Leave a Reply