Quine (dataprogram)

En quine er et dataprogram som skriver en kopi av seg selv (vanligvis kildekoden ) som utdata. Det er derfor en form for selvreferanse .

Hackere og geeks ser på det som en sportslig utfordring å lage minst mulig kviner på de programmeringsspråkene de selv velger (se IOCCC ).

Quines er oppkalt etter logikeren og filosofen Willard Van Orman Quine .

Bygging av kviner

Spør deg selv

En quine kan skrives slik i en C- lignende pseudokode

main() {
    print myself out.
}

Vanligvis blir C-programmer samlet , dvs. H. Den kjøretids versjon av programmet er tilgjengelig i maskinspråk (representasjon som en sekvens av byte , som er lagret i en såkalt binærfilen), men dens opprinnelige representasjon er vanligvis en ASCII- kodet kildetekst som blir også lagret i en annen fil. Tilgangen til egen representasjon ( meg selv ) som kreves for denne tilnærmingen til implementeringen av en Quines ville derfor være veldig komplisert.

En quine er også nødvendig for å være ferdig.

  • Det bør gjøre uten tilgang til eksterne data, noe som betyr at tilgang til din egen kildetekstfil også er ekskludert.
  • Den essensielle koden skal også være tilstede i Quine selv, og det er grunnen til at eksterne funksjoner bare skal brukes sparsomt, biblioteksfunksjonen som for eksempel gir et tegn , er fortsatt tillatt.

Bare noen få språk støtter selvreferanse ( refleksjon ) i den form at et program på dette språket har tilgang til sin egen representasjon.

Et tolket programmeringsspråk, som Perl eller Python , ville i prinsippet ha lettere tid, siden representasjonen av programmet som skal utføres av tolken, også kunne gjøres tilgjengelig for den samme, men dette støttes vanligvis ikke, for eksempel av sikkerhetsgrunner eller fordi designerne av språket ikke ønsket å gå så langt (for eksempel fordi selvmodifiserende kode avvises). Vanligvis er det ikke mye mer refleksjon mulig for programmet enn å lære navnet og navnene på variablene og funksjonene fra kjøretidssystemet.

Refleksjon fører derfor ikke til riktig quine på de fleste programmeringsspråk.

Kode som data

De fleste programmeringsspråk gir liten hjelp til å representere programmer internt og til å jobbe med disse representasjonene:

  • analysere dem ( parsing ),
  • å generere nye programmer fra eksisterende representasjoner ( komposisjon ) og spesielt
  • utføre det representerte programmet ( applikasjonen ).

Et velkjent anvendelse eksempel vil være en funksjon plotter , som er et program for plotting av grafene i noen matematiske funksjoner.

Med andre ord:

I mange programmeringsspråk er det ingen passende datatype med tilsvarende operasjoner for funksjoner.

I C kan du lagre et stykke programkode i en streng , men du kan gjøre lite med det, fordi det er vanskelig å analysere og utføre med hjelp av C. Du må da ty til komplekse merkede strukturer og eksterne biblioteker.

LISP er en positiv eksempel fordi dette språket representerer kildekoden i den algebraiske datatype listen , som det i hovedsak benytter seg ( homoiconicity ).

Quination

Ovennevnte har listet opp vanskeligheter et program har med å be om sin egen struktur. Likevel må det også være mulig å realisere en quine i C (se forklaringene på eksistensen av quines i den teoretiske delen). Følgende teknikk brukes for dette:

Hvis du ikke kan spørre om din egen struktur, må du vite det på forhånd.

Du designer programmet i to deler, en kalt koden og en kalt data. Dataene representerer koden (eller dens tekstform) og de er avledet fra koden på en algoritmisk måte (for det meste ved hjelp av anførselstegn, men noen ganger på en litt mer komplisert måte). Koden bruker dataene til å sende ut koden (noe som er enkelt fordi dataene representerer koden); deretter bruker den dataene til å sende ut dataene (noe som er mulig fordi dataene er hentet i en algoritmisk transformasjon).

Som forklart ovenfor er dette lettere å implementere på noen språk og vanskeligere å implementere på andre, for eksempel avhengig av om funksjoner er førsteklasses borgere av språket eller ikke.

I streng forstand bør quines være uavhengige av tegnsettet, og kildekoden, inkludert alle linjeskift, skal sendes ut nøyaktig igjen.

Eksempler

Språk eksempel Tips
Lisp
((lambda (x)
  (list x (list (quote quote) x)))
 (quote
    (lambda (x)
      (list x (list (quote quote) x)))))
