Citando un mondo incontaminato


16

Questa sfida si basa sulla domanda di Helka Homba , Programming a Pristine World . Da quella domanda, la definizione di un programma incontaminato è:

Definiamo un programma incontaminato come un programma che non ha alcun errore in sé, ma lo farà se lo modifichi rimuovendo qualsiasi sottostringa contigua di N caratteri, dove 1 <= N < program length.

Ad esempio, il programma Python 2 a tre caratteri

`8`

è un programma incontaminato ( grazie, Sp ) perché tutti i programmi risultanti dalla rimozione di sottostringhe di lunghezza 1 causano errori (in effetti errori di sintassi, ma qualsiasi tipo di errore lo farà):

8`
``
`8

e anche tutti i programmi risultanti dalla rimozione di sottostringhe di lunghezza 2 causano errori:

`
`

Se, per esempio, `8fosse stato un programma senza errori, allora `8`non sarebbe incontaminato perché tutti i risultati della rimozione della sottostringa devono essere errati.

Appunti:

  • Gli avvisi del compilatore non vengono considerati errori.
  • I sottoprogrammi in errore possono accettare input o fornire output o fare qualsiasi altra cosa purché si verifichino errori alla fine.

Il tuo compito è creare un programma di lunghezza diversa da zero che stampi esattamente il suo codice sorgente, segua le regole per un quine corretto ed è incontaminato.

Vince la risposta più breve in byte per ogni lingua.


Suppongo che lingue che non sbagliano non possano competere?
ATaco,

@ATaco Purtroppo sì. Altre lingue, come lisp, hanno la sintassi strutturata in modo tale da rendere impossibile un utile programma originale.
Shelvacu,

RIP in realtà / seriamente
ATaco,

"Vince la risposta più breve in byte per ogni lingua." Non sono sicuro che essere la misura migliore per un programma incontaminato.
P. Siehr,

@ P.Siehr Cosa consiglieresti invece?
Shelvacu,

Risposte:


6

Haskell , 132 byte

q x=if length x==132then putStr x else fail[];main=q$(++)<*>show$"q x=if length x==132then putStr x else fail[];main=q$(++)<*>show$"

Provalo online!

Questa è un'estensione del quine

main=putStr$(++)<*>show$"main=putStr$(++)<*>show$"

che funziona concatenando la stringa di dati con una versione quotata (usando show) di se stessa e stampando il risultato. Tuttavia, questo non è incontaminato in quanto qualsiasi carattere nella stringa di dati può essere rimosso senza errori e anche la parte $(++)<*>show$o (++)<*>può essere eliminata senza l'interruzione del programma.

Per risolvere questo problema, qviene definita una funzione di stampa personalizzata che controlla la lunghezza della stringa specificata e chiama failse è inferiore a 132. In questo modo viene rilevata la rimozione di qualsiasi sequenza dalla stringa di dati e anche la rimozione di $(++)<*>show$o (++)<*>, come in entrambi i casi la risultante la stringa passata qè più corta.

qNel numero 132potrebbe essere ridotto a 1, 13, 32o 2, ma in ogni caso di nuovo failviene chiamato.

Per quanto ne so, la rimozione di qualsiasi altra sottostringa causa una sintassi o un errore di tipo, quindi il programma non si compila nemmeno in primo luogo. (Il rigido sistema di tipi di Haskell è utile qui.)

Modifica: grazie a Ørjan Johansen e Shelvacu per aver segnalato i difetti!


Temo di fail[]|length x/=122poter essere rimosso. fail[]:[putStr x|length x==122]potrebbe funzionare meglio.
Ørjan Johansen,

Argh, no, quindi |length x==122potrebbe essere rimosso. if length x==122 then putStr x else fail[]Forse?
Ørjan Johansen,

@ ØrjanJohansen Buona cattura, ho avuto un if then elseprima ma ho pensato di poterlo abbreviare.
Laikoni,

2
putStr xpuò diventare p x, che quando ho provato a funzionare sul mio sistema per molto tempo prima di ucciderlo, sospetto che la ricorsione della chiamata di coda sia stata ottimizzata, quindi è un ciclo infinito. Non conosco abbastanza haskell per fornire suggerimenti su come risolverlo.
Shelvacu,

@Shelvacu Whoops. La ridenominazione pin qdovrebbe risolverlo.
Ørjan Johansen,

4

Python 3 , 113 byte

for[]in{113:[]}[open(1,"w").write((lambda s:s%s)('for[]in{113:[]}[open(1,"w").write((lambda s:s%%s)(%r))]:a'))]:a

Provalo online!

Come funziona

Non possiamo usare facilmente più istruzioni poiché la seconda potrebbe essere eliminata, quindi iniziamo con un quine a espressione singola:

print((lambda s:s%s)('print((lambda s:s%%s)(%r))'))

Per proteggerlo dalle eliminazioni di sottostringhe, utilizziamo open(1,"w").writeinvece di print. In Python 3, writerestituisce il numero di caratteri scritti, che verificheremo 113per garantire che nessuna parte della stringa sia stata eliminata. Lo facciamo cercando il valore restituito nel dizionario {113:[]}e ripetendo il risultato con for[]in…:a, che fallirà se non otteniamo un iterable vuoto o se l' foristruzione viene eliminata.


1
Potresti dare una spiegazione di come funziona il tuo codice?
Shelvacu,

@Shelvacu Sì, aggiunto.
Anders Kaseorg,

3

Rubino, 78 byte

eval(*[($>.write((s=%{eval(*[($>.write((s=%%{%s})%%s)-78).chr])})%s)-78).chr])

L'ho scritto quando ho pensato alla sfida per assicurarmi che fosse possibile. Utilizza lo stesso "wrapper" da una delle mie risposte alla sfida originale.

Spiegazione:

  • eval(*[ espr ])

    Questo valuta qualsiasi codice restituito come programma ruby. Questo verifica efficacemente che la stringa restituita dal codice sia un programma ruby ​​valido. Convenientemente, i programmi di ruby ​​possono essere vuoti o consistere solo di spazi bianchi.

    L'operatore "splat" *consente di utilizzare un array come argomenti per una funzione. Questo significa anche che se evalviene rimosso, il programma risultante è (*[ expr ]) , che non è ruby ​​valido.

  • ($>.write( str )-78).chr

    $> è una variabile breve per STDOUT.

    $>.write(foo) scrive foo su STDOUT e, soprattutto per questo codice, restituisce il numero di byte scritti.

    $>.write(foo)-78: Ecco 78la lunghezza del programma, quindi se il programma non è modificato, sarà anche il numero di byte scritti. Pertanto, nel caso non distorto, questo restituirà zero.

    num.chrrestituisce num come carattere, ad es. 0.chrrestituirà una stringa contenente un singolo byte null. Nel programma non districato, questo darà una stringa con un singolo byte null a eval, che è un programma ruby ​​valido che non è operativo.

    Inoltre, al programma può essere rimossa una sottostringa in modo tale che sia solo eval(*[(78).chr])o eval(*[(8).chr]), il che significa che la costante numerica non può terminare con nessuno dei numeri (0, 4, 9, 10, 11, 12, 13, 26, 32, 35, 48 , 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 64, 95) perché sono codici ASCII per programmi ruby ​​a carattere singolo validi.

  • %{ str }

    Questa è una sintassi meno conosciuta per i letterali di stringa in rubino. La ragione per cui è usata qui è che {}nella stringa possono essere usate coppie bilanciate di , il che significa che questa sintassi può contenere se stessa. Ad esempio, %{foo{bar}}è uguale a "foo{bar}".

  • (s=%{ dati })%s

    Questo definisce la variabile sche è i dati di questo quine, come una stringa printf.

    Le assegnazioni in ruby ​​restituiscono ciò che è stato assegnato, quindi è lo stesso che prima assegnare se poi eseguires%s

    %su una stringa c'è zucchero sintetico per l'equivalente di ruby ​​di sprintf. I %ssignifica dove all'interno dei dati dei dati stessi devono essere incorporati.

    Questo bit di codice definisce la porzione di dati del quine e la incorpora al suo interno per creare il codice completo.


3

ML standard (MLton) , 204 182 189 byte

val()=hd[(fn s=>let val$ =s^"\""^String.toString s^"\"]"val(189,%)=(size$,$)in print%end)"val()=hd[(fn s=>let val$ =s^\"\\\"\"^String.toString s^\"\\\")\"val(189,%)=(size$,$)in print%end)"]

Provalo online!

Per MLton, i programmi SML completi sono espressioni delimitate e terminate da ;(ad esempio print"Hello";print"World";) o dichiarazioni con le parole chiave vare fun(ad esempio var _=print"Hello"var _=print"World") in cui _è un carattere jolly che può anche essere sostituito da qualsiasi nome di variabile.

La prima opzione è inutile per la programmazione incontaminata perché di ;per sé è un programma valido (che non fa nulla, ma non sbaglia neanche). Il problema con il secondo approccio è che dichiarazioni simili var _=print"Hello"possono essere abbreviate in solo var _="Hello"(o anche var _=print) perché la dichiarazione con varfunziona fintanto che il lato destro è un'espressione o un valore SML valido (SML è un linguaggio funzionale, quindi le funzioni possono essere usato anche come valori).

A questo punto, ero pronto a dichiarare impossibile la programmazione incontaminata in SML, quando per caso mi sono imbattuto nel pattern matching in val-declarations. Si scopre che la sintassi per le dichiarazioni non è val <variable_name> = <expression>ma val <pattern> = <expression>, dove un modello può essere costituito da nomi di variabili, costanti e costruttori. Come la printfunzione ha tipo string -> unit, possiamo usare una corrispondenza motivo sul unit-value ()per imporre che la funzione di stampa viene effettivamente applicato alla stringa: val()=print"Hey". Con questo approccio, la rimozione di uno printo "Hey"risulta in un Pattern and expression disagreeerrore.

Con questo modo di stampare in modo impeccabile, il passo successivo è quello di scrivere un quine, prima di aggiungere infine un po 'di protezione in più. In precedenza ho usato una semplice tecnica SML Quine (vedi la cronologia delle revisioni ), ma Anders Kaseorg ha sottolineato un approccio diverso che può salvare alcuni byte nel suo caso. Utilizza la String.toStringfunzione integrata per gestire l'escaping delle stringhe ed è di forma generale <code>"<data>", dove si "<data>"trova una stringa con escape del codeprecedente:

val()=(fn s=>print(s^"\""^String.toString s^"\""))"val()=(fn s=>print(s^\"\\\"\"^String.toString s^\"\\\"\"))"

Questo è un quine funzionante ma non ancora incontaminato. Prima di tutto Anders Kaseorg ha scoperto che MLton accetta una singola virgoletta "come codice senza produrre errori, il che significa che non possiamo avere il codice che termina con una citazione come sopra. Il modo più breve per evitarlo sarebbe racchiudere tutto val()=in una parentesi, tuttavia il codice potrebbe essere ridotto a val()=(). Il secondo modo più breve che ho trovato è quello di utilizzare val()=hd[ ... ], ovvero avvolgere tutto in un elenco e restituire il suo primo elemento per rendere felice il controllo del tipo.

Per assicurarsi che nessuna parte della stringa di dati possa essere rimossa senza essere notata, la corrispondenza del modello in val-declarations torna utile: la lunghezza della stringa finale da stampare (e quindi la lunghezza del programma) dovrebbe essere 195, quindi possiamo scrivere let val t=... val 195=size t in print t endnel corpo fndell'astrazione invece che print(...). La rimozione di una parte della stringa comporta una lunghezza inferiore a 189, causando così Bindun'eccezione.

Rimane ancora un problema: l'intero val 195=size tcontrollo potrebbe essere semplicemente abbandonato. Possiamo impedirlo espandendo il controllo in modo che corrisponda a una tupla:, in modo val t=... val(216,u)=(n+size t,t)in print u endtale che la rimozione del controllo comporti una variabile non associata u.

Complessivamente, ciò produce la seguente soluzione di 195 byte:

val()=hd[(fn s=>let val t=s^"\""^String.toString s^"\")"val(195,u)=(size t,t)in print u end)"val()=hd[(fn s=>let val t=s^\"\\\"\"^String.toString s^\"\\\")\"val(195,u)=(size t,t)in print u end)"]

Applicare il trucco del golf sull'uso di nomi di variabili dell'operatore come !, $e %invece di n, te ual fine di risparmiare spazio bianco (vedere questo suggerimento ) porta alla versione finale di 182 byte.

Tutte le altre rimozioni di sottostringa che non sono state esplicitamente indicate nella spiegazione dovrebbero provocare una sintassi o un errore di tipo.

Modifica 1: length(explode t) è giusto size t.
Modifica 2: Grazie a Anders Kaseorg per un diverso approccio quine e la segnalazione di una "vulnerabilità".


-2 byte scrivendo "\""direttamente e usando String.toStringper scappare.
Anders Kaseorg,

Aspetta, questo è orribile: MLton sembra accettare il programma ", producendo output vuoto ( TIO ).
Anders Kaseorg,

@AndersKaseorg Huh, è strano. Tuttavia, dovrebbe essere possibile risolvere questo problema utilizzando un altro let ... in ... end.
Laikoni,

@AndersKaseorg Ho risolto il problema, si spera senza introdurre nuove "vulnerabilità".
Laikoni

In realtà ho esaminato MLton accettandolo "come programma, e sembra che il bug sia stato corretto in questo commit , quindi forse il tuo 182 o il mio 180 vanno bene purché specifichi la versione Git inedita di MLton.
Anders Kaseorg,
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.