StandardML , 182 176 108 octets
";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))
Version non cotée : essayez-la sur codingground.
Version citée: Essayez-la sur codingground.
Notez que la sortie ressemble à ceci
> val it = "{some string}" : string
> val it = "{some string}" : string
{output to stdout}> val it = fn : string -> unit
car le code est interprété déclaration par déclaration (chacun ;
termine une déclaration) et montre la valeur et le type de chaque déclaration.
Contexte
En SML, il y a un quine de la forme <code>"<code in quotes>"
:
str(chr 34);(fn x=>print(x^it^x^it))"str(chr 34);(fn x=>print(x^it^x^it))"
et un sous la forme "<code in quotes>"<code>
:
";str(chr 34)^it;print(it^it)";str(chr 34)^it;print(it^it)
Les deux s'appuient sur le fait que la <code>
partie-ne contient pas de guillemets et peut donc être citée sans avoir besoin de s'échapper quoi que ce soit, les éléments "
nécessaires pour sortir le quine sont donnés parstr(chr 34)
.
Ils s'appuient également fortement sur l'identifiant implicite it
qui est utilisé quand aucun identifiant explicite n'est donné dans une déclaration.
Dans le premier quine str(chr 34);
se lie it
à la chaîne contenant "
, fn x=>
démarre une fonction anonyme prenant un argument x
, puis concatène x^it^x^it
et imprime la chaîne résultante. Cette fonction anonyme est directement appliquée à une chaîne contenant le code du programme, donc la concaténation x^it^x^it
donne<code>"<code>"
.
La deuxième quine commence avec juste le code du programme en tant que chaîne ";str(chr 34)^it;print(it^it)";
qui est liée à it
. str(chr 34)^it;
Concatène ensuite une citation au début de la chaîne et comme encore aucun identificateur explicite n'est donné, la chaîne résultante "<code>
est liée à it
. Enfin print(it^it)
concatène la chaîne avec elle-même, "<code>"<code>
qui est ensuite imprimée.
Explication
Edit: n'est plus à jour avec la version 108 octets, mais on pourrait aussi le comprendre après avoir lu cette explication.
Le quine sans danger pour les devis combine les deux approches ci-dessus et est lui-même de la forme "<code>"<code>
. Remettre cela entre guillemets donne ""<code>"<code>"
donc une chaîne vide, puis une quine de l'autre forme.
Cela signifie que le programme reçoit soit sa propre source sous la forme "<code>
de l'identifiant it
, soit it
juste "
et nous recevons notre propre source <code>
comme argument et doit donc être une fonction qui gère un tel argument.
(if size it>1then(print(it^it);fn _=>())else fn x=>print(it^it^x^it^x^it))
Pour identifier dans ce cas , nous sommes, nous vérifions si la taille it
est supérieure à 1. Sinon, it
est "
et nous sommes dans le second cas, de sorte que les else
rendements -Part une fonction anonyme fn x=>print(it^it^x^it^x^it)
qui est alors appelé parce que son suivi par la source en tant que chaîne . Notez le it^it^
début qui est nécessaire pour la chaîne vide au début du programme.
Si size it
est plus grand que 1, nous sommes dans la then
partie -et exécutons juste print(it^it)
, non? Pas tout à fait, car j'ai négligé de vous dire que SML est fortement typé, ce qui signifie qu'un conditionnel if <cond> then <exp_1> else <exp_2>
doit toujours avoir le même type, ce qui signifie à nouveau que les expressions <exp_1>
et <exp_2>
doivent avoir le même type. Nous connaissons déjà le type de la else
partie: Une fonction anonyme qui prend une chaîne et appelle ensuite print
a type string -> <return type of print>
, et print
a type string -> unit
( unit
est en quelque sorte similaire à void
dans d'autres langues), donc le type résultant est à nouveau string -> unit
.
Donc, si la then
pièce était juste de print(it^it)
type unit
, nous obtiendrions une erreur de non-correspondance de type. Et alors fn _=>print(it^it)
? (_
est un caractère générique pour un argument qui n'est pas utilisé) Cette fonction anonyme en elle-même a un type 'a -> unit
où 'a
représente un type arbitraire, donc dans le contexte de notre conditionnel qui applique un string -> unit
type, cela fonctionnerait. (La variable type 'a
est instanciée avec type string
.) Cependant, dans ce cas, nous n'imprimerions rien car la fonction anonyme n'est jamais appelée! Rappelez-vous, lorsque nous allons dans la then
partie -le code global est "<code>"<code>
, donc le<code>
partie -évalue une fonction mais, comme rien ne vient après, elle n'est pas appelée.
Au lieu de cela , nous utilisons un sequentialisation qui a la forme (<exp_1>; ...; <exp_n>)
où <exp_1>
à <exp_n-1>
peut avoir des types arbitraires et le type de <exp_n>
fournit le type de l'ensemble sequentialisation. D'un point de vue fonctionnel, les valeurs de <exp_1>
à<exp_n-1>
sont simplement ignorées, mais SML prend également en charge les constructions impératives afin que les expressions puissent avoir des effets secondaires. En bref, nous prenons (print(it^it);print)
la then
partie -part, imprimant donc d'abord et retournant ensuite la fonction print
qui a le bon type.