Det eneste eksemplet som ikke krever en "streng" -datatype
package main
import "fmt"
func main() {
	fmt.Printf("%s%c%s%c\n", s, 0x60, s, 0x60)
}
var s = `
package main
import "fmt"
func main {
	fmt.Printf("%s%c%s%c\n", s, 0x60, s, 0x60)
}
var s = `
Bruker ASCII-kodingen av Grave-aksenten
C.
#include <stdio.h>
char*f="#include <stdio.h>%cchar*f=%c%s%c;main() {printf(f,10,34,f,34,10);}%c";main() {printf(f,10,34,f,34,10);}
Bruker ASCII-kodingen av anførselstegnet
Lua
a="a=%c%s%c;io.write(string.format(a,34,a,34))";io.write(string.format(a,34,a,34))
Bruker ASCII-kodingen av anførselstegnet
Python 2
a="a=%c%s%c;print a%%(34,a,34)";print a%(34,a,34)
Bruker ASCII-kodingen av anførselstegnet
Python 3
a="a=%c%s%c;print(a%%(34,a,34))";print(a%(34,a,34))
Bruker ASCII-kodingen av anførselstegnet
Perle
$a='$a=%c%s%c;printf($a,39,$a,39,10);%c';printf($a,39,$a,39,10);
Bruker ASCII-kodingen til det eneste anførselstegnet
Perle
$r='\'; $_=$r; s/([\\\'\\\\])/\\\\$1/g; print \'$r=\\\'\'.$_.$r;
'; $_=$r; s/([\'\\])/\\$1/g; print '$r=\''.$_.$r;
Uavhengig av tegnsettet
Perl6
my $t="; say \"my \\\$t=\",\$t.perl,\$t"; say "my \$t=",$t.perl,$t
Rubin
puts <<2*2,2
puts <<2*2,2
2
Uavhengig av tegnsettet
Rubin
eval s=%q(puts"eval s=%q(#{s})")
Uavhengig av tegnsettet
Rust
fn main() {
    let x = "fn main() {\n    let x = ";
    let y = "print!(\"{}{:?};\n    let y = {:?};\n    {}\", x, x, y, y)\n}\n";
    print!("{}{:?};
    let y = {:?};
    {}", x, x, y, y)
}
C #
using System;class Quine{static string f=
"using System;class Quine{{static string f={1}{0}{1};static void Main(){{Console.Write(f,f,Convert.ToChar(34));}}}}";
static void Main(){Console.Write(f,f,Convert.ToChar(34));}}
Java
class Q{public static void main(String[]a){String f=
"class Q{public static void main(String[]a){String f=%c%s%1$c;System.out.printf(f,34,f);}}";
System.out.printf(f,34,f);}}
Bare en linje
Kotlin
fun main(args: Array<String>){val f="""fun main(args: Array<String>){val f="%s"%s"%s";System.out.printf(f,'"',f,'"')}""";System.out.printf(f,'"',f,'"')}
Bare en linje, uavhengig av tegnsett
JavaScript
(x=>console.log(x+JSON.stringify(x)+')'))("(x=>console.log(x+JSON.stringify(x)+')'))(")
Søvn
[{$s = ';print("[{\$s = ".chr(39).$s.chr(39).$s);}]';print("[{\$s = ".chr(39).$s.chr(39).$s);}]
PHP
<?php printf($c = '<?php printf($c = %c%s%c, 39, $c, 39); ?>', 39, $c, 39); ?>
Pascal
const a=';begin write(^#^/^.^3^4^`^!^}#39,a,#39,a)end.';begin write(^#^/^.^3^4^`^!^}#39,a,#39,a)end.
bruker escape-sekvenser
Delphi
program Quine;{$APPTYPE CONSOLE}var x:String=
'program Quine;{$APPTYPE CONSOLE}var x:String=;begin Insert(#39+x+#39,x,46);WriteLn(x);ReadLn;end.';
begin Insert(#39+x+#39,x,46);WriteLn(x);ReadLn;end.
uten linjeskift (ville ellers være for lang for denne tabellen)

Teoretisk bakgrunn

Eksistensen av quines er teoretisk sikret av rekursjonssetningen (også kalt Kleenes fastpunktssetning ).

Begrunnelsen går omtrent som følger:

  • Egenskapene til programmeringsspråk kan utledes fra resultatene av beregbarhetsteori , som analyserer veldig enkle modeller av programmer på en matematisk presis måte.
  • Siden alle programmer (mer presist: deres begrensede kildetekster) kan telles, dvs. kartlagt bijectively til de naturlige tall , i denne modellen verden er det tilstrekkelig å angi et naturlig tall som en representasjon av et program. Dette tallet gjør det samme som kildekoden, nemlig valget av akkurat den funksjonen som tilsvarer semantikken i programmet.
  • Med fastpunktsblokken kan det vises at det er et program med nummeret (med ), hvis utgang (for alle mulige innganger ) i sin tur er nummeret . Dermed er dette fra ovennevnte lemma i beregbarhetsteorien nøyaktig ekvivalent med et program som sender ut sin egen representasjon - en Quines.

Uttalelsene fra beregbarhetsteorien for beregningsfunksjoner kan lett generaliseres til Turing-maskiner og dermed til slutt til alle Turing-komplette språk.

Quines er derfor ikke bare et resultat av ressurssterke programmerere som lurer et programmeringsspråk, det er heller en grunnleggende egenskap ved Turing-komplette programmeringsspråk at quines eksisterer for dem.

Se også

litteratur

weblenker

Individuelle bevis

  1. Craig S. Kaplan: The Search for Self-Documenting Code