";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))";str(chr 34)^it;(print(it^it);fn x=>print(x^it^x^it))
Versione non quotata : provalo su codingground.
Versione quotata: provalo su codingground.
Si noti che l'output è simile a questo
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
perché il codice viene interpretato dichiarazione per dichiarazione (ognuno ;termina una dichiarazione) e mostra il valore e il tipo di ogni dichiarazione.
sfondo
In SML c'è un quine del modulo <code>"<code in quotes>":
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
e uno nella forma "<code in quotes>"<code>:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
Entrambi si basano sul fatto che la <code>parte non contiene virgolette e può quindi essere quotata senza la necessità di sfuggire a qualsiasi cosa, i "necessari per produrre il quine sono dati dastr(chr 34) .
Si basano fortemente anche sull'identificatore implicito itche viene utilizzato quando non viene fornito un identificatore esplicito in una dichiarazione.
Nel primo quine si str(chr 34);lega italla stringa contenente ", fn x=>avvia una funzione anonima prendendo un argomento x, quindi concatena x^it^x^ite stampa la stringa risultante. Questa funzione anonima viene applicata direttamente a una stringa contenente il codice del programma, quindi la concatenazione x^it^x^itproduce <code>"<code>".
La seconda riga inizia con solo il codice del programma come stringa a ";str(chr 34)^it;print(it^it)";cui è associato it. Quindi str(chr 34)^it;concatena una citazione all'inizio della stringa e poiché non viene fornito alcun identificatore esplicito, la stringa risultante "<code>viene associata it. Infine print(it^it)concatena la stringa con se stessa cedendo "<code>"<code>che viene quindi stampata.
Spiegazione
Modifica: non più aggiornato con la versione da 108 byte, tuttavia è possibile capirlo anche dopo aver letto questa spiegazione.
Il quine sicuro di virgolette combina entrambi gli approcci di cui sopra ed è esso stesso della forma "<code>"<code>. Mettendolo di nuovo tra virgolette ""<code>"<code>", otteniamo una stringa vuota e poi una quinta dell'altra forma.
Ciò significa che al programma viene data la propria fonte nella forma "<code>dall'identificatore it, oppure itè giusta "e ci viene data la nostra fonte <code>come argomento e deve quindi essere una funzione che gestisce tale argomento.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
Per identificare in quale caso siamo, controlliamo se la dimensione di itè maggiore di 1. Altrimenti lo itè "e siamo nel secondo caso, quindi la elseparte restituisce una funzione anonima fn x=>print(it^it^x^it^x^it)che viene quindi chiamata perché è seguita da source come stringa . Nota il carattere iniziale it^it^necessario per la stringa vuota all'inizio del programma.
Se size itè maggiore di 1 siamo nella thenparte e ci esibiamo print(it^it), giusto? Non del tutto, perché ho trascurato di dirti che SML è fortemente tipizzato, il che significa che un condizionale if <cond> then <exp_1> else <exp_2>deve sempre avere lo stesso tipo, il che significa che le espressioni <exp_1>e <exp_2>devono avere lo stesso tipo. Conosciamo già il tipo di elseparte: una funzione anonima che prende una stringa e quindi chiama printha tipo string -> <return type of print>e printha tipo string -> unit( unitè in qualche modo simile ad voidaltre lingue), quindi il tipo risultante è di nuovostring -> unit .
Quindi, se la thenparte fosse proprio di print(it^it)tipo unit, avremmo un errore di mancata corrispondenza del tipo. E allora fn _=>print(it^it)? ( _è un jolly per un argomento che non viene utilizzato) Questa funzione anonima di per sé ha un tipo 'a -> unitdove 'asta per un tipo arbitrario, quindi nel contesto del nostro condizionale che impone un string -> unittipo che funzionerebbe. (La variabile type 'aviene istanziata con type string.) Tuttavia, in questo caso non stamperemmo nulla poiché la funzione anonima non viene mai chiamata! Ricorda, quando andiamo nella thenparte, il codice generale lo è "<code>"<code>, quindi la parte <code>restituisce una funzione ma, poiché nulla viene dopo di essa, non viene chiamata.
Invece usiamo un sequentialisation che ha la forma (<exp_1>; ...; <exp_n>)dove <exp_1>per <exp_n-1>può avere tipi arbitrari e il tipo di <exp_n>fornisce il tipo di tutta sequentialisation. Da un punto di vista funzionale i valori di <exp_1>to <exp_n-1>vengono semplicemente scartati, tuttavia SML supporta anche costrutti imperativi, quindi le espressioni possono avere effetti collaterali. In breve, prendiamo (print(it^it);print)come then-part, quindi prima stampando e poi restituendo la funzione printche ha il tipo corretto.