Générateur de quine généralisé


19

Le défi

Dans ce défi, vous spécifiez une langue source S et une langue cible T . Votre tâche consiste à écrire le programme suivant Pdans la langue S. Si un programme valide Qdans la langue Test donné en entrée P, il affichera un programme valide Rdans la langue Tqui ne prend aucune entrée et ne sort pas Q(R), c'est-à-dire le programme Qappliqué au code source de R. De plus , vous devez présenter dans votre réponse un exemple de programme non trivial Q(le plus intéressant, le meilleur, bien que vous ne marquiez aucun point pour cela), le programme résultant Ret la sortie de R. C'est le code-golf, donc le code le plus court pour les Pvictoires.

En d'autres termes, il s'agit d'un défi d'écrire un "constructeur de quine universel" qui peut créer des types arbitraires de quines généralisés.

Clarifications

  • Vos langues source et cible peuvent être identiques.
  • Le programme Pdoit prendre une chaîne en entrée (depuis STDIN ou équivalent) et produire une chaîne (vers STDOUT ou équivalent), comme tout programme de sortie R.
  • Les programmes d'entrée Qdoivent également transformer une chaîne en une autre chaîne, mais leur forme est plus flexible: il peut s'agir de fonctions chaîne à chaîne, d'extraits de code qui modifient une variable avec un certain nom, d'extraits qui modifient la pile de données si votre langue cible en a un, etc. Vous pouvez également restreindre davantage la forme des Qen indiquant que, par exemple, ils ne peuvent contenir aucun commentaire. Cependant, vous devez être en mesure d'implémenter n'importe quelle fonction chaîne à chaîne calculable en tant que programme d'entrée Q, et vous devez indiquer explicitement comment ils fonctionnent et quelles contraintes supplémentaires vous leur imposez.
  • Le programme de sortie Rdoit vraiment être un quine (généralisé), il ne doit donc lire aucune entrée (entrée utilisateur, fichiers, etc.) sauf Qsi c'est le cas.
  • Les failles standard ne sont pas autorisées.

Un exemple

Supposons que je choisis Python comme langue source et Haskell comme langue cible, et que je demande en outre que le programme d'entrée soit une définition sur une ligne d'une String -> Stringfonction nommée f. Si je donne le programme d'inversion de chaîne

f x = reverse x

en entrée de mon programme Python P, il affichera le code source d'un autre programme Haskell R. Ce programme imprime dans STDOUT le code source de R, mais inversé. Si Preçoit la fonction d'identité

f x = x

en entrée, le programme de sortie Rest une quine.

Réponses:


7

Source = Cible = CJam, 19 17 16 octets

{`"_~"+}`)q\"_~"

Cela suppose que le programme d'entrée Q(donné sur STDIN) est un extrait CJam qui attend une chaîne en haut de la pile et laisse une autre chaîne en haut de la pile.

Testez-le ici.

Exemples

  1. L'identité ne serait qu'un extrait de code vide, laissant donc les impressions vides de STDIN

    {`"_~"+}_~
    

    Quel est le quine standard, avec un supplément +.

  2. Pour inverser une chaîne dans CJam, vous pouvez utiliser W%, donc en mettant cela sur STDIN, cela donne:

    {`"_~"+W%}_~
    

    que nous pouvons exécuter pour obtenir

    ~_}%W+"~_"`{
    
  3. Comme troisième exemple, disons que nous utilisons un extrait qui entremêle une chaîne avec des espaces: ' *. En cours Pd' exécution avec cela en entrée, nous obtenons

    {`"_~"+' *}_~
    

    qui à son tour imprime

    { ` " _ ~ " + '   * } _ ~  
    
  4. Il fonctionne désormais également s'il Qcontient des sauts de ligne (bien que cela ne soit jamais nécessaire dans CJam). Voici un programme avec un saut de ligne, qui supprime tous les sauts de ligne d'une chaîne (de manière inutilement alambiquée - divisé en lignes, puis joint):

    N/
    ""
    *
    

    Cela se traduit par ce qui suit R:

    {`"_~"+N/
    ""
    *}_~
    

    qui à son tour imprime

    {`"_~"+N/""*}_~
    

Explication

Regardons d'abord la sortie produite:

Le quine standard CJam est

{`"_~"}_~

