Pętla bez „zapętlenia” [zamknięta]

85

Pytanie podobne do tego zostało zadane kilka lat temu , ale to jest jeszcze trudniejsze.

Wyzwanie jest proste. Napisz program (w wybranym języku), który wielokrotnie wykonuje kod bez użycia jakichkolwiek struktur powtarzania takich jak while, for, do while, foreachlub goto( Więc dla was wszystkich nitpickers, nie można użyć pętli ). Jednak rekursja jest niedozwolona, ​​w funkcji wywołującej sens (patrz definicja poniżej) . To uczyniłoby to wyzwanie zdecydowanie zbyt łatwym.

Nie ma ograniczeń co do tego, co należy wykonać w pętli, ale opublikuj wyjaśnienie z odpowiedzią , aby inni mogli dokładnie zrozumieć, co jest wdrażane.

Dla tych, którzy mogą się rozłączyć z definicjami, definicja pętli dla tego pytania jest następująca:

A programming language statement which allows code to be repeatedly executed.

A definicja rekurencji dla tego pytania będzie twoją standardową definicją funkcji rekurencyjnej:

A function that calls itself.

Zwycięzcą zostanie odpowiedź, która uzyska najwięcej głosów poparcia 16 lipca o godzinie 10 czasu wschodniego. Powodzenia!

AKTUALIZACJA:

Aby uspokoić wciąż wyrażane zamieszanie, może to pomóc:

Zasady jak podano powyżej:

  • Nie używaj pętli ani goto
  • Funkcje nie mogą się nazywać
  • Rób co chcesz w „pętli”

Jeśli chcesz coś zaimplementować, a reguły wyraźnie tego nie zabraniają, śmiało i zrób to. Wiele odpowiedzi już zagięło zasady.

CailinP
źródło
27
Dla tych, którzy chcą łatwej sztuczki, nie mogę się tym przejmować: P Wykonaj 2 funkcje, function Apołączenia function Bi function Bwywołania, function Apodczas gdy jedna z funkcji coś wykona. Ponieważ funkcja nie nazywa się sama, powinna być poprawna na podstawie kryteriów ^. ^
Teun Pronk
2
„Zmieniono na konkurs popularności, skupiając się na kreatywności”. Zmiana pytania to oszukiwanie!
CousinCocaine
4
Definicja „rekurencji” nie jest zbyt przydatna. Lepiej byłoby zabronić funkcji rekurencyjnych , które odnoszą się do siebie bezpośrednio lub pośrednio.
lrn
3
Niejasne są „definicje” konstruktora pętli i rekurencji. Żadne z nich nie są bardzo precyzyjne. Przykład: rep(f){f();f();}- jest to instrukcja (deklaracja funkcji jest instrukcją w niektórych językach), która pozwala na wielokrotne wykonywanie kodu. Czy to niedozwolone? Pytasz o kod do implementacji pętli. Jeśli ten kod jest składniowo instrukcją, właśnie go zabroniłeś. Inny przykład: f(b) { b(); g(b); }; g(b) { f(b); }. Powiedziałbym, że fjest funkcją rekurencyjną (poprzez wzajemną rekurencję g). Czy to niedozwolone?
lrn
3
@CailinP, „odłożyłem słuchawkęna to, że pytania na stronie powinny dotyczyć tematu witryny: oznacza to posiadanie jasnej, obiektywnej specyfikacji, czego nie ma w tym pytaniu.
Peter Taylor

Odpowiedzi:

258

Rubin

def method_missing(meth,*args)
  puts 'Banana'
  send(meth.next)
end

def also
  puts "Orange you glad I didn't say banana?"
end

ahem

Próbny

Odchrząkuje, wydrukuje „Banan” 3070 razy, a także „Orange, cieszę się, że nie powiedziałem banana?”.

Wykorzystuje to niedorzeczną funkcję definiowania metody Ruby dokładnie w czasie, aby zdefiniować każdą metodę, która leży alfabetycznie między słowami „ahem” i „również” („ahem”, „ahen”, „aheo”, „ahep”, „aheq”, „aher”, „ahes”, „ahet”, „aheu”, „ahev” ...), aby najpierw wydrukować banan, a następnie wywołać następny na liście.

histocrat
źródło
4
W końcu uderza „także”, które jest zdefiniowane i dlatego nie brakuje.
histocrat
77
To jest histeryczne.
Michael B
4
@barrycarter: w języku Ruby, String#nextktóry jest wywoływany w method_missingfunkcjach mniej więcej takich jak dodawanie 1 do liczby, z tym wyjątkiem, że działa ze wszystkimi znakami alfanumerycznymi (i innymi niż alnum, jeśli są to jedyne znaki w ciągu). Zobacz ruby-doc.org/core-2.1.2/String.html#method-i-next
3Doubloons
2
@NickT jest użyteczny w klasach takich jak konstruktory XML, w których można utworzyć dowolny tag utworzony tylko przez b.my_tag. Jest również używany w modelach ActiveRecord lub OpenStruct. W „Wat talk” mówi, że globalność method_missingjest zła, ale zakres jest niesamowity.
Hauleth,
2
Pamiętam stary komentarz do innego programu rubinowego: „Podoba mi się, ponieważ ma metamfetaminę”
vidya sagar
82

Python - 16

lub w dowolnym innym języku z eval.

exec"print 1;"*9
Vectorized
źródło
Czy możesz opisać, co robi twój program?
CailinP
10
Pobiera string ( "print 1;"), powiela go 9 razy ( *9), a następnie wykonuje wynikowy string ( exec). Powtarzanie fragmentu kodu bez zapętlania.
scragar
12
Tak, mnożenie ciągów!
Thane Brimhall
2
Działa również w Ruby Jeśli zmienisz execsię eval lubprint do echo.
Ajedi32,
80

CSharp

Rozszerzyłem kod w bardziej czytelny sposób, ponieważ nie jest to już kod do golfa i dodałem licznik przyrostowy, aby ludzie mogli zobaczyć, że ten program coś robi.

class P{
    static int x=0;
    ~P(){
        System.Console.WriteLine(++x);
        new P();
    }
    static void Main(){
        new P();
    }
}

(Nigdy tego nie rób proszę).

Na początku tworzymy nową instancję Pklasy, która gdy program próbuje wyjść, wywołuje GC, który wywołuje finalizator, który tworzy nową instancję Pklasy, która, gdy próbuje wyczyścić, tworzy nową, Pktóra wywołuje finalizator. .

Program w końcu umiera.

Edycja: Niewytłumaczalnie działa to tylko około 45 tysięcy razy przed śmiercią. Nie do końca wiem, jak GC wymyślił moją trudną nieskończoną pętlę, ale tak się stało. Krótko mówiąc, wydaje się, że nie udało się tego rozgryźć, a wątek został zabity po około 2 sekundach wykonania: https://stackoverflow.com/questions/24662454/how-does-a-garbage-collector-avoid-an -infinite-loop-here

