Ce défi est basé sur des Helka Homba question de la programmation d' une Pristine mondiale . De cette question, la définition d'un programme vierge est:
Définissons un programme vierge comme un programme qui ne contient aucune erreur lui-même mais qui provoquera une erreur si vous le modifiez en supprimant toute sous-chaîne contiguë de N caractères, où
1 <= N < program length
.Par exemple, le programme Python 2 à trois caractères
`8`
est un programme vierge ( merci, Sp ) car tous les programmes résultant de la suppression de sous-chaînes de longueur 1 provoquent des erreurs (des erreurs de syntaxe en fait, mais n'importe quel type d'erreur fera l'affaire):
8` `` `8
et aussi tous les programmes résultant de la suppression de sous-chaînes de longueur 2 provoquent des erreurs:
` `
Si, par exemple,
`8
avait été un programme sans erreur, il`8`
ne serait pas vierge car tous les résultats de la suppression de la sous-chaîne doivent être erronés.Remarques:
- Les avertissements du compilateur ne comptent pas comme des erreurs.
- Les sous-programmes en erreur peuvent prendre une entrée ou donner une sortie ou faire autre chose tant qu'ils font une erreur, peu importe ce qui finit par se produire.
Votre tâche consiste à créer un programme de longueur non nulle qui imprime exactement son propre code source, suit les règles d'un quine correct et est vierge.
La réponse la plus courte en octets pour chaque langue gagne.
Réponses:
Haskell , 132 octets
Essayez-le en ligne!
Ceci est une extension du quine
qui fonctionne en concaténant la chaîne de données avec une version citée (en utilisant
show
) d'elle-même et en imprimant le résultat. Cependant, ce n'est pas vierge car tous les caractères de la chaîne de données peuvent être supprimés sans échec et la partie$(++)<*>show$
ou(++)<*>
peut également être supprimée sans interruption du programme.Pour résoudre ce problème, une fonction d'impression personnalisée
q
est définie qui vérifie la longueur de la chaîne donnée et appellefail
si elle est inférieure à 132. Cela intercepte la suppression de toute séquence de la chaîne de données et également les suppressions de$(++)<*>show$
ou(++)<*>
, comme dans les deux cas, le résultat la chaîne passée àq
est plus courte.Dans
q
le nombre132
pourrait être réduit à1
,13
,32
ou2
, mais encore une fois dans chaque casfail
est appelé.Pour autant que je sache, la suppression de toute autre sous-chaîne provoque une erreur de syntaxe ou de type, de sorte que le programme ne compile même pas en premier lieu. (Le système de type strict de Haskell est utile ici.)
Edit: Merci à Ørjan Johansen et Shelvacu pour avoir signalé un défaut!
la source
fail[]|length x/=122
qu'on puisse l'enlever.fail[]:[putStr x|length x==122]
pourrait mieux fonctionner.|length x==122
pourrait être retiré.if length x==122 then putStr x else fail[]
peut-être?if then else
avant mais j'ai pensé que je pouvais le raccourcir.putStr x
peut devenirp x
, ce qui, lorsque j'ai essayé mon système, a fonctionné très longtemps avant de le tuer, je soupçonne que la récursivité des appels de queue a été optimisée, c'est donc une boucle infinie. Je ne connais pas suffisamment de haskell pour donner des suggestions sur la façon de le réparer.p
enq
devrait résoudre ce problème.Python 3 , 113 octets
Essayez-le en ligne!
Comment ça fonctionne
Nous ne pouvons pas facilement utiliser plusieurs instructions car la seconde pourrait être supprimée, nous commençons donc par une quine à expression unique:
Pour le protéger contre les suppressions de sous-chaîne, nous utilisons à la
open(1,"w").write
place deprint
. En Python 3,write
retourne le nombre de caractères écrits, que nous vérifierons113
pour nous assurer qu'aucune partie de la chaîne n'a été supprimée. Nous faisons cela en recherchant la valeur de retour dans le dictionnaire{113:[]}
et en parcourant le résultat avecfor[]in…:a
, qui échouera si nous n'avons pas obtenu d'itérable vide ou si l'for
instruction est supprimée.la source
Rubis, 78 octets
J'ai écrit cela quand j'ai pensé au défi pour m'assurer que c'était possible. Il utilise le même "wrapper" de l' une de mes réponses au défi original.
Explication:
eval(*[
expr])
Cela évalue tout code retourné en tant que programme ruby. Cela teste efficacement que la chaîne renvoyée par le code est un programme ruby valide. De manière pratique, les programmes rubis peuvent être vides ou uniquement constitués d'espaces.
L'opérateur "splat"
*
vous permet d'utiliser un tableau comme arguments d'une fonction. Cela signifie également que sieval
est supprimé, le programme résultant est(*[
expr])
, ce qui n'est pas un rubis valide.($>.write(
str)-78).chr
$>
est une variable courte pour STDOUT.$>.write(foo)
écrit foo dans STDOUT et, surtout pour ce code, retourne le nombre d'octets écrits.$>.write(foo)-78
: Voici78
la longueur du programme, et donc si le programme n'est pas modifié, sera également le nombre d'octets écrits. Par conséquent, dans le cas démêlé, cela retournera zéro.num.chr
renvoie num sous forme de caractère, par exemple0.chr
, renverra une chaîne contenant un seul octet nul. Dans le programme démêlé, cela donnera une chaîne avec un seul octet nul àeval
, qui est un programme ruby valide qui est un no-op.En outre, le programme peut avoir une sous-chaîne supprimée de sorte qu'elle soit juste
eval(*[(78).chr])
oueval(*[(8).chr])
, ce qui signifie que la constante numérique ne peut se terminer par aucun des nombres (0, 4, 9, 10, 11, 12, 13, 26, 32, 35, 48 , 49, 50, 51, 52, 53, 54, 55, 56, 57, 59, 64, 95) car ce sont des codes ascii pour des programmes rubis à un seul caractère valides.%{
str}
Il s'agit d'une syntaxe moins connue pour les littéraux de chaîne en ruby. La raison pour laquelle il est utilisé ici est que des paires équilibrées de
{}
peuvent être utilisées dans la chaîne, ce qui signifie que cette syntaxe peut se contenir. Par exemple,%{foo{bar}}
est identique à"foo{bar}"
.(s=%{
Les données})%s
Ceci définit la variable
s
qui est les données de ce quine, comme une chaîne printf.Les affectations en rubis renvoient ce qui a été attribué, c'est donc la même chose que la première affectation
s
puis l'exécutions%s
%
sur une chaîne est du sucre syntaxique pour l'équivalent rubis de sprintf. Le%s
signifie où, dans les données, les données elles-mêmes doivent être intégrées.Ce bit de code définit la partie données du quine et l'intègre en lui-même pour créer le code complet.
la source
Standard ML (MLton) ,
204182189 octetsEssayez-le en ligne!
Pour MLton, les programmes SML complets sont des expressions délimitées et terminées par
;
( par exempleprint"Hello";print"World";
) ou des déclarations avec les mots clésvar
etfun
(par exemplevar _=print"Hello"var _=print"World"
) où_
est un caractère générique qui pourrait également être remplacé par n'importe quel nom de variable.La première option est inutile pour une programmation vierge, car
;
en elle-même est un programme valide (qui ne fait rien, mais ne fait pas d'erreur non plus). Le problème avec la deuxième approche est que les déclarations commevar _=print"Hello"
peuvent être raccourcies à justevar _="Hello"
(ou mêmevar _=print
) parce que la déclaration avecvar
fonctionne tant que le côté droit est une expression ou une valeur SML valide (SML est un langage fonctionnel, donc les fonctions peuvent être utilisé comme valeur aussi).À ce stade, j'étais prêt à déclarer impossible une programmation vierge en SML, quand par hasard je suis tombé sur une correspondance de modèle dans les
val
déclarations. Il s'avère que la syntaxe des déclarations n'est pasval <variable_name> = <expression>
maisval <pattern> = <expression>
, où un modèle peut être composé de noms de variables, de constantes et de constructeurs. Comme laprint
fonction est de typestring -> unit
, nous pouvons utiliser un match de motif sur launit
-valeur()
pour faire respecter que la fonction d'impression est en fait appliquée à la chaîne:val()=print"Hey"
. Avec cette approche, la suppression de l'unprint
ou de l' autre"Hey"
entraîne unePattern and expression disagree
erreur.Avec cette façon d'imprimer à portée de main, la prochaine étape consiste à écrire une quine, avant enfin de rajouter de la sauvegarde. J'ai déjà utilisé une technique de quine SML simple (voir l' historique des révisions ), mais Anders Kaseorg a souligné une approche différente qui peut économiser quelques octets dans son cas. Il utilise la
String.toString
fonction intégrée pour gérer l'échappement de chaîne et est de la forme générale<code>"<data>"
, où se"<data>"
trouve une chaîne d'échappement de l'code
avant:Il s'agit d'un quine de travail mais pas encore vierge. Tout d'abord, Anders Kaseorg a découvert que MLton accepte une seule citation
"
comme code sans produire d'erreurs, ce qui signifie que nous ne pouvons pas avoir de code se terminant par une citation comme ci-dessus. Le moyen le plus court d'empêcher cela serait de tout envelopperval()=
dans une paire de parenthèses, mais le code pourrait alors être réduit àval()=()
. La deuxième façon la plus courte que j'ai trouvée est d'utiliserval()=hd[ ... ]
, c'est-à-dire que nous emballons tout dans une liste et retournons son premier élément pour rendre le vérificateur de type heureux.Pour vous assurer qu'aucune partie de la chaîne de données ne peut être supprimée sans être remarquée, la correspondance de
val
modèle dans les déclarations est à nouveau utile: la longueur de la chaîne finale à imprimer (et donc la longueur du programme) doit être égale à 195, donc nous pouvons écrirelet val t=... val 195=size t in print t end
dans le corps de l'fn
abstraction au lieu deprint(...)
. La suppression d'une partie de la chaîne entraîne une longueur inférieure à 189, provoquant ainsi laBind
levée d' une exception.Il reste un problème: tout le
val 195=size t
chèque pourrait simplement être abandonné. Nous pouvons éviter cela en développant la vérification pour qu'elle corresponde à un tuple:, deval t=... val(216,u)=(n+size t,t)in print u end
sorte que la suppression de la vérification entraîne une variable non liéeu
.Au total, cela donne la solution de 195 octets suivante:
L'application de l'astuce de golf consistant à utiliser des noms de variables d'opérateur comme
!
,$
et%
au lieu den
,t
etu
afin d'économiser de l'espace blanc (voir cette astuce ) conduit à la version finale de 182 octets.Toutes les autres suppressions de sous-chaînes qui, lorsqu'elles ne sont pas explicitement indiquées dans l'explication, devraient entraîner une erreur de syntaxe ou de type.
Edit 1:
length(explode t)
est justesize t
.Edit 2: Merci à Anders Kaseorg pour une approche de quine différente et en soulignant une "vulnérabilité".
la source
"\""
directement et en utilisantString.toString
pour l'échappement."
, produisant une sortie vide ( TIO ).let ... in ... end
."
tant que programme, et il semble que le bogue a été corrigé dans ce commit , alors peut-être que votre 182 ou mon 180 est correct tant que vous spécifiez la version Git non publiée de MLton.