Ciclo autodistruttivo più breve


61

Il vostro compito è quello di scrivere un programma completo o una funzione che non prende in ingresso ed esegue qualsiasi tipo di ciclo ( while, for, foreach, do, do-while, do-loop, goto, ricorsione, ecc) che finirà nel causare un errore che indica che il programma deve fermarsi esecuzione e Uscita.

Regole:

  1. L'errore deve essere un errore di runtime, un'eccezione non gestita o qualsiasi cosa che faccia finire il programma stesso.
  2. L'errore deve produrre l'arresto e uscire dal programma senza chiamare esplicitamente exit;(o equivalente) ad un certo punto.
  3. I messaggi come Warning:, Notice:ecc., Che non causano la fine del programma non sono validi. Ad esempio, nelle divisioni PHP per zero produce un Warningmessaggio ma il programma non si fermerà e continuerà a funzionare, questa non è una risposta valida.
  4. Il loop deve eseguire almeno un ciclo completo. In altre parole, l'errore può verificarsi a partire dal secondo ciclo e oltre. Questo per evitare di causare l'errore utilizzando una sintassi del codice errata: il codice deve essere sintatticamente corretto.
  5. Il ciclo può essere persino infinito (esempio for(;;);) se rispetta le regole sopra menzionate, ma non può richiedere più di 2 minuti per terminare se stesso in un errore di runtime.
  6. La ricorsione senza ottimizzazione della chiamata di coda non è valida ( 1 , 2 ).
  7. Questo è quindi vince il codice più corto.
  8. Sono vietate le scappatoie standard .

Esempio C # ( test online ):

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

Classifica:

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>

Grazie a Martin Ender per il frammento della classifica


Giusto per essere chiari, la ricorsione senza TCO può essere utilizzata purché l'errore non abbia a che fare con troppa ricorsione, giusto? (Ad esempio, una funzione ricorsiva che errori nella seconda ricorsione)
ETHproductions

@ETHproductions È stato suggerito da Dennis in chat: "Potrebbe essere difficile decidere se un ciclo completo è stato completato in questo caso [di ricorsione]. La ricorsione della coda è adatta al conto, ma solo il TCO in realtà completa un ciclo se l'esecuzione viene interrotta per un errore. [...] Direi che la ricorsione senza TCO non è valida. "
Mario,

In for(a;b;c)d;, dopo quale affermazione termina il primo ciclo? È valido interrompere la prima valutazione della cdichiarazione?
Hedi,