Edycja2: Jeśli uważasz, że jest to trochę zbyt podobne do rekurencji, rozważ moje inne rozwiązanie: https://codegolf.stackexchange.com/a/33268/23300

Wykorzystuje reifikację metod ogólnych, dzięki czemu w czasie wykonywania stale generuje nowe metody, a każda z metod nazywa się metodą świeżo wybitą. Unikam również używania referenceparametrów typu, ponieważ zwykle środowisko wykonawcze może współdzielić kod dla tych metod. W przypadku valueparametru typu środowisko wykonawcze jest zmuszane do utworzenia nowej metody.

Michael B.
źródło
20
Nawet nie wiedziałem, że C # ma destruktory. +1 za nauczenie mnie.
patrz
4
@ TheRare, tak, ale mają one charakter niedeterministyczny i mogą nigdy nie zostać wywołane podczas wykonywania programu. Są one zaimplementowane jako nadpisanie metody wirtualnej, Finalizewięc czasami są wywoływane finalizer. W prawdziwym języku C # należy użyć IDisposablewzorca.
Michael B,
Wydaje się, że w pewnym momencie następuje przerwa. Nie sądzę, że to GC zatrzymuje cykl, ale system operacyjny decyduje, że zakończenie twojego programu trwa zbyt długo.
LVBen
Myślę, że to naprawdę środowisko uruchomieniowe decydujące się na zabicie programu, niekoniecznie system operacyjny. Wątek modułu wyrzucania elementów bezużytecznych wywoływany na końcu programu ma ustalony limit czasowy ~ 2 sekund przed zabiciem.
Michael B,
Z pewnymi drobnymi modyfikacjami (niedopuszczenie do zakończenia programu, zwolnienie pierwszego obiektu P do GC i wielokrotne wywoływanie GC.Collect), mogę sprawić, by działał bez końca.
LVBen
53

Befunge

.

Dobre stare Befunge generuje 0 (z pustego stosu) prawie na zawsze, gdy linie się zawijają.

Le Canard fou
źródło
1
Ha! Uwielbiam takie sztuczki
CailinP
47

JS

(f=function(){ console.log('hi!'); eval("("+f+")()") })()

Funkcja zabawy!

Funkcja, która tworzy inną funkcję z tym samym ciałem co ona sama, a następnie uruchamia ją.

Wyświetli się hi na końcu, gdy limit stosu zostanie osiągnięty i cała rzecz się zawali.

Oświadczenie: nie będziesz mógł nic zrobić w przeglądarce, dopóki nie zostanie osiągnięty limit stosu.


I jeszcze jedno, więcej zła :

function f(){ var tab = window.open(); tab.f = f; tab.f()}()

Tworzy funkcję, która otwiera okno, następnie tworzy funkcję w tym oknie, która jest kopią funkcji, a następnie uruchamia ją.

Oświadczenie: jeśli zezwolisz na otwieranie wyskakujących okienek, jedynym sposobem na zakończenie tego będzie ponowne uruchomienie komputera

eithed
źródło
5
To na pewno dość złe;)
CailinP
28
@CailinP Na pewno dość eval.
patrz
Myślę, że brakuje fci końca drugiej funkcji. Powinno być }f()na końcu.
Chirag Bhatia - chirag64
2
Niestety zauważyłem to, ponieważ próbowałem. : P
Chirag Bhatia - chirag64
7
-1 - to tylko rekurencja.
immibis
39

Montaż x86 / DOS

    org 100h

start:
    mov dx,data
    mov ah,9h
    int 21h
    push start
    ret

data:
    db "Hello World!",10,13,"$"

Czy powiedziałem, że nie ma odwrotnej rekurencji ogona ? Czy ja? madame naśladuje purpurowe smoki

Jak to działa

retInstrukcja, używany do powrotu z funkcji, rzeczywiście pojawia adres powrotu ze stosu (która zwykle jest umieścić tam przez odpowiedni call) i skacze do niej. Tutaj przy każdej iteracji podajemy pushadres punktu wejścia na stosie przed zwróceniem, generując w ten sposób nieskończoną pętlę.

Matteo Italia
źródło
Zastanawiałem się, czy było to możliwe podczas montażu.
Ian D. Scott
2
Bałagan ze stosem na własne ryzyko . Oto smoki ;-)
Digital Trauma
1
Miałem zadzwonić do codegolf.stackexchange.com/a/34295/11259 jako duplikat tego jednego, ale widzę, że tak naprawdę jest to wcześniejsza odpowiedź
Digital Trauma
@DigitalTrauma: tak, zauważyłem po opublikowaniu wpisu, ale przywiązałem się do zdjęcia Madame Mim. :-) Na szczęście istnieją pewne różnice (jego jest nieco bardziej zaciemniony i działa na 32-bitowym Linuksie, moje są odtwarzane bezpośrednio na DOS i nie ma innego skoku), jeśli nikt nie miałby nic przeciwko, zostawiłbym to tutaj.
Matteo Italia,
@MatteoItalia Nie zaciemniony, po prostu gburowaty;) (choć „dodaj eax, 4” też mnie zdezorientowało, nie mogłem znaleźć tabeli rozmiarów opcode, więc po prostu zgadłem). Zrobiłem to w kompilatorze online podczas kompilacji mojego projektu roboczego, więc wygląda okropnie. Świetny pomysł na użycie „start:”.
PTwr
37

Jawa

Prosto z XKCD

Klejenie

To niekończąca się gra polegająca na złapaniu rodzica i dziecka!

Cel CHILDjest ustawiony na, PARENTa celem PARENTjest CHILD. Podczas PARENTwywołań AIMwyrzuca instancję BALLklasy i zostaje przechwycona przez instrukcję catch. Instrukcja catch wywołuje następnie PARENT.TARGET.AIMmiejsce docelowe CHILD. CHILDInstancja robi to samo i „wyrzuca piłkę z powrotem” do rodzica.

Kirk Backus
źródło
3
Lubię te komiksy!
Derek 朕 會 功夫
1
Byłoby lepiej, gdyby piłka była rzeczywiście rzucana między rodzicem a dzieckiem. Tak jak jest, piłka jest zawsze rzucana i łapana przez tę samą „osobę”.
Ajedi32,
@ Ajedi32 Wygląda na to, że rzuca go tam iz powrotem; Rodzice CELEM jest dziecko, a celem dziecka jest rodzic. Cel jest wzywany do rodzica, który rzuca piłką, a dziecko celuje i rzuca piłką, pętla
Alex Coleman
12
@AlexColeman Ten kod jest analogiczny do tego, jak rodzic rzuca piłkę w powietrze, łapie ją, a następnie podaje dziecku, które robi to samo, zanim oddaje piłkę rodzicowi i tak dalej.
Ajedi32,
11
Polecenie TARGET.AIM(B);w metodzie AIMjest wywołaniem rekurencyjnym. To narusza zasadę „funkcje nie mogą się nazywać”.
Theodore Norvell
31

