Boucle auto-destructive la plus courte


61

Votre tâche est d'écrire un programme complet ou une fonction qui ne prend pas d' entrée et fonctionne tout type de boucle ( while, for, foreach, do, do-while, do-loop, goto, récursivité, etc.) qui prendra fin en provoquant une erreur, ce qui signifie que le programme doit cesser de se courir et sortie.

Règles:

  1. L'erreur doit être une erreur d'exécution, une exception non gérée ou tout ce qui cause la fin du programme.
  2. L'erreur doit produire l'arrêt et la sortie du programme sans appeler explicitement exit;(ou équivalent) à un moment donné.
  3. Des messages comme Warning:, Notice:, etc, qui ne causent pas le programme lui - même fin ne sont pas valides. Par exemple, en PHP, les divisions par zéro génèrent un Warningmessage, mais le programme ne s’arrête pas et s’exécute quand même, ce n’est pas une réponse valable.
  4. La boucle doit exécuter au moins un cycle complet. En d'autres termes, l'erreur peut se produire à partir du deuxième cycle et plus. Cela permet d'éviter l'erreur en utilisant une syntaxe de code incorrecte: le code doit être syntaxiquement correct.
  5. La boucle peut même être infinie (exemple for(;;);) si elle respecte les règles susmentionnées, mais ne doit pas prendre plus de 2 minutes pour se terminer par une erreur d'exécution.
  6. La récursivité sans optimisation d'appel final n'est pas valide ( 1 , 2 ).
  7. C'est du donc le code le plus court gagne.
  8. Les failles standard sont interdites.

Exemple C # ( test en ligne ):

using System;
public class Program {
    public static void Main() {
        int i;
        int[] n;
        n = new int[5];
        for(i=0; i<7; i++) {
            n[i] = i;
            Console.WriteLine(n[i]);
        }
    }
}


Output: 

0
1
2
3
4
Run-time exception (line 9): Index was outside the bounds of the array.

Stack Trace:

[System.IndexOutOfRangeException: Index was outside the bounds of the array.]
  at Program.Main(): line 9

Classement:

var QUESTION_ID=104323,OVERRIDE_USER=59718;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important;font-family:Arial,Helvetica; font-size:12px}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

Merci à Martin Ender pour l' extrait de classement