Cela fonctionne comme suit:

  • Poussez le bloc {`"_~"}.
  • Dupliquez-le avec _.
  • Exécutez la copie avec ~.
  • Maintenant à l'intérieur du bloc, ` transforme le premier bloc en sa représentation sous forme de chaîne.
  • "_~" pousse les deux caractères de la source qui ne font pas partie du bloc (et donc manquent dans la représentation de la chaîne).
  • Les deux chaînes sont imprimées dos à dos à la fin du programme.

Dans la configuration de base, le `n'est pas nécessaire, car si vous laissez simplement le bloc tel quel, il est tout de même imprimé à la fin du programme.

La sortie de mon programme Pest une version modifiée de cet extrait. Tout d'abord, j'ai ajouté un +au bloc, qui concatène les deux chaînes en une seule chaîne contenant la source entière. Notez que cela sera vrai peu importe ce que je fais à l'intérieur du bloc, car tout cela sera ajouté à la représentation de chaîne obtenue avec `. Maintenant, je peux simplement mettre le programme / extrait de code Qà l'intérieur du bloc après le +, afin qu'il puisse modifier la chaîne source avant son impression. Encore une fois, depuisQ va à l'intérieur du bloc, il fera partie de ladite chaîne source.

En résumé, les Pimpressions

{`"_~"+Q}_~

Maintenant, pour savoir comment je construis cette sortie dans P:

{`"_~"+}         "Push the block without Q.";
        `        "Turn it into a string. This is shorter than writing a string right away,
                  because I'd have to escape the quotes, and I'd need two quotes instead of
                  one backtick.";
         )       "Pop off the last character (the brace) and push it on the stack.";
          q      "Read input Q.";
           \     "Swap Q with the brace.";
            "_~" "Push the final two characters.";

Les quatre chaînes sont imprimées automatiquement (dos à dos) à la fin du programme.


1
Eh bien, c'était rapide! Et certainement difficile à battre. L'explication est belle aussi.
Zgarb

Où avez-vous appris que W% s'inverse? dl.dropboxusercontent.com/u/15495351/cjam.pdf ne l'a pas
Faraz Masroor

Existe-t-il une liste plus complète de méthodes?
Faraz Masroor

@FarazMasroor sourceforge.net/p/cjam/wiki/Basic%20operators/#percent (no. 3) ... c'est une fonctionnalité empruntée à GolfScript et à un moment donné, quelqu'un m'a dit que cela fonctionnait dans GolfScript. Cela semble être un idiome si commun que c'est une connaissance implicite étrange que chaque utilisateur de CJam / GS possède, mais qui n'est pas réellement expliquée dans beaucoup d'endroits. (Pour plus d'opérateurs, pas complètement documentés, voir sourceforge.net/p/cjam/wiki/Operators )
Martin Ender

3

Expressions Haskell → Expressions Haskell, 41 octets

((++)<*>show).('(':).(++")$(++)<*>show$")

Essayez-le en ligne!

Comment ça fonctionne

P $ "Q"= ((++)<*>show).('(':).(++")$(++)<*>show$") $ "Q"construit "R"par

  1. (++")$(++)<*>show$"): ajout de la chaîne ")$(++)<*>show$" ,
  2. ('(':): ajouter le caractère au début '(' , et
  3. (++)<*>show(= \x->x++show x): en ajoutant une version citée de cela,

résultant en "R"= "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\"".

R= (Q)$(++)<*>show$"(Q)$(++)<*>show$"fonctionne par

  1. prendre la ficelle "(Q)$(++)<*>show$",
  2. (++)<*>show: en ajoutant une version citée de cela,
  3. s'appliquant Qà cela,

résultant en Q "(Q)$(++)<*>show$\"(Q)$(++)<*>show$\""= Q "R".

(Les parens autour Qsont nécessaires car ils Qpeuvent contenir $aussi facilement que Rcela et $malheureusement, ils sont associatifs à droite.)

Démo

λ> putStrLn $ ((++)<*>show).('(':).(++")$(++)<*>show$") $ "id"
(id)$(++)<*>show$"(id)$(++)<*>show$"
λ> putStrLn $ (id)$(++)<*>show$"(id)$(++)<*>show$"
(id)$(++)<*>show$"(id)$(++)<*>show$"
λ> putStrLn $ ((++)<*>show).('(':).(++")$(++)<*>show$") $ "reverse"
(reverse)$(++)<*>show$"(reverse)$(++)<*>show$"
λ> putStrLn $ (reverse)$(++)<*>show$"(reverse)$(++)<*>show$"
"$wohs>*<)++($)esrever("$wohs>*<)++($)esrever(
λ> putStrLn $ ((++)<*>show).('(':).(++")$(++)<*>show$") $ "length"
(length)$(++)<*>show$"(length)$(++)<*>show$"
λ> print $ (length)$(++)<*>show$"(length)$(++)<*>show$"
44

Pas seulement $besoin des parenthèses, mais aussi de fuite let, doou des expressions lambda.
Ørjan Johansen

@ ØrjanJohansen C'est vrai, mais j'aurais pu définir un sous-ensemble de langage qui interdit le lambda sans parenthèse / let/ if/ case/ dosi je ne les émets pas moi-même. C'est peut-être aussi bien que je n'étais pas obligé de le faire.
Anders Kaseorg

2

Source = Cible = JavaScript, 66

console.log("function a(){console.log("+prompt()+"(a+'a()'))}a()")

Hypothèses pour Q:

  • Q doit être une fonction anonyme JavaScript chaîne à chaîne.

Exemples:

  • Inverser . Q =function(s) { return s.split('').reverse().join(''); }

Dans ce cas, P(Q)(ou R) sera:, function a(){console.log(function(s) { return s.split('').reverse().join(''); }(a+'a()'))}a()et en l'exécutant, nous obtiendrons: )(a}))')(a'+a(} ;)''(nioj.)(esrever.)''(tilps.s nruter { )s(noitcnuf(gol.elosnoc{)(a noitcnufqui est exactement le même que Q(R).

  • Identité . Q =function(s) { return s; }

dans ce cas, P(Q)(ou R) sera: function a(){console.log(function(s) { return s; }(a+'a()'))}a()qui est une Quine JavaScript . Inutile de dire que ce Q(R)sera la même chose, puisque Q est la fonction d'identité.


Quelques notes:

STDIN en JavaScript est traditionnellement prompt(), cependant, je me suis permis de m'abstenir de la tradition de alert()STDOUT, afin de faciliter le processus de sortie en tant que programme utilisant le copier-coller. (Je me rends compte que je peux enregistrer jusqu'à 12 caractères lors du passage à alert()).

Je peux également raccourcir les choses dans ES6, mais je veux rester avec JavaScript natif pour l'instant. J'envisage de soumettre une réponse S = Scala, T = ECMA6 à l'avenir, juste pour l'expérience.

Je réalise également que JavaScript ne peut presque jamais battre CJam en , mais j'ai dû relever ce défi! C'était sûrement amusant.


Merci! Il serait en effet cool d'avoir une entrée avec différentes langues source et cible.
Zgarb

2

Gelée7 , 9 octets

“ṚƓ^ṾṂ’³3

Essayez-le en ligne!

Q est une fonction 7 (c'est-à-dire qui ne regarde pas au-delà de l'élément supérieur de la pile et effectue des E / S via la pile) et est donnée comme argument de ligne de commande.

Explication

Le programme 7

Le constructeur de quine universel dans 7 que j'utilise ici est:

717162234430…3

La première chose à noter est que le 7 en tête est l'équivalent du premier espace et n'a aucun effet sur le programme. La seule raison pour laquelle il existe est d'obéir aux règles de PPCG contre les quines uniquement littérales (il est codé par le second 1dans le programme plutôt que lui-même).

Le reste du programme est un élément de pile unique (il a équilibré 7s et 6s), qui fait ce qui suit lors de l'exécution:

717162234430…3
 1716           Push a stack element "7" onto the stack
     2          Copy it
      23        Pop and output one of the copies (selecting format 7)
        4430    Prepend it to the top of stack
             3  Output it

En d'autres termes, cet élément de pile est un programme qui imprime le haut de la pile, avec 7préfixé, au format de sortie 7 (ce qui signifie "imprimer littéralement, en utilisant le même codage que le code source", et est donc clairement le meilleur codage pour quines). Il est assez heureux ici que nous puissions réutiliser le littéral 7à deux fins (le format de sortie et le premier espace blanc.) De toute évidence, en insérant quelque chose juste avant la finale 3, nous pouvons produire une fonction de 7+ l'entrée, plutôt que de simplement sortir 7et entrée directement.

Comment cet élément de pile obtient-il son propre code source? Eh bien, lorsque la fin du programme est atteinte, 7 evals l'élément de pile supérieur par défaut. Cependant, il n'est pas réellement sorti de la pile dans le processus, donc le littéral d'élément de pile qui a été evalmené est toujours là. (En d'autres termes, le programme ne lit pas sa propre source - comme en témoigne le fait qu'il est incapable de voir le 7au début du programme, qui est un séparateur d'éléments de pile plutôt qu'une partie d'un littéral - mais plutôt, il se compose principalement d'un littéral qui est evaldirigé par défaut.)

Le programme Jelly

C'est peut-être l'un des programmes Jelly les moins jelly que j'ai écrits; il se compose de trois nilads ( “ṚƓ^ṾṂ’, ³, 3), qui sont juste en sortie car aucune séquence les opérations sont effectuées sur eux. Le 3est assez évident, juste être une constante entière. Ce³ est aussi simple si vous connaissez Jelly: c'est la notation explicite de Jelly pour le premier argument de ligne de commande (qui est l'endroit où Jelly prend généralement son entrée). Le reste du programme Jelly représente la majeure partie de mon constructeur universel de quine 7: en exploitant le fait que toutes les commandes de 7 peuvent être représentées à l'aide de chiffres ASCII, nous pouvons interpréter717162234430non pas comme une série de commandes, ou même comme un nombre octal (comme c'est conceptuellement), mais comme un nombre décimal, ce qui signifie que nous n'avons pas besoin d'un formatage spécial pour la sortie. Ce nombre décimal devient “ṚƓ^ṾṂ’dans la notation entière compressée de Jelly.

Exemple

Si nous donnons 24053comme programme Q, nous obtiendrons la sortie suivante:

717162234430240533

Essayez-le en ligne!

2405 concatène l'élément de pile supérieur à lui-même:

2405   Stack   Explanation
       x
2      x|x     Duplicate top of stack
 4     x||x    Swap two stack elements, with an empty element between
  0    x|(X)   Escape the top stack element, then concatenate the top two
   5   xx      Execute the top stack element

(La dernière étape peut sembler un peu déroutante; ce qui se passe est que l'échappement d'un élément de pile convertit chaque commande qu'il contient de "exécuter cette commande" en "ajouter cette commande en haut de la pile", donc chaque commande s'ajoute à l'original l'élément supérieur de la pile pendant son exécution.)

En tant que tel, l'exécution du programme résultant R nous donne deux copies de R:

7171622344302405371716223443024053

2

CJam → CJam, 13 octets

{`"_~"+7}_~qt