Bash, 3 znaki

yes

tak wielokrotnie zwraca „y” na konsoli

Edycja: zachęcamy wszystkich do edycji tego wiersza:

yes something | xargs someaction

(dzięki Olivier Dulac)

Kuzyn Kokaina
źródło
1
Dlaczego to nadal działa? nie kwestionuję tego, próbuję tylko zrozumieć, dlaczego.
Teun Pronk
2
@TeunPronk yesto polecenie bash, które wypisuje słowo tak, dopóki nie zostanie zabite lub strumień zostanie zamknięty. Jeśli pisze na ekranie, nigdy się nie zatrzyma, dopóki go nie zabijesz. Jest to jednak trochę oszustwo, ponieważ jest to polecenie, które zasadniczo składa się z pętli nad printf.
scragar
1
Bardziej zabawne byłoby użycie yesinnej pętli.
trlkly
3
@izkata: ale wtedy możesz yes something | xargs someaction:: bez rekurencji (możesz nawet dodać -n 1 do xargs, aby mieć tylko 1 „coś” w wierszu itp.). Korzystanie z xargs otwiera drogę do bardziej złożonych zachowań (nawet tych, które w ogóle nie mają nic wspólnego z wynikiem tak)
Olivier Dulac
4
@scragar powinieneś właśnie odpowiedzieć yes.
daviewales
28

C, 35 znaków

main(int a,char**v){execv(v[0],v);}

Program wykonuje się sam. Nie jestem pewien, czy uważa się to za rekurencję, czy nie.

kwokkie
źródło
4
@mniip Rekurencja ogona, a jeśli zastosowana na poziomie procesu
Izkata
3
@ Iskata Ogon rekurencyjny jest nadal rekurencyjny, ale to nie jest rekurencja. Rekurencja oznacza, że ​​funkcja (lub proces w tym przypadku) „czeka” na zakończenie kolejnej iteracji. W takim przypadku execpowoduje , że nowy proces zastępuje oryginalny, więc nie ma stosu wywołań, który ostatecznie zwróci lub przepełni.
millinon
4
@millinon W języku obsługującym optymalizację rekurencja ogona zastępuje poprzednie wywołanie w stosie wywołań, podobnie jak execpoprzedni proces. To też się nie przepełni.
Izkata,
1
@ Millinon, aby być super pedantycznym i dłużej przeciągać tę dyskusję, w języku programowania Scheme ta optymalizacja jest funkcją językową. W specyfikacji jest to, że jeśli wykonasz wywołanie rekurencyjne, interpreter / kompilator musi ponownie użyć ostatniej ramki stosu. Wynika to z faktu, że Schemat nie ma wbudowanych struktur zapętlania, więc jedynym sposobem na zaimplementowanie pętli w Schemacie jest wykonanie rekurencji ogona, i byłoby trochę do bani, gdyby przepełnienie stosu było spowodowane zbyt dużą liczbą zapętleń :)
Ord
2
Jeśli chcesz pedantry, Scheme nie ma „optymalizacji połączeń ogonowych”, ma „odpowiednie wezwania ogonów”. Nie jest to optymalizacja, jest to podstawowy wymóg standardu językowego, a niedostarczenie go nie jest dozwolone, więc „optymalizacja” (lub sugestia, że ​​ma to coś wspólnego z rekurencją) jest bardzo odradzanym terminem.
Leushenko,
28

C (z wbudowanymi GCC - wydaje się również działać z clang)

  • Brak wyraźnych pętli
  • Brak wyraźnych gotos
  • Brak rekurencji
  • Po prostu dobry staromodny bałagan ze stosem (dzieci, nie próbujcie tego w domu bez nadzoru):
#include <stdio.h>

void *frameloop (void *ret_addr) {
    void **fp;
    void *my_ra = __builtin_return_address(0);

    if (ret_addr) {
        fp = __builtin_frame_address(0);
        if (*fp == my_ra) return (*fp = ret_addr);
        else fp++;
        if (*fp == my_ra) return (*fp = ret_addr);
        else fp++;
        if (*fp == my_ra) return (*fp = ret_addr);
        else fp++;
        if (*fp == my_ra) return (*fp = ret_addr);
        return NULL;
    } else {
        return (my_ra);
    }
}

int main (int argc, char **argv) {
    void *ret_addr;
    int i = 0;

    ret_addr = frameloop(NULL);
    printf("Hello World %d\n", i++);
    if (i < 10) {
        frameloop(ret_addr);
    }
}

Wyjaśnienie:

  • main()pierwsze połączenia frameloop(NULL). W takim przypadku użyj __builtin_return_address()wbudowanego, aby uzyskać adres zwrotny (in main()), frameloop()który powróci. Zwracamy ten adres.
  • printf() aby pokazać, że się zapętlamy
  • teraz dzwonimy frameloop()z adresem zwrotnym dla poprzedniego połączenia. Przeglądamy stos pod kątem bieżącego adresu zwrotnego, a gdy go znajdujemy, zastępujemy poprzedni adres zwrotny.
  • Następnie wracamy z drugiego frameloop()połączenia. Ale ponieważ adres zwrotny został zhakowany powyżej, w końcu wracamy do punktu, w main()którym pierwsze połączenie powinno wrócić. W ten sposób powstaje pętla.

Wyszukiwanie adresu zwrotnego na stosie byłoby oczywiście czystsze jako pętla, ale rozwinąłem kilka iteracji, aby nie zapętlać.

Wynik:

$ CFLAGS=-g make frameloop
cc -g    frameloop.c   -o frameloop
$ ./frameloop 
Hello World 0
Hello World 1
Hello World 2
Hello World 3
Hello World 4
Hello World 5
Hello World 6
Hello World 7
Hello World 8
Hello World 9
$ 
Cyfrowa trauma
źródło
2
miły! Zastanawiam się, dlaczego te funkcje nie są częścią specyfikacji C? ;-D
Brian Minton
4
@BrianMinton Właściwie podobna rzecz powinna być osiągalna za pomocą setjmp()/ longjmp(). Nie są one w standardzie c, ale znajdują się w standardowej bibliotece . Czułem jednak, że dzisiaj muszę ręcznie ustawić stos ;-)
Digital Trauma
@BrianMinton Domyślam się, że jest w specyfikacji procesora, co czyni go zależnym od platformy (sprzętowej). I raczej niebezpieczne jest używanie, gdy ramka stosu jest generowana automatycznie, nie zdziwiłbym się, gdyby AV płakał z powodu takiego kodu. Sprawdzić to czy to w wersjach x86 asm.
PTwr
27

Haskell

