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 itqui 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^itet 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^itdonne<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 itjuste "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 itest supérieure à 1. Sinon, itest "et nous sommes dans le second cas, de sorte que les elserendements -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 itest plus grand que 1, nous sommes dans la thenpartie -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 elsepartie: Une fonction anonyme qui prend une chaîne et appelle ensuite printa type string -> <return type of print>, et printa type string -> unit( unitest en quelque sorte similaire à voiddans d'autres langues), donc le type résultant est à nouveau string -> unit.
Donc, si la thenpiè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 -> unitoù 'areprésente un type arbitraire, donc dans le contexte de notre conditionnel qui applique un string -> unittype, cela fonctionnerait. (La variable type 'aest 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 thenpartie -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 thenpartie -part, imprimant donc d'abord et retournant ensuite la fonction printqui a le bon type.