Essayez-le en ligne!

L'entrée Qdoit être un extrait de code qui modifie la seule chaîne de la pile. Qest lu depuis stdin.

Exemple

Contribution:

S*W%

Il ajoute un espace entre tous les deux caractères et inverse la chaîne.

Production:

{`"_~"+S*W%}_~

Sortie du quine généralisé:

~ _ } % W * S + " ~ _ " ` {

Explication

{`"_~"+7}_~      e# Evaluate a generalized quine in CJam that only appends a 7.
q                e# Read the input.
t                e# Replace the 7th character (0-based) with the input.

Il évalue d'abord le quine, afin que nous puissions obtenir sa représentation sous forme de chaîne sans guillemets inutiles. Remplacez ensuite la charge utile par l'entrée.

Cela pourrait être l' {`"_~"+ }_~7qtendroit où l'espace est l'espace réservé de la charge utile. Mais changer la charge utile pour 7économiser un octet.


1

FusainPerl (5), 29 33 octets

A$_=q(αA);evalβαS"\α$_β\n";printβ

Essayez-le en ligne!

Le programme Perl Q doit renvoyer un extrait qui prend l'entrée sous forme de chaîne à sa droite et fournit une sortie dans la variable $_. (Les fonctions Perl arbitraires peuvent être converties dans ce formulaire en les encapsulant comme sub x {…}; $_=x. Dans la plupart des cas, cependant, la syntaxe de Perl signifie qu'aucun encapsulage n'est requis.)

Explication

Le Perl

Voici à quoi ressemble le constructeur de quine universel Perl:

$_=q(…"\$_=q($_);eval";print);eval

(Dans la plupart des cas, vous voudrez jouer au golf $_=q(say…"\$_=q($_);eval");eval, mais je ne suis pas sûr que vous puissiez insérer du code Perl arbitraire dans le .)

En d'autres termes, nous avons un wrapper extérieur $_=q(…);evalqui attribue une chaîne à $_, puis l'évalue. À l'intérieur de l'emballage "\$_=q($_);eval", c'est-à-dire une reconstruction de l'emballage avec son contenu via l'utilisation de la valeur que nous avons stockée dans$_ , plus le code Q spécifié par l'utilisateur, plus printpour imprimer la sortie. (Malheureusement, nous ne pouvons pas l'utiliser say; cela ajoute une nouvelle ligne, et c'est pertinent dans les quines.)

Le charbon de bois

Le "point" de cette réponse était de produire des quines généralisées en Perl, donc une fois que j'ai eu une stratégie de golf pour le faire (celle que j'ai utilisée dans de nombreuses autres réponses), il était temps d'écrire le programme P, qui ne fait que remplacer une chaîne dans un modèle. Ce que je voulais ici, c'était un langage qui était bon pour imprimer des chaînes constantes (idéalement les compresser un peu), et pour y interpoler les entrées utilisateur.

Après avoir essayé quelques-uns, je me suis installé sur Charcoal, que je n'ai jamais utilisé auparavant (et qui pourrait vraiment faire avec de la documentation); il est conçu pour l'art ASCII mais capable d'écrire des chaînes dans une dimension aussi. Les caractères ASCII sont imprimés littéralement dans Charcoal, ce qui signifie que l'impression de chaînes constantes ne prend pas de passe-partout, et nous pouvons utiliser la commande pour interpoler une chaîne prise à partir de l'entrée utilisateur dans le programme.

Il est cependant possible d'aller (légèrement) plus court. Le constructeur de quine universel Perl contient deux sections répétées assez longues. Nous pouvons donc utiliser la commande pour les affecter à des variables (par exemple, des A…αassignations à la variable α), et simplement interpoler les variables dans la chaîne que nous imprimons en utilisant leurs noms. Cela économise quelques octets sur l'écriture littérale de la chaîne.

Malheureusement, Charcoal ajoute également une nouvelle ligne au programme, mais ce n'est pas une grosse affaire; il en coûte simplement deux octets à an \npour ajouter cette nouvelle ligne à l'entrée de Q également.

Exemple

Si nous donnons l'entrée $_=reverse(qui inverse une chaîne), nous obtenons la sortie suivante:

$_=q($_=reverse"\$_=q($_);eval\n";print);eval

Essayez-le en ligne!

qui est un quine-like qui imprime sa source à l'envers, comme prévu.


1

GeléeSous - charge , 15 octets

“(a(:^)*“S):^”j

Essayez-le en ligne!

Prend la fonction de sous-charge d'entrée Q comme un argument de type commande. Q doit prendre l'entrée de la pile et pousser la sortie vers la pile, sans tenter d'inspecter les éléments de pile plus profonds (car ils n'existeront pas).