Poniższy kod nie zawiera funkcji rekurencyjnej (nawet pośrednio), nie ma prymitywnego zapętlenia i nie wywołuje żadnej wbudowanej funkcji rekurencyjnej (wykorzystuje tylko IOdane wyjściowe i powiązanie), ale jednak nieskończenie powtarza dane działanie:

data Strange a = C (Strange a -> a)

-- Extract a value out of 'Strange'
extract :: Strange a -> a
extract (x@(C x')) = x' x

-- The Y combinator, which allows to express arbitrary recursion
yc :: (a -> a) -> a
yc f =  let fxx = C (\x -> f (extract x))
        in extract fxx

main = yc (putStrLn "Hello world" >>)

Funkcja extractniczego nie nazwać, yczwraca tylko extracti mainzwraca tylko yci putStrLna >>, które nie są rekurencyjne.

Objaśnienie: Trik polega na rekurencyjnym typie danych Strange. Jest to rekurencyjny typ danych, który sam się zużywa, co, jak pokazano w przykładzie, umożliwia dowolne powtarzanie. Po pierwsze, możemy skonstruować extract x, co zasadniczo wyraża x xsamozastosowanie w niepisanym rachunku lambda. Pozwala to skonstruować kombinator Y zdefiniowany jako λf.(λx.f(xx))(λx.f(xx)).


Aktualizacja: Jak sugeruję, zamieszczam wariant, który jest bliższy definicji Y w rachunku typu lambda bez typu:

data Strange a = C (Strange a -> a)

-- | Apply one term to another, removing the constructor.
(#) :: Strange a -> Strange a -> a
(C f) # x = f x
infixl 3 #

-- The Y combinator, which allows to express arbitrary recursion
yc :: (a -> a) -> a
yc f =  C (\x -> f (x # x)) # C (\x -> f (x # x))

main = yc (putStrLn "Hello world" >>)
Petr Pudlák
źródło
3
Struktury danych rekurencyjnych zamiast funkcji rekurencyjnych ... fajnie.
ApproachingDarknessFish
6
ten jest bliski mojemu sercu będąc kimś, kto jest zainteresowany całkowitym programowaniem funkcjonalnym. Właśnie pokazałeś, jak zrobić kombinator Y z negatywnie powtarzającym się typem danych. To dlatego wszystkie języki wymagają powtarzających się typów występujących po prawej stronie strzałki i dlaczego drzewa różane są niedozwolone. Niezłe! Założyłem konto tutaj, aby to zagłosować!
Jake
Możesz usunąć letpowiązanie i zdefiniować yc f = extract $ C $ f.extract, ponieważ letprawdopodobnie jest to funkcja języka, która umożliwia rekurencję (klasyczna let x = x in x). Zmniejsza to również niektóre znaki :)
Earth Engine
a nawetyc = extract . C . (.extract)
Earth Engine
@EarthEngine Prawda, chciałem po prostu utrzymać strukturę bliższą oryginalnej definicji Y.
Petr Pudlák
26

C ++

Poniżej przedstawiono wyniki odliczania od 10 do „Blast off!” za pomocą metaprogramowania szablonu.

#include <iostream>

template<int N>
void countdown() {
    std::cout << "T minus " << N << std::endl;
    countdown<N-1>();
}

template<>
void countdown<0>() {
    std::cout << "Blast off!" << std::endl;
}

int main()
{
    countdown<10>();
    return 0;
}

Może to wyglądać jak klasyczny przykład rekurencji, ale tak naprawdę nie jest to, przynajmniej technicznie, zależne od twojej definicji. Kompilator wygeneruje dziesięć różnych funkcji. countdown<10>wypisuje „T minus 10”, a następnie wywołuje countdown<9>i tak dalej do countdown<0>, co wypisuje „Blast off!” a następnie wraca. Rekurencja ma miejsce podczas kompilowania kodu, ale plik wykonywalny nie zawiera żadnych struktur zapętlonych.

W C ++ 11 można osiągnąć podobne efekty za pomocą constexprsłowa kluczowego, takiego jak ta funkcja silnia. (Nie można zaimplementować przykładu odliczania w ten sposób, ponieważ constexprfunkcje nie mogą mieć skutków ubocznych, ale myślę, że może to być możliwe w nadchodzącym C ++ 14).

constexpr int factorial(int n)
{
    return n <= 1 ? 1 : (n * factorial(n-1));
}

Znowu to naprawdę wygląda rekursji, ale kompilator będzie rozwijać się factorial(10)w 10*9*8*7*6*5*4*3*2*1, a następnie prawdopodobnie wymienić go na stałej wartości 3628800, tak wykonywalny nie będzie zawierać żadnych zapętlenie lub kod rekurencyjnej.

Nataniel
źródło
4
Drugi z nich to czysta i prosta rekurencja, a nie metaprogramowanie. Po pierwsze dlatego, że kompilator (w ogólnym przypadku) wyemituje regularne treści funkcji do użycia z niestałymi argumentami; a po drugie, ponieważ podczas wykonywania operacji kompilacji nie wykonuje żadnych czynności związanych z „rozszerzaniem” w stylu szablonu, uruchamia standardową ocenę w miejscu - taką samą jak w środowisku wykonawczym - w celu wykonania 3628800bezpośrednio bez forma pośrednia.
Leushenko
@Leushenko tak, wiem. Ale znowu przykładowy przykład szablonu robi to samo - używa funkcji rekurencyjnej w języku kompletnym Turinga w czasie kompilacji - jedyną różnicą jest to, że constexpr używa języka, który wygląda bardziej jak C ++. Tak jak w przypadku wszystkich odpowiedzi, ta łamie zasady i jestem po prostu szczera. constexprzostał specjalnie zaprojektowany, aby (niektóre aspekty) metaprogramowania szablonów stały się przestarzałe, więc zdecydowanie warto wspomnieć w poście na ten temat.
Nathaniel
1
+1: &countdown<N-1> != &countdown<N>.
Thomas Eding,
21

Jawa

Zagrajmy z modułem ładującym klasy Java i ustawmy go jako własny element nadrzędny:

import java.lang.reflect.Field;

public class Loop {
    public static void main(String[] args) throws Exception {
        System.out.println("Let's loop");
        Field field = ClassLoader.class.getDeclaredField("parent");
        field.setAccessible(true);
        field.set(Loop.class.getClassLoader(), Loop.class.getClassLoader());

    }
}

Ta pętla jest tak silna, że ​​musisz użyć a, kill -9aby ją zatrzymać :-)

Zużywa 100,1% procesora mojego komputera Mac.

100,1% procesora

Możesz spróbować przesunąć System.outna końcu głównej funkcji, aby wypróbować alternatywne zabawne zachowanie.

Arnaud
źródło
lol. utknięcie java w sobie :)
masterX244
Uwielbiam rekurencyjny hack ładowania JVM.
Isiah Meadows
20

CSharp

Jeszcze jeden i równie zły:

public class P{

    class A<B>{
        public static int C<T>(){
            System.Console.WriteLine(typeof(T));
            return C<A<T>>();
        }
    }
    public static void Main(){
        A<P>.C<int>();
    }
}

To nie jest rekurencja ... to jest korekta szablonów kodu. Chociaż wydaje się, że wywołujemy tę samą metodę, środowisko wykonawcze stale tworzy nowe metody. Używamy parametru typu int, ponieważ faktycznie zmusza go to do utworzenia całego nowego typu, a każda instancja metody musi łączyć nową metodę. Nie można tutaj udostępniać kodu. W końcu zabijamy stos wywołań, ponieważ nieskończenie czeka na zwrot int, który obiecaliśmy, ale nigdy nie dostarczyliśmy. W podobny sposób piszemy napisany przez nas typ, aby był interesujący. Zasadniczo każde C, które nazywamy, jest całkowicie nową metodą, która ma tylko to samo ciało. Nie jest to tak naprawdę możliwe w języku takim jak C ++ lub D, który wykonuje swoje szablony w czasie kompilacji. Ponieważ C # JIT jest bardzo leniwy, tworzy to tylko w ostatniej możliwej chwili. A zatem,

Michael B.
źródło
14

Redcode 94 (Core War)

MOV 0, 1

Kopiuje instrukcję pod adres zero, aby adresować jeden. Ponieważ w Core War wszystkie adresy są względne w stosunku do bieżącego adresu PC i wielkości rdzenia modulo, jest to nieskończona pętla w jednej instrukcji bez skoku.

Ten program (wojownik) nosi nazwę „ Imp ” i został po raz pierwszy opublikowany przez AK Dewdney.

jagoda
źródło
3
Chochliki maszerują, przygotują bramy, przygotują je, bo inaczej zostaniesz zmiażdżony.
patrz
Gotowy, SPL 0, 0; MOV 1, -2naprawdę.
wberry
Fajnie, miałem nadzieję, że jeszcze tego nie opublikowano. +1
mbomb007
14

Strzałka

Myślę, że byłby to klasyczny sposób wykonywania rekurencji bez żadnej faktycznej funkcji rekurencyjnej. Żadna z poniższych funkcji nie odnosi się do siebie z nazwy, bezpośrednio lub pośrednio.

(Wypróbuj na dartpad.dartlang.org )

// Strict fixpoint operator.
fix(f) => ((x)=>f(x(x))) ((x)=>(v)=>f(x(x))(v));
// Repeat action while it returns true.
void repeat(action) { fix((rep1) => (b) { if (b()) rep1(b); })(action); }

main() {
  int x = 0;
  repeat(() {  
    print(++x);
    return x < 10;
  });
}
lrn
źródło
6
Kombinator Y?
aditsu
5
Technicznie myślę, że jest to kombinator Z, ponieważ jest przeznaczony dla ścisłego języka. Kombinator Y wymaga leniwego języka, aby uniknąć nieskończonego rozwoju. Jedyną różnicą jest to, że ta ostatnia część jest rozszerzona.
lrn
12

JS

Niezbyt oryginalny, ale mały. 20 znaków.

setInterval(alert,1)
Xem
źródło
Możesz faktycznie usunąć ,1i nadal będzie
działać
@Derek 朕 會 功夫 jeśli to zrobię, dostaję tylko jeden alert w Firefoksie
xem
1
W chrome działa bez ostatniego parametru. Kod należy policzyć jako poprawny, jeśli działa w co najmniej jednym środowisku.
Derek 朕 會 功夫
3
@Derek 朕 會 功夫setIntervalnie jest jednak stwierdzeniem; to tylko funkcja. Jest używany wewnątrz wyrażenia, a jeśli nie możemy użyć wyrażeń, to po prostu już tego nie wiem.
Keen
1
@Cory - Cóż, to chyba ważne!
Derek 朕 會 功夫
12

Sygnały w C

#include <stdio.h>
#include <signal.h>

int main(void) {
    signal(SIGSEGV, main);
    *(int*)printf("Hello, world!\n") = 0;
    return 0;
}

Zachowanie tego programu jest oczywiście bardzo nieokreślone, ale dziś na moim komputerze wciąż wypisuje „Witaj, świecie!”.

Thomas Padron-McCarthy
źródło
11

Emacs Lisp

To świetny czas, aby pochwalić się potężnym projektem Lisp, w którym „kod to dane, a dane to kod”. To prawda, że ​​przykłady te są bardzo nieefektywne i nigdy nie należy ich używać w prawdziwym kontekście.

Makra generują kod, który jest rozwiniętą wersją domniemanej pętli, a wygenerowany kod jest oceniany w czasie wykonywania.

repeat-it: pozwala zapętlić N razy

(defmacro repeat-it (n &rest body)
  "Evaluate BODY N number of times.
Returns the result of the last evaluation of the last expression in BODY."
  (declare (indent defun))
  (cons 'progn (make-list n (cons 'progn body))))

