Suggerimenti per la scrittura di quines


30

Un è un programma che produce un output identico al codice sorgente del programma. Su questo sito Web, in genere ci preoccupiamo solo dei quines appropriati (al momento della stesura, la definizione corrente è "una parte dell'output è codificata da una parte diversa del programma").

Che consiglio hai di scrivere quines appropriate o programmi con proprietà simili? Come al solito, ogni suggerimento dovrebbe avere una risposta diversa.

tips  quine 

Risposte:


14

Utilizzare evalper ridurre la necessità di copiare il codice

La maggior parte dei quines richiede due copie del codice; uno da eseguire, uno come dati. Questo può finire per raddoppiare la lunghezza del codice sorgente, rendendo più difficile il mantenimento e peggiorando il punteggio se stai scrivendo il quine per una competizione di .

Unire le due copie significa che una parte delle informazioni deve essere utilizzata per due scopi. Cercare di trattare il tuo codice come dati spesso non è possibile ed è generalmente considerato barare quando lo è. Il trattamento dei dati come codice, tuttavia, può essere fatto in molte lingue tramite l'uso di un built-in, generalmente chiamato eval. Come tale, il tuo quine sostanzialmente consiste nel memorizzare il corpo principale del tuo quine in una variabile (in modo che tu possa fare riferimento ad esso più di una volta), quindi valutare quella variabile.