Soyons clairs: la récursivité sans TCO peut être utilisée à condition que l’erreur ne soit pas liée à une récursion excessive, exact? (Par exemple, une fonction récursive qui
commet

Dennis: "Il pourrait être difficile de décider si un cycle complet est terminé dans ce cas [de récursion]. La récursion de la queue correspond à la facture, mais seul TCO termine réellement un cycle si l'exécution est annulée. par une erreur. [...] Je dirais que la récursivité sans TCO est invalide. "
Mario

En for(a;b;c)d;, après quelle déclaration se termine le premier cycle? Est-il valide d'interrompre la première évaluation d'une cdéclaration?
Hedi

1
@Hedi Voici mon humble avis (pas le PO): toutes les inscriptions doivent compléter un cycle complet, ce qui signifie qu'elles doivent entrer dans un deuxième cycle; cela signifie qu'au moins une instruction est exécutée une seconde fois. Dans votre exemple a, b, d, c, b, d, c, ..., l'ordre d'exécution best le début du cycle et doit être exécuté au moins une seconde fois.
ETHproductions

2
Je ne veux pas causer d'ennuis, mais comme le programme (de ce fait-là) n'est censé prendre aucune entrée, toutes les solutions récursives ayant un paramètre sont non valides, car un paramètre est entré.
BrainStone

Réponses:


33

MATL , 5 1 octet

Idée tirée de la réponse CJam de @ MartinEnder

`

Essayez-le en ligne!

`    % Do...while loop
     % Implicit end. The loop continues if the top of the stack is true.
     % After the first iteration, since the stack is empty, the program 
     % implicitly tries to take some non-existing input, and finishes
     % with an error

Ancienne version

2:t"x

Essayez-le en ligne!

2:   % Push [1 2]
t    % Duplicate
"    % For each (i.e. do the following twice)
  x  %   Delete top of the stack. Works the first time. The second it tries to
     %   implicitly take some non-existing input, and finishes with an error

3
Fonctionne hors ligne aussi. Aucune entrée signifie que vous pouvez supposer une entrée vide.
Dennis

@Dennis Hm, le programme hors ligne continuera d'attendre les entrées de l'utilisateur. La saisie est interactive, c’est-à-dire demandée au besoin dans la version hors ligne. Donc, le programme va attendre indéfiniment. Pas sûr que ça compte?
Luis Mendo

Vous ne savez pas exactement comment MATL fonctionne en interne, mais si vous l'exécutez dans un environnement incapable de demander une entrée (telle que le backend de TIO), il ne sera pas en mesure d'obtenir une entrée. En outre, vous devez autoriser l'envoi d'une entrée vide en appuyant sur Ctrl-D ou l'équivalent dans un système d'exploitation.
Dennis

35

Python, 16 octets

L'approche non intéressante de la division 0:

for x in 1,0:x/x

La première itération est calculée 1 / 1, ce qui fonctionne bien. La deuxième itération essaie de calculer 0 / 0, ce qui entraîne un ZeroDivisionErrorrejet.

17 octets (favori personnel)

i=1
while i:del i

Au début, i=1ce qui est la vérité, la boucle est entrée.

La première fois que la boucle est exécutée, la variable iest supprimée.

Cela signifie que la deuxième fois, in’est plus une variable et que, par conséquent, son évaluation échoue avecNameError: name 'i' is not defined.


Une autre solution de 15 octets serait def _():_()(newline) _(), car Python n’optimise pas la récursion des queues. Cependant, cela viole la règle n ° 6.


La solution de 17 octets fonctionne également si vous remplacez while ipar while 1car elle tente de supprimer à inouveau.
user6245072

2
@ user6245072 Oui, les deux extraits peuvent être modifiés de manière triviale pour de nombreuses solutions de travail
FlipTack

Vous pouvez utiliser votre deltruc avec un intégré pour raser un peu plus: while 1:del id.
DSM


18

Gelée , 3 2 octets

Ṿß

Se tue en manquant de mémoire. Le fait localement après environ 100 secondes.

Essayez-le en ligne! (certificat de décès dans le tiroir Debug )

Comment ça fonctionne

Ṿß  Main link. Argument: x. Implicit first argument: 0

Ṿ   Uneval; yield a string representation of x.
 ß  Recursively call the main link.
    Jelly uses TCO, so the first cycle finishes successfully before entering
    the next one.

Les premières itérations donnent:

'0'
'”0'
'””,”0'
'””,””,”,,””,”0'
'””,””,”,,””,””,”,,””,”,,”,,””,””,”,,””,”0'
'””,””,”,,””,””,”,,””,”,,”,,””,””,”,,””,””,”,,””,”,,”,,””,””,”,,””,”,,”,,””,”,,”,,””,””,”,,””,””,”,,””,”,,”,,””,””,”,,””,”0'

Après cela, ça devient vraiment moche, très vite.


Quelles sont les limites de la mémoire de la gelée?
Tuskiomi

Jelly n’a pas de limite de mémoire explicite, donc tout ce que Python peut adresser. Cependant, l'utilisation de la mémoire double à chaque itération. Cela devrait donc épuiser assez rapidement toute la mémoire disponible.
Dennis

28
Donc, tous les 2 ans, nous pourrons exécuter une autre itération
tuskiomi

Alors, la condition n ° 5 échouera-t-elle sur une machine lente avec beaucoup de RAM?
Mad Physicist

@MadPhysicist C'est correct. Il s’agit toutefois d’un problème inhérent aux délais. La conformité dépend beaucoup de la machine sur laquelle le programme est exécuté.
Dennis

13

V , 2 octets

òl

Essayez-le en ligne!

C'est le challenge parfait pour V car je le fais déjà tout le temps! En fait, V n’a même pas de condition, il n’a que des fonctions qui s’ajoutent à une erreur. Dans ce cas, les òmoyens "répète pour toujours" et les lmoyens "vont à droite".

Dans un tampon vide (pas d'entrée), cela se cassera lors du premier passage et ne produira aucune sortie. S'il est entrée, il se brisera une fois que nous allons afficher le dernier caractère d'entrée et de sortie tous l'entrée (ce qui en fait un programme de chat)


3
Attendez, ça lveut dire "bouge bien"? Pas "bouger left"?
Conor O'Brien

1
@ ConorO'Brien yep. Il y a en fait de bonnes raisons historiques à cela.
DJMcMayhem

3
Le défi nécessite des réponses qui échouent à la deuxième itération ou plus tard, pas à la première itération.
Martin Ender

11

JavaScript (ES6), 13 octets

f=_=>f(_?a:1)

C'est une fonction récursive qui fonctionne bien une fois, puis jette ReferenceError: a is not definedet quitte.

Voici une version non ES6 de 15 octets:

for(i=0;;)i=i.a

Cela fonctionne bien une fois, puis jette TypeError: i is undefinedet quitte.


10

Bash 4.2, 22 octets

exec $0 $@ $[2**$#%-1]

Ne fonctionne pas dans TIO car il contient Bash 4.3 et le bogue sur lequel je me base a finalement été corrigé.

Vérification

$ xxd -c 22 -g 22 self-destruct
0000000: 6578656320243020244020245b322a2a2423252d315d  exec $0 $@ $[2**$#%-1]
$ ./self-destruct
Floating point exception

Cela se bloque lorsque le programme essaie de calculer 2 63 mod -1 , ce qui bloque dans Bash 4.2 et les versions antérieures en raison d'un bogue connu.


10

PHP, 22 21 20 18 octets

Cela repose sur PHP permettant de donner un nom de fonction à une variable et d’essayer de l’exécuter.

Ceci concatène simplement le nom de la pifonction deux fois. Cela tue PHP avec un Fatal Error: Uncaught Error: Call to undefined function pipi() in [...][...].

while($x.=pi)$x();

Cela fonctionne comme mon ancienne réponse.


Ancienne réponse, 20 octets

PHP vous permet d'incrémenter des caractères, en utilisant l'opérateur d'incrémentation. Cela ne fonctionne que sur la a-zplage, mais cela suffit.

for($x=pi;;)$x=$x();

Je crois que cela remplit tous les points requis et que la boucle ne court qu'une fois.

Vous pouvez voir si, parce que vous obtiendrez l'erreur Fatal error: Function name must be a string.


Comment ça marche, étape par étape:

  • Attribuer pià $x.
    Puisque piest utilisé comme constante, PHP vérifiera s'il existe.
    Comme ce n’est pas le cas, PHP affiche un avertissement Use of undefined constant pi - assumed 'pi'(Fondamentalement: comme la constante n’existe pas, on suppose qu’elle est une chaîne).
  • Boucle la première fois
    • Exécutez la fonction $x().
      Puisque $xa la valeur pi, il exécutera la fonction pi().
  • Stocker la valeur dans $x.
    $xa maintenant π, au lieu depi
  • Boucle pour la deuxième fois
    • Exécutez la fonction $x().
      Comme $xa π, la fonction sera exécutée 3.14159...().
    • π n'est pas une chaîne, ce qui tue le programme à ce stade avec a Fatal Error.

Merci à @Titus d' avoir trouvé la pi()fonction et m'a sauvé 1 octet!


Bien, mais je ne pense pas que ce soit valide. Il ne court pas vraiment la boucle une fois. Vous incrémentez $xjusqu'à ce abtque le corps de la boucle s'exécute. Vous pouvez résoudre ce problème en incrémentant après la boucle.
aross

J'ai pensé à une approche différente
aross

@aross Duh, vous avez raison, ce n'était pas valide. L'incrément est au mauvais endroit. Cela fonctionne comme il se doit maintenant. Vous pouvez essayer de courir for($x=abs;;++$x)echo$x,$x();pour tester. Cela devrait montrer abs0abt Fatal error[...]. Ou similaire.
Ismael Miguel

1
Vous pouvez utiliser piau lieu de abs. Cela ne donne même pas un avertissement avant de jeter le fatal.
Titus

@ Titus, j'ai complètement oublié cette fonction! Je sais que la fonction _est définie dans certains systèmes, mais n'est pas fiable. Mais merci d'avoir trouvé ça!
Ismael Miguel

10

GNU sed , 15 13 5 octets

-2 Merci à seshoumara
-8 Merci à Zeppelin

H;G;D
  1. Ajoute une nouvelle ligne et l'espace de maintien à l'espace de motif.
  2. Ajoute une nouvelle ligne et l'espace de motif à l'espace de maintien.
  3. Supprime jusqu'à la première nouvelle ligne et recommence.

Cela manque rapidement de mémoire:

$ time (echo|sed 'H;G;D')
sed: couldn't re-allocate memory

real    0m1.580s
user    0m0.545s
sys     0m1.012s

Salut, que diriez - vous s:a\?:&a:g? Il est inférieur d'un octet et double également la taille du motif par itération.
Seshoumara

@seshoumara Je ne pense pas que cela corresponde à quoi que ce soit lorsque l'espace de modèle est vide, il ne fera donc jamais le premier remplacement.
Riley

@seshoumara echo -n | sed 's:a\?:&a:g'et n'a aucune sortie. Ce serait la même chose que sed 's::a:'ce qui ne correspondrait à rien.
Riley

Avec echo -nabsolument rien ne passe à sed, mais sed ne peut pas démarrer sans contribution de par sa conception. Vérifiez ce lien méta pour voir que echo|sedc’est le moyen accepté de commencer sed pour les défis invoquant une règle de non entrée.
Seshoumara

@seshoumara Je pensais que ça donnerait quand même une ficelle vide. Cela semble fonctionner alors. Merci!
Riley

9

R, 22 25 22 20 18 octets

Edit: Merci à @Mego pour avoir signalé que R ne prend pas en charge l'optimisation des appels en queue.

Edit4: Nous avons trouvé une solution encore plus courte, simple mais complexe.

repeat(ls(T<-T-1))

La réponse utilise la variable de vérité booléenne intégrée, Tqui est décrémentée indéfiniment dans la boucle qui se répète. La fonction ls()s'appelle chaque itération qui répertorie tous les objets de l'environnement actuel. Cependant, le premier argument namespécifie de quel environnement depuis lequel lister les objets. Dans la documentation R, nous trouvons que:

L'argument name peut spécifier l'environnement à partir duquel les noms d'objet sont pris sous l'une des formes suivantes: sous la forme d'un entier (la position dans la searchliste); comme nom de chaîne de caractères d'un élément dans la liste de recherche; ou en tant qu'explicite environment(y compris en utilisant sys.framepour accéder aux appels de fonction actuellement actifs).

Cela signifie principalement que lors de la première itération, nous exécutons ls(-1) ce qui reviendrait character(0)(standard lorsque vous tentez d'accéder à l' everything-except-the-firstélément inexistant d'un objet de type caractère). Au cours de la deuxième itération, Test décrémenté de deux et on appelle ensuite ls(-3)ce qui retourne à son tour l'erreur:

Error in as.environment(pos) : invalid 'pos' argument

C’est parce que nous essayons de lister everything-except-the-third éléments mais l’environnement local ne contient que la variable Tà ce stade (en tant que tel, ls()il renverrait une liste de longueur 1à cette itération) et une erreur est renvoyée.


1
Cela ne sonne pas comme si la récursivité était faite avec l'optimisation des appels de queue, s'il y avait une limite de récursivité.
Mego

@Mego Après quelques recherches approfondies, j'ai découvert que R ne prend effectivement pas en charge l'optimisation des appels en aval, aussi cette réponse n'est-elle pas valide (je n'avais jamais entendu parler du concept auparavant). Passera à une réponse valide dans un instant.
Billywob

9

Befunge-93, 3 octets (éventuellement 1 ou 0)

!%!

Essayez-le en ligne!

À la première itération de la boucle, la pile est vide, ce qui équivaut à tous les zéros. L’opération !(not) convertit donc le sommet de la pile en 1 et le% opération (modulo) calcule 0 mod 1, en laissant 0. L' !opération suivante convertit ce 0 en 1 avant que le compteur de programme ne soit renvoyé et ne recommence la boucle.

À la deuxième itération, la première ! opération convertit en 0 le 1 qui se trouve maintenant en haut de la pile. L' %opération calcule ensuite 0 mod 0, ce qui produit une division par zéro erreur sur l'interpréteur de référence et termine ainsi le programme.

Il y a aussi la réponse plus ennuyeuse d'un octet, bien que je ne sache pas si cela est considéré comme valide.

"

Essayez-le en ligne!

Cette "commande démarre une chaîne. Ainsi, chaque espace du reste de la ligne est placé sur la pile jusqu'à ce que le compteur de programme soit renvoyé à la ligne et rencontre à "nouveau la fermeture de la chaîne. Il faudra ensuite répéter la procédure pour répéter le processus en démarrant une autre chaîne et en insérant 79 cases supplémentaires dans la pile. Finalement, cela manquera de mémoire (comportement de l'interpréteur de référence) ou provoquera un débordement de pile.

Maintenant, si vous voulez vraiment pousser les règles, il existe aussi techniquement une solution de zéro octet.


Si vous prenez cette décision comme signifiant que tout interprète définit la langue (comme beaucoup le font ici), alors nous pouvons supposer pour le moment que la langue Befunge est définie par cet interprète . Et l'une des "caractéristiques" de cet interpréteur est qu'il insère une valeur indéfinie dans la pile pour chaque boucle du champ de lecture lors de l'exécution d'un programme vierge. Avec suffisamment de temps, il manquera éventuellement de mémoire.

La vitesse à laquelle cela se produira dépendra de la vitesse de l'ordinateur, de la mémoire disponible et du navigateur utilisé. Sur ma machine, j’ai trouvé que Microsoft Edge fonctionnait mieux, mais même alors, c’était «seulement» avec 500 Mo au bout de deux minutes. Ce n’est qu’après environ quinze minutes (avec plusieurs giga-octets utilisés) que Edge a décidé de mettre fin au processus et d’actualiser l’onglet. Il est donc peu probable que le temps imparti soit inférieur à deux minutes, mais avec les bonnes conditions, cela ne serait pas nécessairement exclu.


8

FALSE, 8 octets

J'aime vraiment cette langue.

1[$][.]#

Ceci pousse a 1, puis [$][.]#boucle alors que $est vrai (dupliquer le haut de la pile) et ( .) le sort. Cet interprète plante après l’ 1impression du single (preuve que la boucle a été exécutée au moins une fois.) Il semble s’agir d’un bogue dans cet interpréteur. Le programme de 9 octets suivant devrait fonctionner avec tous les interprètes conformes:

1[$][..]#

Vous devriez également essayer DUP, qui est essentiellement un sur-ensemble de FALSE. C'est ce que j'avais l'habitude de faire RETURN.
Mama Fun Roll

@ MamfunRoll oh ouais, j'ai oublié que tu avais fait RETOUR! Je dois essayer celui-là. : D
Conor O'Brien

@MamaFunRoll J'aime le DUP, je viens d'écrire un interprète DUP et je joue avec.
ML

@ ConnorO'Brien: Je dirais que votre première solution devrait bloquer tout interprète. Je viens de lancer un processus de débogage avec mon propre interprète, et il est évident que le premier .vide la pile de données, tandis que dans la deuxième boucle $tente de dupliquer l'élément supérieur de la pile vide, ce qui devrait entraîner une erreur (enfin, mon interprète ). La deuxième version ne doit pas être valide car elle ne termine même pas la première boucle car elle tente déjà d’accéder prématurément à la pile vide.
ML

Pour votre deuxième exemple, voici un vidage de débogage de couleur complète de mon interpréteur DUP. c'est évident une fois que vous voyez comment fonctionnent la pile de données (ds) et la pile de retour (rs), ce dernier n'étant toutefois pas transparent dans FALSE.
ML

8

C, 21 octets

i;f(){for(;1/!i++;);}

Ici iest garanti pour commencer comme 0.

Il peut être confirmé que cela fonctionne une fois comme ceci:

i;f(){for(;1/!i++;)puts("hi");}
main(){f();}

Qui, sur ma machine, a pour résultat:

llama@llama:...code/c/ppcg104323loop$ ./a.out 
hi
zsh: floating point exception (core dumped)  ./a.out

La solution la plus courte que je puisse trouver est 22 octets :

f(i){f(i-puts(""-i));}

gccL'élimination des appels de queue est égale -O2ou supérieure uniquement , point auquel nous devons appeler une fonction comme putspour éviter que tout ne soit optimisé. Confirmation que cela fonctionne:

llama@llama:...code/c/ppcg104323loop$ cat loop.c       
main(){f();}
f(i){f(i-puts(""-i));}
llama@llama:...code/c/ppcg104323loop$ gcc -O2 -S loop.c 2>/dev/null
llama@llama:...code/c/ppcg104323loop$ grep call loop.s
    call    puts
    call    f

Ce qui suit est un programme complet, qui suppose qu'il est appelé sans arguments de ligne de commande, à 22 octets :

main(i){for(;1/i--;);}

qui équivaut à la fonction de même longueur:

f(i){for(i=1;1/i--;);}

Une fonction comme celle-ci est-elle traitée comme principale? Si c'est le cas, le premier argument est la longueur de la liste d'arguments (qui est 1, le nom utilisé pour l'appeler).
Riley

Ou bien, le registre d'arguments a toujours la valeur qui était là depuis l'appelant.
Riley

@Riley Ahh, cette dernière théorie semble être le cas, comme en témoigne le fait que le nombre augmente à mesure que les arguments de ligne de commande sont ajoutés. Merci pour la perspicacité!
Poignée de porte

Je ne savais pas comment vous l'appeliez dans mes premières suppositions, mais je devrais être le même que le premier argument de la fonction qui appelle f.
Riley

Oui, tio
Riley

6

MATLAB, 18 octets

Ceci peut être exécuté en tant que script:

for j=1:2;j(j);end

La première itération est bien, car j(1)est juste 1. La deuxième itération se bloque avec une erreur de tableau hors limites, car j(2)dépasse les dimensions de j, ce qui correspond à un tableau 1x1.

Cela peut également être exécuté en tant que script, mais cela ne fonctionne que la première fois que vous l'exécutez. Pourtant, c’est un abus assez hilarant des constantes prédéfinies de MATLAB que je pensais l’inclure. C'est aussi 18 octets.

while i/i;i={};end

Lorsqu'il est exécuté dans un espace de travail dans lequel la variable in'a pas encore été définie, cela suppose qu'il is'agit de l'unité imaginaire, donc i/i = 1. Dans la première boucle, l'affectation i={}crée un tableau de cellules vide appelé i. À la deuxième itération, la boucle se termine avec "Opérateur non défini '/' pour les arguments d'entrée de type 'cellule'."


Les deux sont géniaux! Vous le savez probablement, mais vous j(2)donneriez normalement une matrice 2-sur-2 avec0+1i
Stewie Griffin

Merci! C'est vrai dans Octave mais pas dans MATLAB, je pense
MattWH

6

Perl 6 , 13 octets

loop {5[$++]}

Indexe un littéral entier dans une boucle infinie.
S'appuie sur le fait que sur les valeurs scalaires, la syntaxe d'indexation de tableau peut être utilisée avec index 0(renvoyer la valeur elle-même), mais génère une Index out of rangeerreur pour tout autre index.


6

QBasic, 17 octets

Ce code est très étrange.

DO
i=11+a(i)
LOOP

Comment ça fonctionne

Dans QBasic, les variables sont pré-initialisées. Une variable régulière sans aucun suffixe de type, comme iici, est pré-initialisée à zéro.

Sauf si vous essayez d'indiquer dans cette variable un tableau ... Dans ce cas, il s'agit d'un tableau de 11 zéros. *

Sur la première fois à travers la boucle, donc, iest 0et aest un tableau. a(i)donne l'élément zeroth du tableau (qui est 0). Tout va bien. Nous nous sommes mis ià 11et boucle. Mais ce 11n’est pas un index valide pour le tableau a, et le programme s’arrête avec Subscript out of range.

Une version de 19 octets qui montre mieux ce qui se passe:

DO
?a(i)
i=i+1
LOOP

Cela imprimera 0onze fois avant d’être erroné.


* Conceptuellement, c'est un tableau de 10 éléments. La plupart des choses dans QBasic sont indexées sur 1, mais les tableaux ne le sont pas, probablement pour des raisons d'implémentation. Pour que les choses fonctionnent comme prévu pour les programmeurs, QBasic ajoute une entrée supplémentaire afin que vous puissiez utiliser les index 1 à 10. Cependant, l'indice 0 est toujours parfaitement accessible. Allez comprendre.


QBasic et les tableaux, où s'arrête le plaisir!
Steenbergh

Puisque l'erreur ne doit pas nécessairement être sur la deuxième boucle, ne pourriez-vous pas le faire i=1+a(i)?
Quelklef

@Quelklef Non, tu devrais le faire i=i+1+a(i). Sinon, l'index ne dépasse jamais 1, ce qui n'est pas une erreur.
DLosc

@DLosc Oh, tu as raison.
Quelklef

5

Haskell, 15 octets

f(a:b)=f b
f"a"

f"a"exécute de manière récursive la chaîne "a" en supprimant le premier caractère et finit par échouer à sa fin avec une Non-exhaustive patterns in function fexception, car elle fn'est définie que pour les chaînes non vides.


5

C #, 71 38 octets

Puisque vous avez fourni un exemple en C #, voici une autre version jouée au golf

Et merci à pinkfloydx33

void c(){checked{for(uint i=1;;i--);}}

Plus court que Parse.ToString()et même que Parse($"{c--}") j'ai vidé mentalement checkedparce que c'est un mot clé trop long. Dur c'est certainement plus court queParse(c.ToString())

Réponse originale

class p{static void Main(){for(int c=0;;c--)uint.Parse(c.ToString());}}

Cela commencera c=0puis décrémentera, quand c=-1le uint.Parseprovoquera un:

Unhandled Exception: System.OverflowException: Value was either too large or too small for a UInt32.

Version non-golfée et vérification de l'exécution de la boucle au moins une fois

class p {
    static void Main() {
        for(int c=0;;c--) {
            System.Console.Write(c);
            uint.Parse(c.ToString());
        }
    }
}

for(int c=0;;)uint.Parse($"{c--}");
pinkfloydx33

1
checked{for(uint c=1;;)c--;}
pinkfloydx33

Ok, wow! Je ne connaissais pas le raccourci '$'!
MrPaulch

4

CJam , 4 octets

1{}g

Essayez-le en ligne!

La première itération de la {}gboucle vide fait apparaître le 1, ce qui lui dit de continuer. La deuxième itération tente de créer une autre condition, mais la pile est vide et le programme se bloque.


4

Assemblage x86 (syntaxe AT & T), 40 octets

f:
mov $1,%eax
A:
div %eax
dec %eax
je A

Déclare une fonction f qui divise 1 par 1 à sa première itération, puis tente de diviser 0 par 0 et les erreurs.


Vous pouvez économiser 4 octets en passant à la syntaxe Intel :)
mriklojn

6
Nous notons généralement assemblage par la taille du code d'octet généré, et non par les instructions lisibles par l'homme.
Dennis

@Dennis assmebled assembly est un langage de machine. mais oui, cela pourrait être réclamé beaucoup plus court sous forme de langage machine.
Jasen

Débarrassez-vous de l'étiquette f et du mov. Échangez le dec et le div et vous pourrez vous en débarrasser encore plus.
Clearer

4

CJam, 4 octets

P`:~

P`génère la chaîne 3.141592653589793. :~évalue chaque personnage. 3est un code valide dans CJam qui renvoie simplement 3. À l'itération suivante, .provoque une erreur car il nécessite un chiffre ou un opérateur pour le suivre.


4

Ruby, 14 octets

loop{$./=~$.}

Sorties dues à ZeroDivisionError: divided by 0

$. The current input line number of the last file that was read

Ruby Docs



4

Lot, 22 à 20 octets

:a
set i=%i%1
goto a

Explication

Ceci est une boucle infinie qui ajoute un 1sur une chaîne initialement vide. Finalement, cela passera la longueur de chaîne maximale de 8192 et plantera. Sur ma machine, cela prend environ 30 secondes.


Agréable! Vous pouvez économiser 2 octets en utilisant des fins de ligne Unix.
briantiste

Vous pouvez utiliser% 0 qui est le nom du fichier à la place de l'étiquette et allez à.
YourDeathIsComing

Je ne savais pas si cela enfreignait la règle de la récursion de la queue.
SomethingDark

4

JavaScript, 9 octets

for(;;i);

Cela fonctionne une fois, puis lance ReferenceError: i is not definedce qui arrête la boucle.

// With a console.log(1) to see that it runs once.
for(;;i)console.log(1);


À titre d'exemple, prenons la <increment>fin du premier cycle ou le début du deuxième cycle?

0:for(<init>;<test>;<increment>)
1:{
2:  <statement>;
3:}

1 / je le vois

Après être passé des lignes 0 à la ligne 3 puis revenir à la ligne 0, on a l'impression qu'un cycle complet est terminé.
Cela ferait <increment>le début du deuxième cycle.
- Premier cycle: <init>-><test> -> <statement>
- Deuxième cycle: <increment>-> <test>-><statement>

2 / While équivalent

0:<init>;
1:while(<test>)
2:{
3:  <statement>;
4:  <increment>;
5:}

Dans cet équivalent whilel' <increment>est la fin du premier cycle et il se sent comme il est la même chose avec le for.
Cela ferait <increment>la fin du premier cycle.
- Premier cycle: <test>-> <statement>-> <increment>
- Deuxième cycle: <test>-> <statement>-><increment>

3 / Une déclaration est rencontrée deux fois

Un cycle complet est terminé lorsqu'une instruction est rencontrée deux fois.
La première déclaration rencontrée deux fois est <test>.
Cela ferait <increment>la fin du premier cycle.
- Premier cycle: <test>-> <statement>-><increment>
- Deuxième cycle: <test>-> <statement>-><increment>

4 / C'est une configuration

Il ne <init>s’agit que de mettre en place tout ce qui est nécessaire pour le premier cycle.
Il ne <increment>s’agit que de mettre en place tout ce qui est nécessaire pour le deuxième cycle.
Cela ferait <increment>le début du deuxième cycle.
- Premier cycle: <init as a setup>-> <test>-> <statement>
- Deuxième cycle: <increment as a setup>-> <test>-><statement>


La spécification de langue ECMAScript® 2016

Durée de for(<init>;<test>;<increment>)<statement>;

Soit varDcl le résultat de l’évaluation <init>.
ReturnIfAbrupt (varDcl).
Revenir ? ForBodyEvaluation ( <test>,<increment> , <statement>, «», labelSet).

Il y a trois formes, alors j'ai pris la plus courte ici, il n'y a pas de différence:
- Quoi que ce soit, <init>cela ne fait pas partie de la première itération.
- Ce qui est pertinent est dans ForBodyEvaluation.

Détails de ForBodyEvaluation ( <test>, <increment>, <statement>, «», labelSet)

0 Soit V non défini.
1 effectuer? CreatePerIterationEnvironment (perIterationBindings).
2 Répétez
3 Si n'est pas [vide], alors
4 Laissez testRef le résultat de l'évaluation <test>.
5 Que testValue soit? GetValue (testRef).
6 Si ToBoolean (testValue) est défini sur false, retournez NormalCompletion (V).
7 Soit le résultat le résultat de l'évaluation <statement>.
8 Si LoopContinues (result, labelSet) est défini sur false, retournez Completion (UpdateEmpty (result, V)).
9 Si le résultat. [[Valeur]] n'est pas vide, laissez V le résultat. [[Valeur]].
10 effectuer? CreatePerIterationEnvironment (perIterationBindings). 13 effectuer? GetValue (incRef).
11 Si n'est pas [vide], alors
12 Soit incRef le résultat de l'évaluation <increment>.

6 / je le vois

Un cycle complet une exécution complète de la partie répétée.
Cela ferait <increment>la fin du premier cycle.
- Premier cycle: <test>-> <statement>-> <increment>/ En d'autres termes, de la ligne 3 à la ligne 13
- Deuxième cycle: <test>-> <statement>-> <increment>/ En d'autres termes, de la ligne 3 à la ligne 13

7 / Un cycle est une itération

Un cycle commence par CreatePerIterationEnvironment.
Alors, quand CreatePerIterationEnvironmentest rencontré un nouveau cycle commence, terminant ainsi le précédent.
Cela ferait <increment>le début du deuxième cycle.
- Premier cycle: <test>-> <statement>/ En d'autres termes, de la ligne 1 à la ligne 9
- Deuxième cycle: <increment>-> <test>-> <statement>/ En d'autres termes, de la ligne 10 en boucle jusqu'à la ligne 9


Est le <increment> la fin du premier cycle ou le début du deuxième cycle?

La bonne explication est 6 ou 7.


8
Je pense que je suis plus enclin à attribuer l'accroissement à la fin de la première itération, plutôt qu'au début de la deuxième itération ou à aucune des deux itérations. Je suppose que ceci est une ambiguïté de la question.

1
Puisque for(a;b;c)d;est à peu près équivalent à a;while(b){d;c;}, je suis enclin à dire que l'erreur est toujours générée lors de la première itération (avant que la condition de boucle ne soit vérifiée une seconde fois).
ETHproductions

@Hurkyl La première itération commence par l'initialisation, donc je pense que l'incrément devrait être le début de la seconde itération.
Hedi

4
Si vous lisez la spécification , vous pouvez voir que l'opération d'incrémentation est la dernière partie de l'itération et, en tant que telle, appartient toujours à la première itération.
Nit

3
@ Hedi, je ne vois pas en quoi cela est pertinent. L'opération d'incrémentation fait très clairement partie de la première séquence de la boucle. Pour reformuler, lorsque l'opération d'incrémentation est appelée, la boucle n'a pas terminé une seule exécution complète.
Nit

4

INTERCAL , 12 octets

(1)DO(1)NEXT

Essayez-le en ligne!

NEXTest la commande principale du flux de contrôle d'INTERCAL-72. (Révisions ultérieures introduitesCOME FROM , qui sont devenues plus célèbres, mais ce n'était pas dans la version originale du langage; et toutes les mises en œuvre INTERCAL terminées, je suis conscient du supportNEXT de la compatibilité avec les , avec toutes sauf une activant le support par défaut. Je ne ressens pas le besoin de nommer INTERCAL-72 spécifiquement dans le titre.)

Lorsque vous utilisez NEXTpour former une boucle, vous êtes censé utiliser RESUMEou FORGETpour libérer l’espace qu’elle utilise pour se souvenir de l’emplacement du programme; RESUMErend rétroactivement NEXTquelque chose qui ressemble à un appel de fonction (bien que vous puissiez revenir de fonctions autres que celle dans laquelle vous vous trouvez) alors FORGETqu’il en fait quelque chose de plus semblable à une instruction GOTO. Si vous ne le faites pas non plus (et ce programme ne le fait pas), le programme se bloquera après 80 itérations (ce comportement est en fait spécifié dans la spécification INTERCAL).

Il est quelque peu ambigu de savoir si cela compte comme une récursion sans limite (non autorisée dans la question); vous pouvez certainement utiliser ce genre deNEXT application pour implémenter un appel de fonction, auquel cas ce serait effectivement une fonction récursive, mais il n'y a pas assez d'informations ici pour déterminer si nous effectuons un appel de fonction ou non. Au moins, je publie cela quand même car cela ne viole pas les règles de manière non équivoque, et une implémentation INTERCAL qui optimisait "l'appel final" violerait non seulement la spécification, mais ferait également échouer la plupart des programmes existants, car le retour de la "mauvaise fonction" est le moyen principal d'effectuer l'équivalent d'une instruction IF.

Voici le message d'erreur résultant, tel que généré par C-INTERCAL:

ICL123I PROGRAM HAS DISAPPEARED INTO THE BLACK LAGOON
    ON THE WAY TO 1
        CORRECT SOURCE AND RESUBNIT

(Notez que la deuxième ligne est indentée avec un onglet et la troisième avec huit espaces. Cela semble correct dans un terminal ou dans pratiquement tout programme comportant des tabulations multiples de 8. Toutefois, Markdown a des tabulations multiples de Quatrièmement, enfreignant les suppositions que la plupart des programmes plus anciens font à propos des onglets, le message d'erreur est un peu mal formaté ici.)


Est-ce que l'erreur dit vraiment CORRECT SOURCE AND RESUBNIT? Comme dans une faute de frappe dans le message d'erreur C-INTERCAL d'origine?
Andrakis

1
@Andrakis: Oui, c'est le cas. Cette faute de frappe a été soigneusement préservée pendant des années.

3

Pyth, 3 octets

W1w

Essayez-le en ligne.

W1est juste while 1:en Python. Le corps de la boucle imprime une ligne lue à partir de STDIN, qui se bloque pour la deuxième itération lorsque le code est exécuté avec une entrée vide.

Si les boucles utilisant #(boucle-jusqu'à-erreur) sont interdites (je suppose donc), je pense que c'est la plus courte possible.


3

Python 3, 29 octets

i=1
def x(n):del i;x(i)
x(i)

Vraiment simple. Lors du deuxième appel à x, i n'est pas là et Python s'en plaint.


3

Labyrinthe , 3 octets

#(/

Essayez-le en ligne!

Comme la plupart des langages 2D, Labyrinth n'a pas de construction en boucle explicite. Au lieu de cela, tout code conçu de telle sorte qu'il est exécuté plusieurs fois de suite est une boucle dans ces langages. Dans le cas de Labyrinth, un programme linéaire simple agit comme une boucle, car le pointeur d'instruction va rebondir sur celui-ci. Si le programme est abc(pour certaines commandes a, betc ), alors l'exécution réelle sera abcbabcbabcb...telle qu'il s'exécuteabcb dans une boucle infinie.

En ce qui concerne la raison pour laquelle ce programme se bloque à la deuxième itération de cette boucle, voici ce que font les commandes individuelles. Notez que la pile de Labyrinth contient une quantité implicite infinie de zéros au bas:

#   Push stack depth.   [... 0]
(   Decrement.          [... -1]
/   Divide.             [... 0]
(   Decrement.          [... -1]
#   Push stack depth.   [... -1 1]
(   Decrement.          [... -1 0]
/   Divide.             Crashes with division-by-zero error.

3

Bash, 11 (non concurrent)

exec $0 1$@

Ce script s'exécute de manière récursive, en ajoutant 1aux arguments transmis à chaque itération. Je pense que cela compte comme un coût total de possession car l’Exec réutilise l’espace de traitement mais ne mange pas la pile. C'est à la limite de la concurrence car il a fallu environ 10 minutes avant d'être tué sur ma machine - YMMV.


1
exec $0 1$@$@ se termine beaucoup plus rapidement mais est deux caractères plus long.
Jasen

3

cmd, 34 octets

for /l %i in (0,1,10) do color %i0

Cela passera %ide 0 à 10. La colorcommande (ancienne) acceptera avec plaisir tout argument comportant 2 chiffres hexadécimaux. Avec l'argument, 100il échouera, en imprimant le message d'aide et en réglant ERRORLEVELsur 1.

Preuve de la boucle exécutée au moins une fois: la couleur de votre shell sera différente!

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.