test powtórzeń:

;; repeat-it test
(progn
  (setq foobar 1)

  (repeat-it 10
    (setq foobar (1+ foobar)))

  ;; assert that we incremented foobar n times
  (assert (= foobar 11)))

repeat-it-with-index:

To makro jest podobne, repeat-itale w rzeczywistości działa tak jak zwykłe makro zapętlone do-times, pozwala określić symbol, który będzie powiązany z indeksem pętli. Używa symbolu czasu rozszerzania, aby upewnić się, że zmienna indeksu jest ustawiona poprawnie na początku każdej pętli, niezależnie od tego, czy zmodyfikujesz jej wartość podczas treści pętli.

(defmacro repeat-it-with-index (var-and-n &rest body)
  "Evaluate BODY N number of times with VAR bound to successive integers from 0 inclusive to n exclusive..
VAR-AND-N should be in the form (VAR N).
Returns the result of the last evaluation of the last expression in BODY."
  (declare (indent defun))
  (let ((fallback-sym (make-symbol "fallback")))
    `(let ((,(first var-and-n) 0)
           (,fallback-sym 0))
       ,(cons 'progn
              (make-list (second var-and-n)
                         `(progn
                            (setq ,(first var-and-n) ,fallback-sym)
                            ,@body
                            (incf ,fallback-sym)))))))

test powtórzeń z indeksem:

Ten test pokazuje, że:

  1. Ciało ocenia N razy

  2. zmienna indeksu jest zawsze ustawiana poprawnie na początku każdej iteracji

  3. zmiana wartości symbolu o nazwie „awaryjne” nie zadziała z indeksem

;; repeat-it-with-index test
(progn
  ;; first expected index is 0
  (setq expected-index 0)

  ;; start repeating
  (repeat-it-with-index (index 50)
    ;; change the value of a  'fallback' symbol
    (setq fallback (random 10000))
    ;; assert that index is set correctly, and that the changes to
    ;; fallback has no affect on its value
    (assert (= index expected-index))
    ;; change the value of index
    (setq index (+ 100 (random 1000)))
    ;; assert that it has changed
    (assert (not (= index expected-index)))
    ;; increment the expected value
    (incf expected-index))

  ;; assert that the final expected value is n
  (assert (= expected-index 50)))
