Quine (informática)
Un quine es un programa de computadora que no recibe entradas y produce una copia de su propio código fuente como única salida. Los términos estándar para estos programas en la teoría de la computabilidad y la literatura informática son 'programas autorreplicantes', 'programas autorreproductores' y 'programas autocopiantes'.;.
Un quine es un punto fijo de un entorno de ejecución, cuando el entorno de ejecución se ve como una función que transforma los programas en sus resultados. Quines son posibles en cualquier lenguaje de programación completo de Turing, como consecuencia directa del teorema de recursión de Kleene. Por diversión, los programadores a veces intentan desarrollar el quine más corto posible en cualquier lenguaje de programación dado.
El nombre "quine" fue acuñado por Douglas Hofstadter, en su libro de divulgación científica Gödel, Escher, Bach, en honor al filósofo Willard Van Orman Quine (1908-2000), quien realizó un extenso estudio de autorreferencia indirecta, y en particular para la siguiente expresión productora de paradoja, conocida como paradoja de Quine:
"Yields falsehood when preceded by its quote" produces falsehood when preceded by its quote.
Historia
La idea de los autómatas que se reproducen a sí mismos surgió desde los albores de la informática, si no antes. John von Neumann teorizó sobre ellos en la década de 1940. Más tarde, el artículo de Paul Bratley y Jean Millo "Computer Recreations: Self-Reproducing Automata" discutido en 1972. Bratley se interesó por primera vez en los programas de reproducción automática después de ver el primer programa conocido escrito en Atlas Autocode en Edimburgo en la década de 1960 por el profesor e investigador de la Universidad de Edimburgo, Hamish Dewar.
La "fuente de descarga" requisito de la Licencia Pública General Affero se basa en la idea de un quine.
Ejemplos
Quienes constructivos
En general, el método utilizado para crear un quine en cualquier lenguaje de programación consiste en tener, dentro del programa, dos piezas: (a) código utilizado para realizar la impresión real y (b) datos que representan la forma textual del código. El código funciona utilizando los datos para imprimir el código (lo que tiene sentido ya que los datos representan la forma textual del código), pero también utiliza los datos, procesados de forma sencilla, para imprimir la representación textual de los datos en sí.
Aquí hay tres pequeños ejemplos en Python 3:
# Ejemplo A. Note that chr(39) == "'".a = A = {}{} {} {} {}} {}} {}}} {}}}} {}}} {}}} {}}} {}}} {}}}} {}}} {}}} {}}} {} {}}}} {}}} {}}} {}}} {}} {}}}} {}}}}} {}} {}}}}}}} {} {}}}}} {}}}}} {}}}}} {}}}}} {}}}}} {} {}}}}} {}}} {}}}} {}}} {}} {} {}}}}}}}}}}} {}}}}}}}}}} {} {} {} {} {}}}} {}}}}}} {} {} {}}}}}}}}} {}}}}}} {}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}; print(a.format(chr(39), a, chr(39))) '; impresión()a.formato()chr()39), a, chr()39))
# Ejemplo B. Note that chr(39) == "'".b = b ♪♪; print(b) %% (chr(39), b, chr(39)))) '; impresión()b % ()chr()39), b, chr()39))
# Ejemplo C. Tenga en cuenta que %r cotizará automáticamente.c = C = %r; print(c %% c) '; impresión()c % c)
El siguiente código Java demuestra la estructura básica de un quine.
público clase Quine{} público estática vacío principal()String[] args) {} char q = 34; // Marca de calificación carácter String[] l = {} // Array of source code "Clase pública Quine", "{", "vacío estático público principal", ", " char q = 34; // caracteres de marca de calificación", " String[] l = { // Array of source code", ", ", "para(int i = 0; i) Código de apertura de impresión", " System.out.println(l[i]);", "por(int i = 0; i) hice l.length; i++) // array de cadena de impresión", " System.out.println(l[6] + q + l[i] + q + ',');", "por(int i = 7; i) il.length; i++) // Imprima este código", " System.out.println(l[i]);", ", ", }; para()int i = 0; i . 6; i++) // Impresión código de apertura Sistema.Fuera..println()l[i]); para()int i = 0; i . l.longitud; i++) // Imprimir matriz de cadena Sistema.Fuera..println()l[6] + q + l[i] + q + ','); para()int i = 7; i . l.longitud; i++) // Imprimir este código Sistema.Fuera..println()l[i]); }}
El código fuente contiene una matriz de cadenas de sí mismo, que se genera dos veces, una vez entre comillas.
Este código fue adaptado de una publicación original de c2.com, donde el autor, Jason Wilson, lo publicó como una versión minimalista de Quine, sin comentarios de Java.
Gracias a la nueva característica de bloques de texto en Java 15 (o posterior), es posible una versión más legible y simple:
público clase Quine {}público estática vacío principal()String[] args) {}String textBlockQuotes = nuevo String()nuevo char[]{}' ', ' ', ' '});char newLine = 10;String fuente = "clase pública Quine {}public static void main(String[] args) {String textBlockQuotes = new String(new char[]{'"', ' ', ' '});char newLine = 10;String fuente = %s;Sistema.Fuera..impresión()fuente.formateado()textBlockQuotes + newLine + fuente + textBlockQuotes));}}""System.out.print(source.formatted(textBlockQuotes + newLine + source + textBlockQuotes));}}
Evaluar quines
Algunos lenguajes de programación tienen la capacidad de evaluar una cadena como un programa. Quines puede aprovechar esta función. Por ejemplo, este Ruby quine:
eval s="print 'eval s=';p s"
Lua puede hacer:
s="print(string.format('s=%c%c; load(s)(s)',34,s,34))"; carga()s)()
En Python 3.8:
exec()s:='print("exec(s:=%r)%s) ')
"Hacer trampa" Quines
Autoevaluación
En muchos lenguajes funcionales, incluidos Scheme y otros Lisps, y lenguajes interactivos como APL, los números se autoevalúan. En TI-BASIC, si la última línea de un programa devuelve un valor, el valor devuelto se muestra en la pantalla. Por lo tanto, en dichos lenguajes, un programa que consta de un solo dígito da como resultado un quine de 1 byte. Dado que dicho código no se construye a sí mismo, esto a menudo se considera una trampa.
1
En algunos lenguajes, particularmente lenguajes de secuencias de comandos pero también C, un archivo fuente vacío es un punto fijo del lenguaje, siendo un programa válido que no produce resultados. Un programa tan vacío, presentado como "el programa autorreproductor más pequeño del mundo", ganó una vez el "peor abuso de las reglas" premio en el Concurso Internacional de Código C Ofuscado. El programa en realidad no se compiló, pero usó cp
para copiar el archivo en otro archivo, que podría ejecutarse para no imprimir nada.
Otras técnicas cuestionables incluyen el uso de mensajes del compilador; por ejemplo, en el entorno GW-BASIC, al ingresar "Error de sintaxis" hará que el intérprete responda con "Error de sintaxis".
Inspección de código fuente
Quines, por definición, no puede recibir ninguna forma de entrada, incluida la lectura de un archivo, lo que significa que se considera que un quine está "haciendo trampa" si mira su propio código fuente. El siguiente script de shell no es un quine:
#/bin/sh# Invalid quine.# Leer el archivo ejecutado desde el disco es hacer trampa.gato $0
Una variante más corta, que explota el comportamiento de las directivas shebang:
#/bin/cat
Programas Ouroboros
El concepto de quine se puede extender a múltiples niveles de recursividad, lo que da lugar a los 'programas ouroboros', o quine-relays. Esto no debe confundirse con multiquinas.
Ejemplo
Este programa Java genera el código fuente de un programa C++ que genera el código Java original.
#include ■iostream#include Identificadoutilizando namespace std;int principal()int argc, char* argv[]){} char q = 34; cuerda l[] = {} ", "================= ======= C++ Código, titulado > >, "#incluye", "#incluye", "usando el espacio de nombres std;", ", "int main(int argc, char* argv[])", "{", " char q = 34", "La cuerda l [] = {", ", "para(int i = 20; i י= 25; i++)", " cout" se realizó l [i], "para(int i = 0; i י= 34; i++)", " cout" se realizó l[0] + q + l[i] + q + ',' "se realizó endl", "para(int i = 26; i י= 34; i++)", " cout" se realizó l [i], "Vuelve 0;", ", "================= ======= Código de Java, titulado " titulado ", "Clase pública Quine", "{", "vacío estático público principal", ", " char q = 34", "Estring[] l = {", ", "para(int i = 2; i) = 9; i++)", " System.out.println(l[i]);", "para(int i = 0; i < il.length; i++)", " System.out.println(l[0] + q + l[i] + q + ',');", "para(int i = 10; i י= 18; i++)", " System.out.println(l[i]);", ", ", }; para()int i = 20; i . 25; i++) Cout .. l[i] .. endl; para()int i = 0; i . 34; i++) Cout .. l[0] + q + l[i] + q + ',' .. endl; para()int i = 26; i . 34; i++) Cout .. l[i] .. endl; retorno 0;}
público clase Quine{} público estática vacío principal()String[] args) {} char q = 34; String[] l = {} ", "================= ======= C++ Código, titulado > >, "#incluye", "#incluye", "usando el espacio de nombres std;", ", "int main(int argc, char* argv[])", "{", " char q = 34", "La cuerda l [] = {", ", "para(int i = 20; i י= 25; i++)", " cout" se realizó l [i], "para(int i = 0; i י= 34; i++)", " cout" se realizó l[0] + q + l[i] + q + ',' "se realizó endl", "para(int i = 26; i י= 34; i++)", " cout" se realizó l [i], "Vuelve 0;", ", "================= ======= Código de Java, titulado " titulado ", "Clase pública Quine", "{", "vacío estático público principal", ", " char q = 34", "Estring[] l = {", ", "para(int i = 2; i) = 9; i++)", " System.out.println(l[i]);", "para(int i = 0; i < il.length; i++)", " System.out.println(l[0] + q + l[i] + q + ',');", "para(int i = 10; i י= 18; i++)", " System.out.println(l[i]);", ", ", }; para()int i = 2; i . 9; i++) Sistema.Fuera..println()l[i]); para()int i = 0; i . l.longitud; i++) Sistema.Fuera..println()l[0] + q + l[i] + q + ','); para()int i = 10; i . 18; i++) Sistema.Fuera..println()l[i]); }}
Estos programas se han producido con ciclos de diversa duración:
- Haskell → Python → Ruby
- Python → Bash → Perl
- C → Haskell → Python → Perl
- Haskell → Perl → Python → Ruby → C → Java
- Ruby → Java → C# → Python
- C → C++ → Ruby → Python → PHP → Perl
- Ruby → Python → Perl → Lua → OCaml → Haskell → C → Java → Brainfuck → Whitespace → Unlambda
- Ruby → Scala → Plano → Scilab → Shell (bash) → S-Lang → Smalltalk → Squirrel3 → Standard ML →... → Rexx (128 (y anteriormente 50) lenguajes de programación)
- Aplicación web → C (código fuente de aplicaciones web consiste en HTML, JavaScript y CSS)
Multiquinas
David Madore, creador de Unlambda, describe las multiquinas de la siguiente manera:
"Un multiquino es un conjunto de programas diferentes (en r diferentes idiomas – sin esta condición podríamos tomarlos todos iguales a una sola quine), cada uno de los cuales es capaz de imprimir cualquiera de los programas r (incluido él mismo) de acuerdo con el argumento de línea de comandos que se aprueba. (Nota que no se permite el engaño: los argumentos de la línea de comandos no deben ser demasiado largos: pasar el texto completo de un programa se considera trampa)."
Un multiquine formado por 2 idiomas (o biquine) sería un programa que:
- Cuando se ejecuta, es una quine en el lenguaje X.
- Cuando se suministra con un argumento de línea de comando definida por el usuario, imprimiría un segundo programa en el idioma Y.
- Dado el segundo programa en el idioma Y, cuando se ejecuta normalmente, también sería una quinta en el idioma Y.
- Dado el segundo programa en el idioma Y, y suministrado con un argumento de línea de comando definida por el usuario, produciría el programa original en el idioma X.
Una biquine podría entonces verse como un conjunto de dos programas, los cuales pueden imprimir cualquiera de los dos, según el argumento de la línea de comando proporcionado.
Teóricamente, no hay límite en el número de idiomas en un multiquine. Se ha producido una multiquina (o pentaquina) de 5 partes con Python, Perl, C, NewLISP y F# y también hay un multiquine de 25 idiomas.
Endurecido por radiación
Un quine endurecido por radiación es un quine al que se le puede quitar cualquier carácter y aun así produce el programa original sin que falte ningún carácter. Por necesidad, tales quines son mucho más complicados que los quines ordinarios, como se ve en el siguiente ejemplo en Ruby:
eval=Eval$q=%q(puts %q(10210/#{1 1 si 1==21}}/.i rescate#1 1"[13,213].max_by{ soportas.size}#"#").gsub(/d/){[" =47eval$q=%q(#$q)47##47",:eval,:instance_," sometida a muerte=9" [eval$ golpe]}salida# '## 'instance_eval=Eval$q=%q(puts %q(10210/#{1 1 si 1==21}}/.i rescate#1 1"[13,213].max_by{ soportas.size}#"#").gsub(/d/){[" =47eval$q=%q(#$q)47##47",:eval,:instance_," sometida a muerte=9" [eval$ golpe]}salida# '## '/#{eval eval si eval==instance_eval}}/.i rescate##eval eval"[eval vidas eternas=9,instance_eval vidas eternas=9].max_by{ vidas soportas.size}#"###
Contenido relacionado
Historia de la radio
Estación terrestre de satélite Goonhilly
Ancla