1
@Hedi Ecco la mia modesta opinione (non l'OP): tutte le voci devono completare un ciclo completo, nel senso che devono entrare in un secondo ciclo; questo significa che almeno un'istruzione viene eseguita una seconda volta. Poiché l'ordine di esecuzione nel tuo esempio è a, b, d, c, b, d, c, ..., bè l'inizio del ciclo e deve essere eseguito almeno una seconda volta.
ETHproductions

2
Non voglio iniziare alcun problema, ma poiché il programma (di funzione per quella materia) non dovrebbe assumere alcun input, tutte le soluzioni ricorsive che hanno un parametro non sono valide perché è stato inserito un parametro.
BrainStone,

Risposte:


33

MATL , 5 1 byte

Idea presa dalla risposta CJam di @ MartinEnder

`

Provalo online!

`    % 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

Vecchia versione

2:t"x

Provalo online!

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
Funziona anche offline. Nessun input significa che puoi assumere input vuoti.
Dennis,

@Dennis Hm il programma offline continuerà ad attendere l'input dell'utente. L'input è interattivo, cioè richiesto secondo necessità nella versione offline. Quindi il programma attenderà indefinitamente. Non sei sicuro che conta?
Luis Mendo,

Non sono esattamente sicuro di come funzioni MATL internamente, ma se lo esegui in un ambiente incapace di richiedere input (come il backend di TIO), non sarà in grado di ottenere alcun input. Inoltre, premendo Ctrl-D o l'equivalente dipendente dal sistema operativo dovrebbe essere consentito inviare un input vuoto.
Dennis,

35

Python, 16 byte

L'approccio non interessante della divisione 0:

for x in 1,0:x/x

Viene calcolata la prima iterazione 1 / 1, che funziona bene. La seconda iterazione tenta di calcolare 0 / 0, generando un ZeroDivisionErrorlancio.

17 byte (preferito personale)

i=1
while i:del i

Inizialmente, il i=1che è vero, quindi il ciclo è inserito.

La prima volta che viene eseguito il ciclo, la variabile iviene eliminata.

Ciò significa che, la seconda volta, inon è più una variabile e quindi la sua valutazione fallisceNameError: name 'i' is not defined.


Un'altra soluzione da 15 byte sarebbe def _():_()(newline) _(), perché Python non ottimizza la ricorsione della coda. Tuttavia, ciò viola la regola n. 6.


La soluzione di 17 byte funziona anche se si sostituisce while icon while 1perché cerca di eliminare idi nuovo;
user6245072

2
@utente6245072 sì, entrambi gli snippet possono essere banalmente modificati per molte soluzioni funzionanti
FlipTack

È possibile utilizzare il deltrucco con un built-in di radersi un paio di più: while 1:del id.
DSM,


18

Gelatina , 3 2 byte

Ṿß

Si uccide esaurendo la memoria. Lo fa localmente dopo ~ 100 secondi.

Provalo online! (certificato di morte nel cassetto di debug )

Come funziona

Ṿß  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.

Le prime poche iterazioni producono:

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

Dopodiché, diventa davvero brutto, molto velocemente.


Quali sono i limiti di memoria di Jelly?
tuskiomi,

Jelly non ha un limite di memoria esplicito, quindi qualunque cosa Python possa affrontare. Tuttavia, l'utilizzo della memoria raddoppia con ogni iterazione, quindi questo dovrebbe esaurire piuttosto rapidamente tutta la memoria disponibile.
Dennis,

28
Quindi, ogni 2 anni, saremo in grado di eseguire un'altra iterazione
tuskiomi il

Quindi fallirà la condizione # 5 su macchine lente con molta RAM?
Fisico pazzo il

@MadPhysicist È corretto. Questo è un problema intrinseco con limiti di tempo. La conformità dipende molto dalla macchina su cui viene eseguito il programma.
Dennis,

13

V , 2 byte

òl

Provalo online!

Questa è la sfida perfetta per V perché lo faccio già tutto il tempo! In effetti, V non ha nemmeno alcun condizionale, ha solo funzioni che si rompono in caso di errore. In questo caso, i òmezzi "ripeti per sempre" e i lmezzi "muoviti a destra".

In un buffer vuoto (nessun input) questo si interromperà al primo passaggio e non produrrà alcun output. Se non v'è entrata, si romperà una volta ci spostiamo inviare l'ultimo carattere di input e di output tutto l'input (rendendo questo anche un programma di gatto)


3
Aspetta, lsignifica "sposta a destra"? Non "muovi a lpoppa"?
Conor O'Brien,

1
@ ConorO'Brien sì. In realtà ci sono alcune buone ragioni storiche per questo.
DJMcMayhem

3
La sfida richiede risposte in caso di arresto anomalo sulla seconda iterazione o successiva, non sulla prima iterazione.
Martin Ender,

11

JavaScript (ES6), 13 byte

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

Questa è una funzione ricorsiva che funziona bene una volta, poi si lancia ReferenceError: a is not definede si chiude.

Ecco una versione non ES6 a 15 byte:

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

Funziona bene una volta, poi si lancia TypeError: i is undefinede si chiude.


10

Bash 4.2, 22 byte

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

Non funziona in TIO perché ha Bash 4.3 e il bug su cui faccio affidamento è stato finalmente risolto.

Verifica

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

Questo si arresta in modo anomalo quando il programma tenta di calcolare 2 63 mod -1 , che si arresta in modo anomalo in Bash 4.2 e versioni precedenti a causa di un bug noto.


10

PHP, 22 21 20 18 byte

Questo si basa su PHP che consente di assegnare un nome di funzione a una variabile e provare a eseguirlo.

Questo semplicemente concatena il nome della pifunzione due volte. Questo uccide PHP con a Fatal Error: Uncaught Error: Call to undefined function pipi() in [...][...].

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

Funziona in modo simile alla mia vecchia risposta.


Vecchia risposta, 20 byte

PHP ti consente di incrementare i caratteri, usando l'operatore di incremento. Funziona solo sulla a-zgamma, ma è abbastanza.

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

Credo che questo soddisfi tutti i punti richiesti e che il ciclo funzioni una volta.

Puoi vedere se perché otterrai l'errore Fatal error: Function name must be a string.


Come funziona, passo dopo passo:

  • Assegna pia $x.
    Poiché piviene utilizzato come costante, PHP verificherà se esiste.
    Dato che non lo è, PHP mostra un avvertimento che dice Use of undefined constant pi - assumed 'pi'(Fondamentalmente: poiché la costante non esiste, si presume che sia una stringa)
  • Ripeti la prima volta
    • Esegui la funzione $x().
      Poiché $xha il valore pi, eseguirà la funzione pi().
  • Memorizza il valore in $x.
    $xora ha π, invece dipi
  • Ripeti per la seconda volta
    • Esegui la funzione $x().
      Poiché $xha π, eseguirà la funzione 3.14159...().
    • π non è una stringa, uccidendo il programma a questo punto con a Fatal Error.

Grazie a @Titus per aver trovato la pi()funzione, salvandomi 1 byte!


Bello, ma non credo sia valido. In realtà non esegue il ciclo una volta. Si incrementa $xper abtprima che il corpo del ciclo viene eseguito. Potresti risolverlo incrementando dopo il ciclo.
circa il

Ho pensato a un approccio diverso
aross

@aross Duh, hai ragione, non era valido. L'incremento è nel posto sbagliato. Funziona come dovrebbe ora. Puoi provare a correre for($x=abs;;++$x)echo$x,$x();per testare. Dovrebbe mostrare abs0abt Fatal error[...]. O simili.
Ismael Miguel,

1
È possibile utilizzare piinvece di abs. Questo non dà nemmeno un avvertimento prima che getta il fatale.
Tito

@Titus Mi sono completamente dimenticato di quella funzione! So che la funzione _è definita in alcuni sistemi, ma non è affidabile. Ma grazie per averlo trovato!
Ismael Miguel,

10

GNU sed , 15 13 5 byte

-2 Grazie a seshoumara
-8 Grazie a zeppelin

H;G;D
  1. Aggiunge una nuova riga e lo spazio di attesa allo spazio del motivo.
  2. Aggiunge una nuova riga e lo spazio del motivo allo spazio di attesa.
  3. Elimina fino alla prima riga nuova e ricomincia.

Questo esaurisce rapidamente la memoria:

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

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

Ciao, che ne dici s:a\?:&a:g? È 1 byte in meno e raddoppia anche la dimensione del pattern per iterazione.
seshoumara,

@seshoumara Non credo che corrisponderà a nulla quando lo spazio del modello è vuoto, quindi non effettuerà mai la prima sostituzione.
Riley,

@seshoumara echo -n | sed 's:a\?:&a:g'e non ho avuto output. Sarebbe lo stesso sed 's::a:'che non corrisponderebbe a nulla.
Riley,

Con echo -nassolutamente nulla viene passato a sed, ma sed non può iniziare senza input dal design. Controlla questo meta link per vedere che echo|sedè il modo accettato per avviare sed per le sfide che invocano una regola di non input.
seshoumara,

@seshoumara Ho pensato che gli avrebbe comunque dato una stringa vuota. Sembra che funzioni allora. Grazie!
Riley,

9

R, 22 25 22 20 18 byte

Modifica: grazie a @Mego per aver sottolineato che R non supporta l'ottimizzazione delle chiamate di coda.

Edit4: ho trovato una soluzione ancora più breve, semplice ma piuttosto complessa.

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

La risposta utilizza la variabile di verità booleana incorporata, Tche viene decrementata indefinitamente nel ciclo ripetuto. La funzione ls()si chiama ogni iterazione che elenca tutti gli oggetti nell'ambiente corrente. Tuttavia, il primo argomento namespecifica da quale ambiente da cui elencare gli oggetti. Dalla documentazione R troviamo che:

L'argomento name può specificare l'ambiente da cui i nomi degli oggetti sono presi in una delle varie forme: come un numero intero (la posizione searchnell'elenco); come nome della stringa di caratteri di un elemento nell'elenco di ricerca; o come esplicito environment(incluso l'utilizzo sys.frameper accedere alle chiamate di funzione attualmente attive).

Ciò significa principalmente che nella prima iterazione eseguiremo la ls(-1)restituzione character(0)(standard quando si tenta di accedere everything-except-the-firstall'elemento inesistente di qualsiasi oggetto di tipo carattere). Durante la seconda iterazione, Tviene diminuito di due e successivamente chiamiamo ls(-3)che a sua volta restituisce l'errore:

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

Questo perché proviamo a elencare l' everything-except-the-thirdelemento ma l'ambiente locale contiene solo la variabile Ta questo punto (come tale, ls()restituirebbe un elenco di lunghezza 1in questa iterazione) e viene restituito un errore.


1
Non sembra che la ricorsione venga eseguita con l'ottimizzazione della chiamata di coda, se esiste un limite di ricorsione.
Mego

@Mego Dopo aver scavato un po 'ho scoperto che R in effetti non supporta l'ottimizzazione delle chiamate di coda, quindi questa risposta non è valida (non avevo mai sentito parlare del concetto prima). Passerà a una risposta valida in un momento.
Billywob,

9

Befunge-93, 3 byte (possibilmente 1 o 0)

!%!

Provalo online!

Alla prima iterazione del ciclo, lo stack è vuoto, che è l'equivalente di tutti gli zeri. L' !operazione (non) converte quindi lo stack top in 1 e l' %operazione (modulo) calcola 0 mod 1, lasciando 0. L' !operazione successiva converte tale 0 in 1 prima che il contatore del programma si avvolga e ricomincia il ciclo.

Nella seconda iterazione, le prime !operazioni converte 1 che è ora in cima allo stack in 0. L' %operazione quindi calcola 0 mod 0, che produce una divisione per errore zero sull'interprete di riferimento e quindi termina il programma.

C'è anche la risposta più noiosa da 1 byte, anche se non sono sicuro che questo sia considerato valido.

"

Provalo online!

Questo "comando avvia una stringa, quindi ogni spazio sul resto della riga viene inserito nello stack fino a quando il contatore del programma non si avvolge e incontra "nuovamente la chiusura della stringa. Dovrà quindi avvolgere una seconda volta per ripetere il processo avviando un'altra stringa e spingendo altri 79 spazi sulla pila. Alla fine questo esaurirà la memoria (il comportamento dell'interprete di riferimento) o produrrà un overflow dello stack.

Ora se vuoi davvero spingere le regole c'è anche tecnicamente una soluzione a zero byte.


Se prendi questa regola per indicare che qualsiasi interprete definisce la lingua (come molti qui fanno), allora possiamo supporre per il momento che la lingua di Befunge sia definita da questo interprete . E una delle "caratteristiche" di quell'interprete è che spinge un valore indefinito nello stack per ogni loop del campo di gioco quando esegue un programma vuoto. Dato abbastanza tempo, alla fine rimarrà senza memoria.

La velocità con cui ciò accade dipenderà dalla velocità del computer, dalla memoria disponibile e dal browser in uso. Sulla mia macchina ho scoperto che Microsoft Edge funzionava meglio, ma anche allora "solo" utilizzava 500 MB dopo due minuti. Fu solo intorno ai quindici minuti (con diversi gigabyte usati) che Edge decise di interrompere il processo e aggiornare la scheda. Quindi è improbabile che ci riesca entro il limite di due minuti, ma con le giuste condizioni che non sarebbero necessariamente fuori discussione.


8

FALSO, 8 byte

Mi piace molto questa lingua.

1[$][.]#

Questo spinge a 1, quindi [$][.]#esegue il ciclo mentre $è vero (duplicato all'inizio dello stack) e ( .) lo emette. Questo interprete si arresta in modo anomalo dopo che il singolo 1è stato stampato (prova del ciclo in esecuzione almeno una volta.) Sembra essere un bug in questo interprete. Il seguente programma a 9 byte dovrebbe funzionare in tutti gli interpreti conformi:

1[$][..]#

Dovresti anche provare DUP, che è fondamentalmente un superset di FALSE. Questo è quello che ero solito fare RITORNO.
Mama Fun Roll

@MamaFunRoll oh yeah, ho dimenticato che hai fatto RITORNO! Devo provare quello. : D
Conor O'Brien,

@MamaFunRoll Adoro DUP, ho appena scritto un interprete DUP e ci sto giocando.
ML

@ ConnorO'Brien: direi che la tua prima soluzione dovrebbe mandare in crash qualsiasi interprete. Ho appena eseguito un debug con il mio interprete, ed è ovvio che il primo .svuota lo stack di dati, mentre nel secondo ciclo $tenta di duplicare l'elemento superiore dello stack vuoto, il che dovrebbe portare a un errore (beh, il mio interprete fa ). La seconda versione non dovrebbe essere valida perché non termina nemmeno il primo ciclo perché tenta già di accedere prematuramente allo stack vuoto.
ML

Per il tuo secondo esempio, ecco un Dump di debug a colori completo del mio interprete DUP. è ovvio quando vedi come funzionano lo stack di dati (ds) e lo stack di ritorno (rs), quest'ultimo però non è trasparente in FALSE.
ML

8

C, 21 byte

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

Qui iè garantito per iniziare come 0.

Si può confermare che questo funziona una volta così:

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

Che, sulla mia macchina, si traduce in:

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

La soluzione ricorsiva più breve che riesco a trovare è di 22 byte :

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

gccelimina solo la coda di chiamata in poi -O2o superiore, a quel punto dobbiamo chiamare una funzione come putsper impedire che l'intera cosa venga ottimizzata. Conferma che funziona:

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

Di seguito è riportato un programma completo, che presuppone che venga chiamato senza argomenti della riga di comando, a 22 byte :

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

che equivale alla funzione della stessa lunghezza:

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

Una funzione come questa è trattata come principale? In tal caso, il primo argomento è la lunghezza dell'elenco degli argomenti (ovvero 1, il nome utilizzato per chiamarlo).
Riley,

In alternativa, il registro degli argomenti ha ancora il valore presente nella chiamata principale.
Riley,

@Riley Ahh, quest'ultima teoria sembra essere il caso, come evidenziato dal fatto che il numero aumenta con l'aggiunta di argomenti da riga di comando. Grazie per la comprensione!
Maniglia della porta

Non ero sicuro di come lo stavi chiamando nella mia prima ipotesi, ma dovrei essere lo stesso del primo argomento della funzione che chiama f.
Riley,

Sì, tio
Riley il

6

MATLAB, 18 byte

Questo può essere eseguito come uno script:

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

La prima iterazione va bene, poiché j(1)è giusta 1. La seconda iterazione si arresta in modo anomalo con un array fuori limite, poiché j(2)supera le dimensioni di j, ovvero un array 1x1.

Anche questo può essere eseguito come script, ma funziona solo la prima volta che lo esegui. Tuttavia, è un abuso abbastanza esilarante delle costanti predefinite di MATLAB che ho pensato di includerlo. Sono anche 18 byte.

while i/i;i={};end

Quando viene eseguito in un'area di lavoro in cui la variabile inon è ancora stata definita, si presume che isia l'unità immaginaria, quindi i/i = 1. Nel primo ciclo, l'assegnazione i={}crea un array di celle vuoto chiamato i. Nella seconda iterazione, il ciclo termina con "Operatore non definito '/' per argomenti di input di tipo 'cella'."


Entrambi sono fantastici! Probabilmente lo sai, ma j(2)normalmente darebbe una matrice 2 per 2 con0+1i
Stewie Griffin

Grazie! Questo è vero in Octave ma non in MATLAB, credo
MattWH,

6

Perl 6 , 13 byte

loop {5[$++]}

Indica un valore intero letterale in un ciclo infinito.
Si basa sul fatto che su valori scalari, la sintassi di indicizzazione dell'array può essere utilizzata con l'indice 0(restituendo il valore stesso), ma genera un Index out of rangeerrore per qualsiasi altro indice.


6

QBasic, 17 byte

Questo codice è molto strano.

DO
i=11+a(i)
LOOP

Come funziona

In QBasic, le variabili sono preinizializzate. Una variabile regolare senza alcun suffisso di tipo, come iqui, è preinizializzata a zero.

Tranne se provi a iscriverti a quella variabile come un array ... nel qual caso, è un array di 11 zeri. *

Alla prima volta attraverso il ciclo, quindi, iè 0ed aè un array. a(i)fornisce l'elemento zeroth dell'array (che è 0). Tutto bene. Abbiamo impostato iper 11e loop. Ma ora 11non è un indice valido per l'array ae il programma si arresta Subscript out of range.

Una versione a 19 byte che mostra meglio cosa sta succedendo:

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

Questo verrà stampato 0undici volte prima di errori.


* Concettualmente, è un array di 10 elementi. La maggior parte delle cose in QBasic sono indicizzate 1, ma gli array non lo sono, probabilmente per motivi di implementazione. Per far funzionare le cose come previsto per i programmatori, QBasic inserisce una voce aggiuntiva in modo da poter utilizzare gli indici da 1 a 10. L'indice 0, tuttavia, è ancora perfettamente accessibile. Vai a capire.


QBasic e array, dove finisce il divertimento!
Steenbergh,

Dal momento che l'errore non deve essere sul secondo ciclo, non potresti farlo i=1+a(i)?
Quelklef,

@Quelklef No, dovresti farlo i=i+1+a(i). Altrimenti l'indice non supera mai 1, il che non è un errore.
DLosc

@DLosc Oh, hai ragione.
Quelklef,

5

Haskell, 15 byte

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

f"a"scorre in modo ricorsivo attraverso la stringa "a" rilasciando il primo carattere e alla fine fallisce con Non-exhaustive patterns in function fun'eccezione, perché fè definito solo per stringhe non vuote.


5

C #, 71 38 byte

Dato che hai fornito un esempio in C # qui un'altra versione ha giocato a golf

E grazie a pinkfloydx33

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

Più corto di Parse.ToString()e persino di quello che Parse($"{c--}") ho scaricato mentalmente checkedperché troppo lungo di una parola chiave. Difficilmente è più breve diParse(c.ToString())

Risposta originale

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

Ciò avvierà c=0poi farlo diminuire, quando c=-1il uint.Parsecauserà un:

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

Versione non golfata e verifica che il ciclo venga eseguito almeno una volta

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! Non sapevo della scorciatoia '$'!
Mr Paul Paul,

4

CJam , 4 byte

1{}g

Provalo online!

La prima iterazione del {}gciclo vuoto fa apparire il 1, che gli dice di continuare. La seconda iterazione tenta di visualizzare un altro condizionale, ma lo stack è vuoto, quindi il programma si arresta in modo anomalo.


4

assembly x86 (sintassi AT&T), 40 byte

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

Dichiara una funzione f che divide 1 per 1 alla prima iterazione, quindi tenta di dividere 0 per 0 ed errori.


Puoi salvare 4 byte passando alla sintassi Intel :)
mriklojn il

6
Generalmente calcoliamo l'assemblaggio in base alla dimensione del codice byte generato, non alle istruzioni leggibili dall'uomo.
Dennis,

L'assemblea assemblata @Dennis è un linguaggio automatico. ma sì, questo potrebbe essere rivendicato molto più breve in termini di linguaggio macchina.
Jasen,

Sbarazzarsi dell'etichetta f e del mov. Scambia dec e div e puoi sbarazzartene ancora di più.
Più chiaro il

4

CJam, 4 byte

P`:~

P`genera la stringa 3.141592653589793. :~valuta ogni personaggio. 3è un codice valido in CJam che restituisce semplicemente 3. Nella successiva iterazione, .causa un errore perché richiede una cifra o un operatore che lo segue.


4

Rubino, 14 byte

loop{$./=~$.}

Uscite a causa di ZeroDivisionError: divided by 0

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

Ruby Docs



4

Lotto, 22 20 byte

:a
set i=%i%1
goto a

Spiegazione

Questo è un ciclo infinito che aggiunge 1a una stringa inizialmente vuota. Alla fine questo passerà la lunghezza massima della stringa di 8192 e si arresterà in modo anomalo. Sulla mia macchina, ci vogliono circa 30 secondi.


Bello! Puoi salvare 2 byte usando i finali di linea Unix.
Briantist,

Puoi usare% 0 che è il nome file invece dell'etichetta e vai a.
YourDeathIsComing

Non ero sicuro che ciò infrangesse la regola della ricorsione della coda.
Something

4

JavaScript, 9 byte

for(;;i);

Questo viene eseguito una volta, quindi genera ReferenceError: i is not definedche interrompe il ciclo.

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


Prendendo il seguente esempio, è la <increment>fine del primo ciclo o l'inizio del secondo ciclo?

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

1 / Lo vedo

Dopo essere passato dalle righe 0 alla riga 3, quindi tornare alla riga 0, sembra che sia stato completato un ciclo completo.
Ciò renderebbe l' <increment>inizio del secondo ciclo.
- Primo ciclo: <init>-> <test>-> <statement>
- Secondo ciclo: <increment>-> <test>-><statement>

2 / Whileequivalente

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

In questo equivalente whilealla <increment>è la fine del primo ciclo e ci si sente come se fosse la stessa cosa con il for.
Ciò renderebbe la <increment>fine del primo ciclo.
- Primo ciclo: <test>-> <statement>-> <increment>
- Secondo ciclo: <test>-> <statement>-><increment>

3 / Un'istruzione viene rilevata due volte

Un ciclo completo viene completato quando si incontra un'istruzione due volte.
La prima affermazione incontrata due volte è <test>.
Ciò renderebbe la <increment>fine del primo ciclo.
- Primo ciclo: <test>-> <statement>-> <increment>
- Secondo ciclo: <test>-> <statement>-><increment>

4 / È una configurazione

Sta <init>semplicemente impostando tutto ciò che è necessario per il primo ciclo.
Sta <increment>semplicemente installando tutto ciò che è necessario per il secondo ciclo.
Ciò renderebbe l' <increment>inizio del secondo ciclo.
- Primo ciclo: <init as a setup>-> <test>-> <statement>
- Secondo ciclo: <increment as a setup>-> <test>-><statement>


La specifica della lingua ECMAScript® 2016

Durata di for(<init>;<test>;<increment>)<statement>;

Lascia che varDcl sia il risultato della valutazione <init>.
ReturnIfAbrupt (varDcl).
Ritorno ? ForBodyEvaluation ( <test>, <increment>, <statement>, «», labelSet).

Esistono tre forme, quindi ho preso la più breve qui, non c'è differenza:
- Qualunque sia la <init>parte non fa parte della prima iterazione.
- Ciò che è rilevante è in ForBodyEvaluation.

Dettagli di ForBodyEvaluation ( <test>, <increment>, <statement>, «», labelSet)

0 Lascia che V non sia definito.
1 eseguire? CreatePerIterationEnvironment (perIterationBindings).
2 Ripeti
3 Se non è [vuoto], quindi
4 Lascia che testRef sia il risultato della valutazione <test>.
5 Lascia che testValue sia? GetValue (testRef).
6 Se ToBoolean (testValue) è falso, restituisce NormalCompletion (V).
7 Lascia che il risultato sia il risultato della valutazione <statement>.
8 Se LoopContinues (risultato, labelSet) è falso, restituisce Completamento (UpdateEmpty (risultato, V)).
9 Se il risultato. [[Valore]] non è vuoto, sia V il risultato. [[Valore]].
10 eseguire? CreatePerIterationEnvironment (perIterationBindings).
11 Se non è [vuoto], allora
12 Sia incRef il risultato della valutazione <increment>.
13 Eseguire? GetValue (incRef).

6 / Lo vedo

Un ciclo completo per una corsa completa della parte ripetuta.
Ciò renderebbe la <increment>fine del primo ciclo.
- Primo ciclo: <test>-> <statement>-> <increment>/ In altre parole dalla riga 3 alla riga 13
- Secondo ciclo: <test>-> <statement>-> <increment>/ In altre parole dalla riga 3 alla riga 13

7 / Un ciclo è un'iterazione

Un ciclo inizia con CreatePerIterationEnvironment.
Quindi, quando CreatePerIterationEnvironmentsi incontra, inizia un nuovo ciclo, che termina così il precedente.
Ciò renderebbe l' <increment>inizio del secondo ciclo.
- Primo ciclo: <test>-> <statement>/ In altre parole dalla riga 1 alla riga 9
- Secondo ciclo: <increment>-> <test>-> <statement>/ In altre parole dalla riga 10 loop fino alla riga 9


È la <increment>fine del primo ciclo o l'inizio del secondo ciclo?

La spiegazione giusta è 6 o 7.


8
Penso di essere più propenso ad attribuire l'incremento alla fine della prima iterazione, piuttosto che all'inizio della seconda iterazione o a nessuna iterazione. Suppongo che questa sia un'ambiguità della domanda.

1
Poiché for(a;b;c)d;è approssimativamente equivalente a a;while(b){d;c;}, sono propenso a dire che l'errore viene ancora generato nella prima iterazione (prima che la condizione del ciclo venga verificata una seconda volta).
Produzioni ETH il

@Hurkyl La prima iterazione inizia con l'inizializzazione, quindi penso che l'incremento dovrebbe essere l'inizio della seconda iterazione.
Hedi,

4
Se leggi le specifiche , puoi vedere che l'operazione di incremento è l'ultima parte dell'iterazione e come tale appartiene ancora alla prima iterazione.
Nit

3
@Hedi Non vedo quanto sia rilevante. L'operazione di incremento fa chiaramente parte della prima esecuzione del ciclo. Per riformulare, quando viene chiamata l'operazione di incremento, il ciclo non ha terminato una singola corsa completa.
Nit

4

INTERCAL , 12 byte

(1)DO(1)NEXT

Provalo online!

NEXTè il comando di flusso di controllo principale di INTERCAL-72. (Sono state introdotte revisioni successive COME FROM, che sono diventate più famose, ma non erano nella versione originale del linguaggio; e tutte le implementazioni INTERCAL finite sono a conoscenza del supporto NEXTper la compatibilità con le versioni precedenti, con tutti tranne uno che ne abilita il supporto per impostazione predefinita. Non sento il bisogno di nominare INTERCAL-72 specificamente nel titolo.)

Quando si utilizza NEXTper formare un ciclo, è necessario utilizzare RESUMEo FORGETper liberare lo spazio utilizzato per ricordare dove si trova il programma; RESUMErende retroattivamente NEXTqualcosa di simile a una chiamata di funzione (anche se puoi tornare da funzioni diverse da quella in cui ti trovi) mentre lo FORGETrende in qualcosa di più simile a un'istruzione GOTO. Se non lo fai (e questo programma no), il programma si arresterà in modo anomalo dopo 80 iterazioni (questo comportamento è in realtà specificato nella specifica INTERCAL).

È in qualche modo ambiguo se questo conta come ricorsione illimitata (non consentita nella domanda); puoi certamente usare questo tipo di NEXTimplementare una chiamata di funzione, nel qual caso sarebbe effettivamente una funzione ricorsiva, ma qui non ci sono abbastanza informazioni per determinare se stiamo facendo una chiamata di funzione o meno. Almeno, lo sto pubblicando comunque perché non viola in modo inequivocabile le regole e un'implementazione INTERCAL che ha ottimizzato la "coda di chiamata" non solo violerebbe le specifiche, ma causerebbe anche la rottura della maggior parte dei programmi esistenti, perché il ritorno da la "funzione sbagliata" è il modo principale per fare l'equivalente di un'istruzione IF.

Ecco il messaggio di errore risultante, generato da C-INTERCAL:

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

(Si noti che la seconda riga è rientrata con una scheda e la terza con otto spazi. Questo sembra corretto in un terminale o in quasi tutti i programmi che hanno tabulazioni a multipli di 8. Tuttavia, Markdown ha tabulazioni a multipli di quattro, violando le ipotesi che la maggior parte dei programmi meno recenti fa riguardo alle schede, quindi il messaggio di errore è un po 'malformattato qui.)


L'errore dice davvero CORRECT SOURCE AND RESUBNIT? Come in un refuso nel messaggio di errore C-INTERCAL originale?
Andrakis,

1
@Andrakis: Sì, lo fa. Quel refuso è stato conservato con cura per anni.

3

Pyth, 3 byte

W1w

Provalo online.

W1è solo while 1:in Python. Il corpo del ciclo stampa una riga letta da STDIN, che si arresta in modo anomalo per la seconda iterazione quando il codice viene eseguito con input vuoto.

Se i loop che usano #(loop-until-error) sono vietati (presumo così), penso che questo sia il più breve che può ottenere.


3

Python 3, 29 byte

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

Davvero semplice. Alla seconda chiamata a x, non ci sono, e Python se ne lamenta.


3

Labirinto , 3 byte

#(/

Provalo online!

Come la maggior parte dei linguaggi 2D, Labyrinth non ha costrutti loop espliciti. Al contrario, qualsiasi codice disposto in modo tale da essere eseguito più volte di seguito è un ciclo in queste lingue. Nel caso di Labyrinth, un semplice programma lineare funge da loop, poiché il puntatore dell'istruzione rimbalza avanti e indietro su di esso. Se il programma è abc(per alcuni comandi a, be c), l'esecuzione effettiva sarà abcbabcbabcb...tale da essere eseguita abcbin un ciclo infinito.

Per quanto riguarda il motivo per cui questo particolare programma si arresta in modo anomalo sulla seconda iterazione di questo ciclo, ecco cosa fanno i singoli comandi. Nota che lo stack di Labyrinth contiene una quantità infinita implicita di zeri nella parte inferiore:

#   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 (borderline non in competizione)

exec $0 1$@

Questo script si esegue in modo ricorsivo, aggiungendo 1gli args passati ad ogni iterazione. Penso che questo contenga come TCO perché exec riutilizza lo spazio di processo ma non consuma stack. È borderline non competitiva perché ci sono voluti circa 10 minuti prima di essere ucciso sulla mia macchina - YMMV.


1
exec $0 1$@$@ termina molto più velocemente ma è più lungo di due caratteri.
Jasen,

3

cmd, 34 byte

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

Questo ciclo %i da 0 a 10. Il colorcomando (antico) accetterà felicemente qualsiasi argomento che abbia 2 cifre (esad) decimali. Con l'argomento 100fallirà, stampando il messaggio di aiuto e impostando ERRORLEVELsu 1.

Prova del ciclo in esecuzione almeno una volta: il colore della tua shell sarà diverso!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.