Jordon Biondo
źródło
11

Rachunek lambda bez typu

λf.(λx.f (x x)) (λx.f (x x))
Artur B.
źródło
3
Nie jestem pewien, czy liczy się to jako rekurencja, czy nie, co stanowi podstawową teoretyczną podstawę ... +1 w każdym razie.
puszysty
@fluffy To nie jest rekurencyjne, żadna z funkcji nie wywołuje siebie (szczególnie dlatego, że funkcje nie są nazwane).
dumny haskeller
IMHO, rachunek lambda jest modelem obliczeniowym i nie jest językiem programowania (tzn. Bez konkretnego modelu maszyny nie można uznać rachunku lambda za PL).
Ta Thanh Dinh
Możesz absolutnie zbudować maszynę, która interpretuje rachunek lambda. A składnia może być używana jako język programowania. Zobacz na przykład github.com/MaiaVictor/caramel
Arthur B
10

Haskell, 24 znaki

sequence_ (repeat (print "abc"))

lub w formie skróconej, z 24 znakami

sequence_$repeat$print"" 

(chociaż tekst został zmieniony, nadal będzie się zapętlał - spowoduje to nieskończone wydrukowanie dwóch cudzysłowów i nowego wiersza)

wyjaśnienie: print „abc” jest w zasadzie działaniem we / wy, które po prostu wypisuje „abc”.
repeat jest funkcją, która przyjmuje wartość x i zwraca nieskończoną listę składającą się tylko z x.
sekwencja_ jest funkcją, która pobiera listę akcji we / wy i zwraca akcję we / wy, która wykonuje wszystkie akcje sekwencyjnie.

więc w zasadzie ten program tworzy nieskończoną listę poleceń drukowania „abc” i wielokrotnie je wykonuje. bez pętli i rekurencji.

dumny haskeller
źródło
4
Zamierzałem zamieścić w Clojure w zasadzie tę samą odpowiedź, ale myślałem repeat, że tak będzie a programming language statement which allows code to be repeatedly executed.
patrz
3
fix(print"">>), nie obejmuje to również wyraźnie nazwanych funkcji powtarzania.
mniip
1
@ TheRare Nie wiem, jak się to kończy, ale w Haskell powtórzenie nie jest „instrukcją języka programowania, która pozwala na wielokrotne wykonywanie kodu” - jest to funkcja, która generuje nieskończone listy. jest to pętla tak jak „int [] arr = {x, x, x};” jest pętlą.
dumny haskeller
1
tak, ale coś musi zostać zaimplementowane przy użyciu rekurencji, ponieważ bez tego jest to w zasadzie niemożliwe
dumny haskeller
3
W rzeczywistości każda funkcja
zawarta
10

ASM (x86 + I / O dla Linux)

Nie ma znaczenia, jak bardzo zmagają się twoje słabe języki wysokiego poziomu, nadal będzie to po prostu ukryta manipulacja wskaźnikiem instrukcji. W końcu będzie to rodzaj „goto” (jmp), chyba że będziesz się nudzić, aby rozwinąć pętlę w czasie wykonywania.

Możesz przetestować kod w Ideone

Możesz także sprawdzić bardziej wyrafinowaną wersję tego pomysłu w kodzie Matteo Italia DOS .

Zaczyna się od ciągu 0..9 i zastępuje go A..J, nie stosuje się bezpośrednich skoków (powiedzmy, że nie wydarzyło się „goto”), nie ma też nawrotu.

Kod prawdopodobnie może być mniejszy z pewnym nadużyciem przy obliczaniu adresu, ale praca na kompilatorze online jest uciążliwa, więc zostawię go takim, jaki jest.

Część główna:

mov dl, 'A' ; I refuse to explain this line!
mov ebx, msg ; output array (string)

call rawr   ; lets put address of "rawr" line on stack
rawr: pop eax ; and to variable with it! In same time we are breaking "ret"

add eax, 4 ; pop eax takes 4 bytes of memory, so for sake of stack lets skip it
mov [ebx], dl ; write letter
inc dl ; and proceed to next 
inc ebx
cmp dl, 'J' ; if we are done, simulate return/break by leaving this dangerous area
jg print

push eax ; and now lets abuse "ret" by making "call" by hand
ret

Cały kod

section     .text
global      _start                              

_start:

;<core>
mov dl, 'A'
mov ebx, msg

call rawr
rawr: pop eax

add eax, 4
mov [ebx], dl
inc dl
inc ebx
cmp dl, 'J'
jg print

push eax
ret
;</core>

; just some Console.Write()
print:
    mov     edx,len
    mov     ecx,msg
    mov     ebx,1
    mov     eax,4
    int     0x80

    mov     eax,1
    xor     ebx, ebx
    int     0x80

section     .data

msg     db  '0123456789',0xa
len     equ $ - msg
PTwr
źródło
Miałem to nazwać dupkiem codegolf.stackexchange.com/a/34298/11259 , ale widzę, że to wcześniejsza odpowiedź. +1
Cyfrowa trauma
@DigitalTrauma och, widzę, że ktoś stworzył wyrafinowaną wersję mojego pomysłu - stara sztuczka, ale w erze zarządzania kodem ludzie często zapominają, jak to naprawdę działa. (Nie lubię gry w golfa, zbyt często sprowadza się to do „patrz mamo! Mogę sprawić, że coś się stanie, naciskając jeden klawisz!”)
PTwr
9

Preprocesor C.

Trochę „techniki”, którą wymyśliłem podczas próby zaciemnienia. Nie ma rekurencji funkcji, ale jest ... rekurencja pliku?

noloop.c:

#if __INCLUDE_LEVEL__ == 0
int main() 
{
    puts("There is no loop...");
#endif
#if __INCLUDE_LEVEL__ <= 16
    puts(".. but Im in ur loop!");
    #include "noloop.c"
#else
    return 0;
}
#endif

Napisałem / przetestowałem to za pomocą gcc. Oczywiście twój kompilator musi obsługiwać __INCLUDE_LEVEL__makro (lub alternatywnie __COUNTER__makro z pewnymi poprawkami), aby to skompilować. Powinno być dość oczywiste, jak to działa, ale dla zabawy uruchom preprocesor bez kompilacji kodu (użyj -Eflagi z gcc).

Podejście do ciemności
źródło
8

PHP

Oto jeden z PHP. Pętle zawierają ten sam plik, dopóki licznik nie osiągnie $ max:

<?php
if (!isset($i))
    $i = 0;        // Initialize $i with 0
$max = 10;         // Target value

// Loop body here
echo "Iteration $i <br>\n";

$i++;               // Increase $i by one on every iteration

if ($i == $max)
    die('done');    // When $i reaches $max, end the script