Explication

La sous-charge

Le constructeur de quine universel Underload utilisé ici est:

(a(:^)*…S):^

La plupart du programme est un seul littéral. Nous suivons cela par :^, qui le copie, puis évalue une copie (en laissant l'autre copie sur la pile).

Lorsque le littéral commence à évaluer, nous exécutons a(escape, qui le ramène sous la même forme que le programme original A), et (:^)*(qui s'ajoute :^), reconstruisant ainsi le code source du programme entier. Nous pouvons ensuite exécuter la fonction Q pour transformer cela de manière arbitraire et imprimer le résultat avec S.

La gelée

Je ne peux pas utiliser Charcoal cette fois car un interpréteur de validation de sous-charge se bloque à la fin du programme si le programme se termine par une nouvelle ligne. (Certains interprètes de sous-charge, comme celui sur TIO, n'appliquent pas cette règle, mais je voulais être correctement portable.) Malheureusement, Charcoal ajoute naturellement des nouvelles lignes à sa sortie. Au lieu de cela, j'ai utilisé Jelly, qui est presque aussi laconique dans des cas simples comme celui-ci; le programme se compose d'une liste littérale avec deux éléments ( ““”), et les joint sur l'entrée ( j), interpolant ainsi l'entrée utilisateur dans le programme.

Exemple

En utilisant l'entrée :S^(imprimer une copie, puis évaluer l'original), nous obtenons le programme Underload suivant:

(a(:^)*:S^S):^

Essayez-le en ligne!

Cela s'imprime infiniment de fois, d'une manière assez intéressante: après avoir fait le comportement normal de quine, il s'exécute ensuite evalsur une copie de ce qu'il a sorti. Cela provoque le programme reconstruit entier pour s'exécuter à nouveau, indéfiniment (Underload est récursif de queue). Quining et faire un evalest en fait la seule façon de faire une boucle infinie dans Underload.


Charcoal n'ajoute plus de nouvelles lignes de fin (yay)
ASCII uniquement

1

RProgN 2 , 11 octets

'{`{.%s}{'F

Explication du programme

'{`{.%s}{'F
'{`{.%s}{'  # Push the string "{`{.%s}{" to the stack.
          F # Format the input with the top of the stack as a template. Which produces {`{.<INPUT>}{

Quine Explication

Le quine qui est produit est simple, mais utilise la fonctionnalité de gestionnaires de fonctions inégalés dans RProgN2 pour créer un quine court et doux, appelé quine "Looping". C'est un concept étonnamment similaire à un <> <quine.

{`{.}{
{`{.}   # Push the function {`{.} to the stack.
     {  # Try to define a new function, fail, loop back to index 1. (Which in turn, skips the function definition.)
 `{     # Push the string "{" to the stack.
   .    # Concatenate the top two values of the stack, which stringifies the function, then appends { to it.
    }   # Try to terminate a function, fail quietly, and terminate the program.

Bien sûr, en raison de la structure de ce quine, tout sauf les vrais no-ops (qui ne sont pas stringifiés) peuvent être placés après la fonction de concaténation, et

Quelques quines

  • {`{.i}{: Sorties {}i.{`{. iest juste la fonction "inverse", donc ce programme sort lui-même inversé.
  • {`{.S§.}{: Sorties ..S`{{{}§. Sconvertit la chaîne en une pile de caractères, §trie la pile lexographiquement, puis la .rassemble à nouveau, sortie elle-même triée.

Essayez-le en ligne!

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.