Ecco un esempio di come funziona (l'esempio è scritto in Python, ma qualcosa di simile funziona in molte altre lingue):

d='print("d="+repr(d)+"\\neval(d)")'
eval(d)

2
@QPaysTaxes: ho l'obiettivo di rendere il mio codice qui leggibile e gestibile come le condizioni di vittoria lo consentono. Sfortunatamente, questo è ancora indistinguibile dal rumore di linea ASCII (o solo dal rumore di linea normale se sto usando Jelly) da persone che non sono abituate alla lingua.

14

Approfitta della formattazione delle stringhe

Uno dei modi più semplici per creare un quine è definire una stringa, quindi inserirla al suo interno con la formattazione della stringa.

s='s=%r;print s%%s';print s%s

Quindi in questo esempio Python quine, dichiariamo una stringa con la prima parte uguale a qualsiasi cosa sia prima della stringa s=, quindi consentiamo che la stringa venga inserita con la formattazione %re, infine, mettiamo ciò che viene dopo la stringa per stamparla e formattarla . La nuova riga finale è perché printstampa una nuova riga finale.

Quindi il modello è davvero questo, in Python:

<A>'<A>%r<B>'<B>

Per espandere il quine esistente con più codice:

<more A>s='<more A>s=%r;print s%%s<more B>';print s%s<more B>

9

Funzioni rigorose

In diverse lingue, gli oggetti funzione (o costrutti equivalenti) memorizzano implicitamente il loro codice sorgente e lo restituiranno quando convertiti in una stringa. Ciò consente di avere quines compatte senza usare lo string eval . Un esempio notevole di tale lingua è JavaScript:

function f(){console.log(f+"f()")}f()

Questo codice definisce e chiama una funzione fche, quando viene chiamata, stampa il proprio codice sorgente seguito da una chiamata a se stesso. L'unica parte del programma che deve essere duplicata è la chiamata di funzione f(). Naturalmente, il corpo della funzione può includere un "payload" arbitrario di codice che verrà eseguito anche quando viene chiamata la funzione.


Una versione più compatta dello stesso trucco funziona nei linguaggi del golf GolfScript :

{".~"}.~

e CJam :

{"_~"}_~

Ciascuno di questi quines definisce innanzitutto un blocco di codice anonimo (racchiuso tra parentesi graffe), che si comporta in modo molto simile a un oggetto funzione in JavaScript: può essere eseguito e, se sottoposto a stringhe, restituisce il suo codice sorgente. Il resto del codice ( .~in GolfScript o _~in CJam) esegue quindi il blocco, lasciandone una copia nello stack. Il codice all'interno del blocco quindi inserisce una stringa nello stack che ripete il codice all'esterno del blocco. Quando l'interprete esce, si stringe e stampa automaticamente tutto ciò che rimane sulla pila. Come nell'esempio JavaScript, questi blocchi di codice potrebbero anche essere realizzati per trasportare ed eseguire un payload arbitrario di codice aggiuntivo senza doverlo duplicare.


9

Utilizzare i delimitatori di stringa che nidificano senza escape

Spesso, una delle parti più difficili della scrittura di un quine è il passo di fuga. Ciò è necessario in quasi ogni quiné; il problema è che stai memorizzando i dati in qualche modo e devi replicare il codice che archivia i dati nell'output del quine. Quel codice conterrà una forma di dati con escape, quindi il programma vedrà una forma senza caratteri di escape e dovrai eseguirne nuovamente la escape.

Il modo più semplice per gestire il passaggio senza escape è se le forme di escape e non di escape dei dati differiscono solo in presenza o assenza di delimitatori di stringa. L'escaping è quindi una semplice questione di aggiungere una nuova coppia di delimitatori di stringa attorno alla stringa. Sfortunatamente, questo può chiaramente funzionare solo se i delimitatori di stringa stessi possono essere espressi nei dati senza scappare.

Perl è un buon esempio di una lingua in cui funziona questo trucco. Sebbene i suoi soliti delimitatori di stringa siano "…"o '…', i q(…)nidi meno comunemente usati , che consentono di scrivere questo tipo di quine:

$_=q($_=q(0);s/\d/$_/;print);s/\d/$_/;print

Questo è un codice + dati quine. s///è un'operazione di sostituzione della stringa regex; usiamo 0come marker e lo abbiniamo all'interno della regex come \d("qualsiasi cifra"), per evitare di usare il marker più di una volta (anche se come altra ottimizzazione, potremmo effettivamente averlo usato di 0nuovo, perché Perl s///sostituisce solo la prima occorrenza con predefinito). Si noti che qui non è necessario alcun passaggio di escape esplicito, poiché i q(…)delimitatori possono essere inclusi letteralmente nella stringa di dati.


8

Codice + dati interrogati

La struttura più generale per un quine assomiglia a questo pseudocodice:

data = " una versione con escape dell'intero programma,
        con questa stringa sostituita da un marcatore "
program = data.replace (
  un'espressione che valuta il marcatore ma non lo menziona ,
  escape (dati))
programma di stampa;

Questa struttura può essere usata per scrivere un quine (abbastanza ingenuo) nella maggior parte delle lingue. Tuttavia, tende a segnare un punteggio abbastanza basso sulla maggior parte dei sistemi di punteggio, perché devi scrivere l'intero programma due volte. Tuttavia, la maggior parte delle strutture quine possono essere considerate ottimizzazioni di questo.

Ci sono alcune sottigliezze in questo. In alcune lingue, la parte più difficile dell'esecuzione di questa operazione è scrivere il codice di escape; in molte lingue, è difficile produrre il marcatore senza menzionarne il nome; e in alcune lingue esoteriche, dovrai inventare il tuo tipo di stringa letterale. Tutte e tre le operazioni tendono tuttavia a non causare troppi problemi.

Ad esempio, possiamo scrivere un quine Python che fuoriesce da una stringa usando repre usando la x"stringa di sequenza di 2 caratteri (che è rappresentabile come "x\"", cioè non usando la sequenza x"nella rappresentazione di stringa della stringa stessa) come marcatore:

d='d=x"\nprint(str.replace(d,"x\\"",repr(d)))'
print(str.replace(d,"x\"",repr(d)))

2
Potrebbe valere la pena notare (possibilmente in un'altra risposta) che inserire la stringa nella posizione di un marker è spesso costoso in esolangs, e potrebbe valere la pena strutturare il codice in modo tale che la stringa stessa sia la prima o l'ultima cosa (forse separata da la fine di uno o due caratteri che puoi codificare) in modo da sapere dove deve andare.
Martin Ender,

@MartinEnder: sono d'accordo che vale la pena menzionare, ma è probabilmente un'altra risposta (piuttosto che un commento o una modifica in questa risposta). La maggior parte dei suggerimenti di Quine sono modifiche a questa struttura generale, quindi volevo prima farne uno da solo, dato che molte persone non hanno idea di dove iniziare a scrivere un quine.

Un'alternativa a un marcatore è usare due stringhe, l'ho fatto per Glass .
Ørjan Johansen,

4

Sfrutta il codice sorgente di wrapping

In parecchie lingue (principalmente lingue 2D), il codice sorgente può andare in giro; in determinate circostanze (ad es. in Befunge-98, se il tuo programma è di tipo "one-liner") oltre la fine del programma ti riporterà all'inizio del programma. Questo tipo di comportamento non lineare significa che puoi scrivere codice che è dentro e fuori una stringa letterale allo stesso tempo; un ineguagliato "(o qualunque sia il delimitatore di stringa) ti darà effettivamente una stringa che contiene tutto il resto del programma (tranne che per se "stesso).

Un problema con l'utilizzo di questo trucco è che otterrai la stringa vista dal punto di vista di ", piuttosto che dall'inizio del programma (come vorresti). Pertanto, è probabilmente più semplice riorganizzare il programma in modo che "appaia all'inizio o alla fine. Questo spesso significa tagliare il programma in più pezzi e utilizzare qualsiasi comando di controllo del flusso interessante / insolito nella tua lingua (la maggior parte delle lingue che consentono ai letterali di stringhe di avvolgersi nel programma ne ha una buona selezione).

Un buon esempio è il quine @ Justin's Befunge-98 :

<@,+1!',k9"

L'impareggiabile "alla fine del programma avvolge l'intero programma in una stringa letterale, quindi (correndo da destra a sinistra a causa <dell'inizio) tutto ciò che dobbiamo fare è produrre il programma ( 9k), quindi produrre la doppia virgoletta ( '!1+,) e exit ( @). Ciò consente di risparmiare due copie del programma (una come codice, una come dati); le due copie sono lo stesso codice, solo interpretate in modi diversi.


4

Ricorda la struttura di un Quine

Mi piace pensare ai quines come a tre parti, piuttosto che a 2:

  • Parte 1: Genera una rappresentazione dei dati delle parti 2 e 3.
  • Parte 2: utilizzare i dati per stampare in modo algoritmico la parte 1.
  • Parte 3: decodifica la rappresentazione per stampare le parti 2 e 3.

Questo può rendere più facile pensare alle quines. Ecco un quine Python, con ogni riga corrispondente a una parte:

s = "print(\"s = \" + repr(s))\nprint(s)"
print("s = " + repr(s))
print(s)

A volte, usi uno evalo simili per rimuovere la duplicazione, ma generalmente ho scoperto che questo aiuta a scrivere semplici quine.

Diamo un'occhiata a due diverse quine Underload. Questo è il primo:

(:aSS):aSS

La prima parte è (:aSS), che genera la rappresentazione dei dati. Il secondo è :aS, che stampa (:aSS). La terza parte è S, che stampa :aSS.

Ecco il secondo quine:

(:aS(:^)S):^

All'inizio, questo non sembra adattarsi. Ma se espandi il quine, otterrai:

(:aS(:^)S):aS(:^)S

Ora (:aS(:^)S)è parte 1, :aSè parte 2 ed (:^)Sè parte 3.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.