include(__FILE__);  // Proceed with the loop
?>

To samo co dla pętli for:

<?php
for ($i = 0; $i < 10; $i++) {
    echo "Iteration $i <br>\n";
}
die('done');
?>
Pichan
źródło
Cholera, to też liczy się jako rekurencja, prawda?
Pichan
Nie myśl, że tak - podobieństwo przychodzi na myśl w przypadku przykładu @ Nathaniela: preprocesor obejmie te pliki, które następnie będą oceniane jednocześnie.
wyjechał
@Pichan Powiedziałbym, że bardziej rozwija się pętla, kiedy kończysz się kopiami kodu w pamięci.
PTwr
Właśnie widziałem to pytanie dzisiaj i wymyśliłem prawie identyczny kod. Za późno dla mnie!
TecBrat
Czy jest header("Location: .?x=".$_GET['x']+1);liczony jako rekurencja?
Charlie
8

Pyton

Poniższy kod nie zawiera funkcji rekurencyjnej (bezpośredniej lub pośredniej), nie zawiera operacji podstawowej zapętlającej się i nie wywołuje żadnej wbudowanej funkcji (oprócz print):

def z(f):
    g = lambda x: lambda w: f(lambda v: (x(x))(v), w)
    return g(g)

if __name__ == "__main__":
    def msg(rec, n):
        if (n > 0):
            print "Hello world!"
            rec(n - 1)
    z(msg)(7)

Drukuje „Witaj świecie!” określoną liczbę razy.

Objaśnienie: Funkcja zimplementuje ścisły Z -punktowy kombinator , który (choć nie zdefiniowany rekurencyjnie) pozwala wyrazić dowolny algorytm rekurencyjny.

Petr Pudlák
źródło
Nazwałbym gbardzo pośrednio rekurencyjnym.
patrz
@ TheRare Dlaczego? Jaki jest twój argument? Co to za gpołączenie to gponownie? Oczywiście, sztuczka polega na samodzielnym nałożeniu g(g), ale nie wiąże się to z rekurencją. Czy rzeczywiście nazwałbyś gpośrednio rekurencyjnym, jeśli jeszcze tego nie widziałeś g(g)? Jest to standardowy sposób, jak to zrobić w językach, które nie dopuszczają definicji rekurencyjnych, takich jak rachunek lambda.
Petr Pudlák,
Dajesz gjako argument, xa następnie dzwonisz x(x).
patrz
2
@TheRare Funkcja (lub zestaw funkcji) nie jest rekurencyjna ani nierekurencyjna ze względu na sposób jej użycia, jest to określone tylko na podstawie jej definicji.
Petr Pudlák,
1
wszystkie odpowiedzi oszukują w ten czy inny sposób: zawsze jest gdzieś rekurencja lub pętla , jeśli nie w odpowiedzi, to w kodzie odpowiedź wywołuje się. Podoba mi się sposób, w jaki ten oszukuje.
Wayne Conrad,
8

kod maszynowy z80

W środowisku, w którym można wykonać pod każdym adresem i mapować pamięć ROM wszędzie, mapuj 64 KB pamięci ROM wypełnionej zerami do całej przestrzeni adresowej.

Co robi: nic. Wielokrotnie.

Jak to działa: procesor rozpocznie wykonywanie, bajt 00jest nopinstrukcją, więc po prostu będzie kontynuował, dotarł do adresu $ffff, zawinął się $0000i kontynuował wykonywanie, nopdopóki go nie zresetujesz.

Aby uczynić to nieco bardziej interesującym, wypełnij pamięć inną wartością (uważaj, aby uniknąć instrukcji sterowania przepływem).

Harold
źródło
Możesz wypełnić pamięć zerami i umieścić gdzieś prawdziwy program.
patrz
Więc mógłbyś zainstalować program 64k, bez rozgałęzień, a on po prostu wielokrotnie się uruchamiał?
Bill Woodger
@BillWoodger możesz, szczególnie jeśli nie masz żadnych przerwań na platformie (lub nie ma żadnych włączonych)
Harold
Fajna
8

Perl-regex

(q x x x 10) =~ /(?{ print "hello\n" })(?!)/;

próbny

lub wypróbuj jako:

perl -e '(q x x x 10) =~ /(?{ print "hello\n" })(?!)/;'

(?!)Nigdy nie pasuje. Dlatego silnik wyrażeń regularnych próbuje dopasować każdą pozycję zerowej szerokości w dopasowanym ciągu.

To (q x x x 10)samo co (" " x 10)- powtórz spacedziesięć razy.

Edycja: zmieniono „znaki” na pozycje o zerowej szerokości, aby były bardziej precyzyjne dla lepszego zrozumienia. Zobacz odpowiedzi na to pytanie dotyczące przepływu stosu .

jm666
źródło
6

T-SQL -12

print 1
GO 9

Właściwie bardziej dziwactwo Sql Server Management Studio. GO jest separatorem skryptów i nie jest częścią języka T-SQL. Jeśli podasz GO, a następnie liczbę, blok wykona tyle razy.

Michael B.
źródło
1
Używam T-SQL prawie codziennie i nie miałem pojęcia, że ​​możesz to zrobić za pomocą GO. +1
CailinP
Technicznie nie jest to T-SQL. GOjest w rzeczywistości dyrektywą SSMS, dlatego nie można umieścić jej w obiektach skryptowych T-SQL, takich jak np. procedura składowana.
RBarryYoung
Tak, dodałem to w komentarzu do spoilera. Myślałem, że użycie sqlcmd byłoby zbyt wielkim oszustwem.
Michael B,
6

DO#

Wyświetla wszystkie liczby całkowite z uint.MaxValue do 0.

   class Program
   {
      public static void Main()
      {
          uint max = uint.MaxValue;
          SuperWriteLine(ref max);
          Console.WriteLine(0);
      }

      static void SuperWriteLine(ref uint num)
      {
          if ((num & (1 << 31)) > 0) { WriteLine32(ref num); }
          if ((num & (1 << 30)) > 0) { WriteLine31(ref num); }
          if ((num & (1 << 29)) > 0) { WriteLine30(ref num); }
          if ((num & (1 << 28)) > 0) { WriteLine29(ref num); }
          if ((num & (1 << 27)) > 0) { WriteLine28(ref num); }
          if ((num & (1 << 26)) > 0) { WriteLine27(ref num); }
          if ((num & (1 << 25)) > 0) { WriteLine26(ref num); }
          if ((num & (1 << 24)) > 0) { WriteLine25(ref num); }
          if ((num & (1 << 23)) > 0) { WriteLine24(ref num); }
          if ((num & (1 << 22)) > 0) { WriteLine23(ref num); }
          if ((num & (1 << 21)) > 0) { WriteLine22(ref num); }
          if ((num & (1 << 20)) > 0) { WriteLine21(ref num); }
          if ((num & (1 << 19)) > 0) { WriteLine20(ref num); }
          if ((num & (1 << 18)) > 0) { WriteLine19(ref num); }
          if ((num & (1 << 17)) > 0) { WriteLine18(ref num); }
          if ((num & (1 << 16)) > 0) { WriteLine17(ref num); }
          if ((num & (1 << 15)) > 0) { WriteLine16(ref num); }
          if ((num & (1 << 14)) > 0) { WriteLine15(ref num); }
          if ((num & (1 << 13)) > 0) { WriteLine14(ref num); }
          if ((num & (1 << 12)) > 0) { WriteLine13(ref num); }
          if ((num & (1 << 11)) > 0) { WriteLine12(ref num); }
          if ((num & (1 << 10)) > 0) { WriteLine11(ref num); }
          if ((num & (1 << 9)) > 0) { WriteLine10(ref num); }
          if ((num & (1 << 8)) > 0) { WriteLine09(ref num); }
          if ((num & (1 << 7)) > 0) { WriteLine08(ref num); }
          if ((num & (1 << 6)) > 0) { WriteLine07(ref num); }
          if ((num & (1 << 5)) > 0) { WriteLine06(ref num); }
          if ((num & (1 << 4)) > 0) { WriteLine05(ref num); }
          if ((num & (1 << 3)) > 0) { WriteLine04(ref num); }
          if ((num & (1 << 2)) > 0) { WriteLine03(ref num); }
          if ((num & (1 <<  1)) > 0) { WriteLine02(ref num); }
          if ((num & (1 <<  0)) > 0) { WriteLine01(ref num); }
      }

      private static void WriteLine32(ref uint num) { WriteLine31(ref num); WriteLine31(ref num); }
      private static void WriteLine31(ref uint num) { WriteLine30(ref num); WriteLine30(ref num); }
      private static void WriteLine30(ref uint num) { WriteLine29(ref num); WriteLine29(ref num); }
      private static void WriteLine29(ref uint num) { WriteLine28(ref num); WriteLine28(ref num); }
      private static void WriteLine28(ref uint num) { WriteLine27(ref num); WriteLine27(ref num); }
      private static void WriteLine27(ref uint num) { WriteLine26(ref num); WriteLine26(ref num); }
      private static void WriteLine26(ref uint num) { WriteLine25(ref num); WriteLine25(ref num); }
      private static void WriteLine25(ref uint num) { WriteLine24(ref num); WriteLine24(ref num); }
      private static void WriteLine24(ref uint num) { WriteLine23(ref num); WriteLine23(ref num); }
      private static void WriteLine23(ref uint num) { WriteLine22(ref num); WriteLine22(ref num); }
      private static void WriteLine22(ref uint num) { WriteLine21(ref num); WriteLine21(ref num); }
      private static void WriteLine21(ref uint num) { WriteLine20(ref num); WriteLine20(ref num); }
      private static void WriteLine20(ref uint num) { WriteLine19(ref num); WriteLine19(ref num); }
      private static void WriteLine19(ref uint num) { WriteLine18(ref num); WriteLine18(ref num); }
      private static void WriteLine18(ref uint num) { WriteLine17(ref num); WriteLine17(ref num); }
      private static void WriteLine17(ref uint num) { WriteLine16(ref num); WriteLine16(ref num); }
      private static void WriteLine16(ref uint num) { WriteLine15(ref num); WriteLine15(ref num); }
      private static void WriteLine15(ref uint num) { WriteLine14(ref num); WriteLine14(ref num); }
      private static void WriteLine14(ref uint num) { WriteLine13(ref num); WriteLine13(ref num); }
      private static void WriteLine13(ref uint num) { WriteLine12(ref num); WriteLine12(ref num); }
      private static void WriteLine12(ref uint num) { WriteLine11(ref num); WriteLine11(ref num); }
      private static void WriteLine11(ref uint num) { WriteLine10(ref num); WriteLine10(ref num); }
      private static void WriteLine10(ref uint num) { WriteLine09(ref num); WriteLine09(ref num); }
      private static void WriteLine09(ref uint num) { WriteLine08(ref num); WriteLine08(ref num); }
      private static void WriteLine08(ref uint num) { WriteLine07(ref num); WriteLine07(ref num); }
      private static void WriteLine07(ref uint num) { WriteLine06(ref num); WriteLine06(ref num); }
      private static void WriteLine06(ref uint num) { WriteLine05(ref num); WriteLine05(ref num); }
      private static void WriteLine05(ref uint num) { WriteLine04(ref num); WriteLine04(ref num); }
      private static void WriteLine04(ref uint num) { WriteLine03(ref num); WriteLine03(ref num); }
      private static void WriteLine03(ref uint num) { WriteLine02(ref num); WriteLine02(ref num); }
      private static void WriteLine02(ref uint num) { WriteLine01(ref num); WriteLine01(ref num); }
      private static void WriteLine01(ref uint num) { Console.WriteLine(num--); }
   }
LVBen
źródło
1
Nie wiem, czy to się liczy. Wyraźnie dzwonisz do WriteLine01 Int.MaxValue razy. Po prostu eksplodował za ogromną ilością callstacka.
Michael B,
Jak to się nie liczy? Nie ma pętli ani rekurencji.
LVBen
1
Ponadto stos wywołań nie jest prawie ogromny, chyba że uważasz, że wysokie są 32 połączenia.
LVBen
1
Dlaczego tylko 32 razy zamiast 4294967296 razy?
LVBen
4
@ ja72 Jeśli kiedykolwiek pracuję nad projektem o otwartym kodzie źródłowym, w którym nie mogę używać pętli ani rekurencji, to całkowicie zamierzam wnieść taki kod!
LVBen
6

JS (w przeglądarce)

Co powiesz na to?

document.write(new Date());
location = location;

Drukuje bieżącą godzinę i ładuje stronę ponownie.

Pichan
źródło
No nie. Właśnie opublikowałem odpowiedź z tą samą podstawową koncepcją. Skanowałem stronę w poszukiwaniu „JavaScript” lub czegokolwiek pokazującego tagi HTML. Podejrzewam, że mogę zostawić swoją odpowiedź, tylko dlatego, że obsługuje ona narożnik, w którym lokalizacja zawiera „#”. W każdym razie +1.
Keen
W przeglądarce Firefox 30:[Exception... "The operation is insecure." code: "18" nsresult: "0x80530012 (SecurityError)" location: "<unknown>"]
Alex Reynolds
@AlexReynolds Huh, dziwne. Mój działa dobrze na FF 30.
Pichan
Skopiowałem i wkleiłem tylko kod, który został napisany. To nie działa Być może masz włączone specjalne preferencje bezpieczeństwa, aby to zadziałało?
Alex Reynolds,
@AlexReynolds Nie, nigdy nie zmieniałem żadnych ustawień bezpieczeństwa. Działa to również w Chrome.
Pichan