Loop senza "loop" [chiuso]


85

Una domanda simile a questa è stata posta un paio di anni fa , ma questa è ancora più complicata.

La sfida è semplice Scrivere un programma (in lingua di propria scelta) che esegue più volte il codice senza l'uso di strutture di ripetizione, come while, for, do while, foreacho goto( Quindi per tutti voi nitpickers, non è possibile utilizzare un ciclo ). Tuttavia, la ricorsione non è consentita, nella funzione che si chiama senso (vedi definizione sotto) . Ciò renderebbe questa sfida troppo semplice.

Non ci sono restrizioni su ciò che deve essere eseguito nel ciclo, ma pubblica una spiegazione con la tua risposta in modo che gli altri possano capire esattamente ciò che viene implementato.

Per coloro che possono essere attaccati alle definizioni, la definizione di un ciclo per questa domanda è:

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

E la definizione di ricorsione per questa domanda sarà la definizione di funzione ricorsiva standard:

A function that calls itself.

Il vincitore sarà la risposta con il maggior numero di voti il ​​16 luglio alle 10, ora orientale. In bocca al lupo!

AGGIORNARE:

Per calmare la confusione ancora espressa, ciò può aiutare:

Regole come sopra indicato:

  • Non usare loop o goto
  • Le funzioni non possono chiamarsi
  • Fai quello che vuoi nel 'loop'

Se vuoi implementare qualcosa e le regole non lo vietano esplicitamente, vai avanti e fallo. Molte risposte hanno già piegato le regole.


27
Per coloro che desiderano un trucco semplice, non posso preoccuparmi di pubblicarlo: P Basta fare 2 funzioni, function Achiamate function Be function Bchiamate function Amentre 1 delle funzioni esegue qualcosa. Poiché la funzione non si chiama da sola, dovrebbe essere valida in base ai criteri ^. ^
Teun Pronk,

2
"Passato al concorso di popolarità per concentrarsi sulla creatività" Cambiare la domanda è barare!
Cugina Cocaina,

4
La definizione di "ricorsione" non è molto utile. Sarebbe meglio vietare le funzioni ricorsive , che sono funzioni che si riferiscono a se stesse, direttamente o indirettamente.
lrn,

3
Ciò che non è chiaro sono le "definizioni" del costruttore di loop e della ricorsione. Né sono molto precisi. Esempio: rep(f){f();f();}- questa è un'istruzione (una dichiarazione di funzione è un'istruzione in alcune lingue) che consente l'esecuzione ripetuta del codice. È vietato. Richiedi il codice per implementare un ciclo. Se quel codice è sintatticamente un'istruzione, l'hai appena vietato. Un altro esempio: f(b) { b(); g(b); }; g(b) { f(b); }. Direi che fè una funzione ricorsiva (essendo reciprocamente ricorsivi g). È vietato?
lrn,

3
@CailinP, quello su cui sono " agganciato " è che le domande sul sito dovrebbero essere in tema per il sito: ciò significa avere una specifica chiara e obiettiva, cosa che questa domanda non ha.
Peter Taylor,

Risposte:


258

Rubino

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

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

ahem

dimostrazione

Si schiarisce la gola, stampa "Banana" 3070 volte e mette anche "Orange, sei contento di non aver detto banana?".

Questo utilizza la ridicola funzionalità di definizione del metodo just-in-time di Ruby per definire ogni metodo che si trova in ordine alfabetico tra le parole 'ahem' e 'also' ("ahem", "ahen", "aheo", "ahep", "aheq", "aher", "ahes", "ahet", "aheu", "ahev" ...) per stampare prima Banana e quindi chiamare il successivo nell'elenco.


4
Alla fine colpisce "anche", che è definito, e quindi non manca.
istocratico

77
Questo è isterico.
Michael B,

4
@barrycarter: in Ruby, String#nextche viene chiamato in method_missingfunzioni più o meno come l'aggiunta di 1 a un numero tranne per il fatto che funziona con tutti i caratteri alfanumerici (e non-allarmi se sono gli unici caratteri nella stringa). Vedi ruby-doc.org/core-2.1.2/String.html#method-i-next
3Doubloons

2
@NickT è utilizzabile in classi come i builder XML dove è possibile qualsiasi tag creato solo da b.my_tag. Inoltre è utilizzato nei modelli ActiveRecord o OpenStruct. In "Wat talk" afferma che il globale method_missingè negativo, ma lo scopo è fantastico.
Hauleth,

2
Ricordo un vecchio commento su un altro programma di rubini: "Mi piace perché ha meth"
vidya sagar

82

Python - 16

o qualsiasi altra lingua con eval.

exec"print 1;"*9

Puoi descrivere cosa fa il tuo programma?
CailinP

10
Prende una stringa ( "print 1;"), la duplica 9 volte ( *9), quindi esegue la stringa risultante ( exec). Ripetendo un pezzo di codice senza realmente eseguire il looping.
scragar

12
Sì per la moltiplicazione delle stringhe!
Thane Brimhall,

2
Funziona anche in Ruby se si cambia il execper eval e il printper echo.
Ajedi32,

80

CSharp

Ho ampliato il codice in un modo più leggibile in quanto questo non è più un codice golf e ho aggiunto un contatore di incrementi in modo che le persone possano effettivamente vedere che questo programma fa qualcosa.

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

(Non farlo mai per favore).

All'inizio creiamo una nuova istanza della Pclasse, che quando il programma tenta di uscire chiama il GC che chiama il finalizzatore che crea una nuova istanza della Pclasse, che quando tenta di ripulire crea una nuova Pche chiama il finalizzatore. .

Alla fine il programma muore.

Modifica: inspiegabilmente funziona solo circa 45k volte prima di morire. Non so come il GC abbia capito il mio complicato loop infinito, ma lo ha fatto. In breve sembra non averlo capito e il thread è stato ucciso dopo circa 2 secondi di esecuzione: https://stackoverflow.com/questions/24662454/how-does-a-garbage-collector-avoid-an -infinito-loop-qui

Edit2: se pensi che sia un po 'troppo simile alla ricorsione, considera la mia altra soluzione: https://codegolf.stackexchange.com/a/33268/23300

Utilizza la reificazione di metodi generici in modo che in fase di runtime generi costantemente nuovi metodi e ogni metodo a termine chiama un metodo coniato di recente. Inoltre evito di utilizzare i referenceparametri di tipo, poiché normalmente il runtime può condividere il codice per tali metodi. Con un valueparametro type il runtime è costretto a creare un nuovo metodo.


20
Non sapevo nemmeno che C # avesse distruttori. +1 per avermi insegnato.
Seequ,

4
@TheRare, lo fa ma sono di natura non deterministica e potrebbero non essere mai richiamati durante l'esecuzione di un programma. Sono implementati come override del metodo virtuale, Finalizequindi a volte vengono chiamati finalizer. Nel vero C #, dovresti usare il IDisposablemodello.
Michael B,

Sembra che ci sia un timeout che si verifica ad un certo punto. Non penso che sia il GC a interrompere il ciclo, ma invece il sistema operativo sta decidendo che il programma impiega troppo tempo per terminare.
LVBen,

Penso che questo sia davvero il runtime che decide di uccidere il programma non necessariamente il sistema operativo. Al thread Garbage Collector chiamato alla fine del programma viene assegnato un limite di tempo fisso di ~ 2 secondi prima che venga ucciso.
Michael B,

Con alcune piccole modifiche (non lasciando terminare il programma, rilasciando il primo oggetto P sul GC e chiamando ripetutamente GC.Collect), riesco a farlo funzionare indefinitamente.
LVBen,

53

Befunge

.

Il buon vecchio Befunge produce 0 (da uno stack vuoto) praticamente per sempre, mentre le linee si avvolgono.


1
Ha! Adoro i trucchi come questo
CailinP

47

JS

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

Fun fun!

Una funzione che crea un'altra funzione con lo stesso corpo di se stessa e quindi la esegue.

Verrà visualizzato ciao alla fine quando viene raggiunto il limite di stack e l'intero oggetto collassa.

Disclaimer: non sarai in grado di fare nulla nel tuo browser fino al raggiungimento del limite di stack.


E un altro, più malvagio :

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

Crea una funzione che apre una finestra, quindi crea una funzione all'interno di quella finestra che è copia della funzione e quindi la esegue.

Dichiarazione di non responsabilità: se si consente l'apertura dei popup, l'unico modo per terminare sarà riavviare il computer


5
Questo è piuttosto male di sicuro;)
CailinP

28
@CailinP Abbastanza eval di sicuro.
Seequ,

Penso che ti manchi un falla fine della tua seconda funzione. Dovrebbe essere }f()alla fine.
Chirag Bhatia - chirag64,

2
Purtroppo l'ho notato perché l'ho provato. : P
Chirag Bhatia - chirag64,

7
-1 - questa è solo una ricorsione.
user253751

39

assembly x86 / DOS

    org 100h

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

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

Ho detto nessuna ricorsione della coda invertita ? Ho fatto? madame mim purple dragons

Come funziona

L' retistruzione, usata per tornare da una funzione, in realtà estrae l'indirizzo di ritorno dallo stack (che normalmente viene messo lì dal corrispondente call) e salta ad esso. Qui ad ogni iterazione abbiamo pushl'indirizzo entrypoint nello stack prima di tornare, generando così un ciclo infinito.


Mi chiedevo se questo fosse possibile in assemblea.
Ian D. Scott,


1
Stavo per chiamare codegolf.stackexchange.com/a/34295/11259 come un duplicato di questo, ma vedo che in realtà è la risposta precedente
Digital Trauma

@DigitalTrauma: sì, l'ho notato dopo aver pubblicato la mia voce, ma ho attaccato alla foto di Madame Mim. :-) Fortunatamente ci sono alcune differenze (la sua è un po 'più offuscata e funziona su Linux a 32 bit, la mia è giocata direttamente su DOS e non ha nessun altro salto), se nessuno ha obiezioni lascerei comunque questo qui.
Matteo Italia,

@MatteoItalia Non offuscato, solo schifoso;) (anche se "aggiungi eax, 4" mi ha confuso, non sono riuscito a trovare la tabella delle dimensioni dell'opcode quindi ho indovinato le dimensioni). L'ho realizzato nel compilatore online mentre il mio progetto di lavoro era in fase di compilazione, quindi sembra orribile. Ottima idea di usare "start:".
PTwr,

37

Giava

Direttamente da XKCD

Bonding

È un gioco senza fine di cattura tra un genitore e un figlio!

Il target di CHILDè impostato su PARENTe il target di PARENTè il CHILD. Quando PARENTchiama AIM, genera l'istanza della BALLclasse e viene catturata dall'istruzione catch. L'istruzione catch chiama quindi PARENT.TARGET.AIMdove è l'obiettivoCHILD . L' CHILDistanza fa lo stesso e "getta la palla indietro" al genitore.


3
Mi piacciono quei fumetti!
Derek 功夫 會 功夫 l'

1
Sarebbe meglio se la palla fosse effettivamente lanciata tra genitore e figlio. Così com'è, la palla viene sempre lanciata e presa dalla stessa "persona".
Ajedi32,

@ Ajedi32 In realtà sembrerebbe che lo butti avanti e indietro; Genitori TARGET è il bambino e l'obiettivo del bambino è il genitore. L'obbiettivo è chiamato sul genitore, che lancia la palla e fa mirare il bambino e lancia la palla, spunto
Alex Coleman,

12
@AlexColeman Questo codice è analogo al genitore che lancia la palla in aria, la cattura, quindi la passa al bambino che fa lo stesso prima di restituire la palla al genitore, e così via.
Ajedi32,

11
Il comando TARGET.AIM(B);nel metodo AIMè una chiamata ricorsiva. Quindi questo viola la regola "le funzioni non possono chiamarsi".
Theodore Norvell,

31

Bash, 3 personaggi

yes

yes restituirà ripetutamente 'y' alla console

Modifica: tutti sono incoraggiati a modificare questa riga:

yes something | xargs someaction

(grazie a Olivier Dulac)


1
Perché questo continuerà a funzionare? non lo metto in discussione, sto solo cercando di capire perché.
Teun Pronk,

2
@TeunPronk yesè un comando bash che stampa la parola yes fino a quando non viene ucciso o il flusso non viene chiuso. Se sta scrivendo sullo schermo non si fermerà mai fino a quando non lo ucciderai. È una specie di imbroglio, poiché è un comando che sostanzialmente consiste in un loop su printf.
scragar

1
Più divertente sarebbe usare yesper mantenere qualche altro ciclo in corso.
sinceramente il

3
@izkata: ma poi puoi yes something | xargs someaction:: nessuna ricorsione (puoi anche aggiungere -n 1 a xargs per avere solo 1 "qualcosa" per riga, ecc.). L'uso di xargs apre la strada a comportamenti più complessi (anche quelli che non hanno nulla a che fare con l'output yes)
Olivier Dulac

4
@scragar avresti dovuto rispondere yes.
daviewales,

28

C, 35 caratteri

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

Il programma si esegue da solo. Non sono sicuro se questo è considerato ricorsione o no.


4
@mniip Tail ricorsion, quindi, se applicato a livello di processo
Izkata

3
La ricorsione della coda di @Izkata è ancora ricorsiva, ma questa non è ricorsione. La ricorsione implica una funzione (o processo in questo caso) 'in attesa' di terminare un'altra iterazione di se stesso. In questo caso, execfa sì che il nuovo processo sostituisca quello originale, quindi non c'è stack di chiamate che alla fine restituirà o overflow.
millinon

4
@millinon In una lingua che supporta l'ottimizzazione, la ricorsione della coda sostituisce la chiamata precedente nello stack di chiamate, in modo simile a come execsostituisce il processo precedente. Nemmeno traboccerà.
Izkata,

1
@millinon solo per essere super pedanti e trascinare più a lungo questa discussione, nel linguaggio di programmazione Scheme, questa ottimizzazione è una caratteristica del linguaggio. È nelle specifiche che se si effettua una chiamata ricorsiva di coda, l'interprete / compilatore deve riutilizzare l'ultimo frame dello stack. Questo perché Scheme non ha strutture di loop integrate, quindi l'unico modo per implementare un loop in Scheme è fare la ricorsione della coda, e farebbe schifo se avessi troppi overflow dello stack cercando di eseguire il loop di troppe volte :)
Ord

2
Se vuoi pedanteria, Scheme non ha "ottimizzazione delle chiamate di coda", ha "chiamate di coda adeguate". Non è un'ottimizzazione, è un requisito di base dello standard linguistico e non è possibile non fornirlo, quindi "ottimizzazione" (o il suggerimento che abbia qualcosa a che fare con la ricorsione) è molto un termine scoraggiato.
Leushenko,

28

C (con builtin GCC - sembra funzionare anche con clang)

  • Nessun loop esplicito
  • Nessuna gotos esplicita
  • Nessuna ricorsione
  • Solo un buon pasticcio vecchio stile con lo stack (ragazzi, non provatelo a casa senza supervisione):
#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);
    }
}

Spiegazione:

  • main()prime chiamate frameloop(NULL). In questo caso usa l' __builtin_return_address()integrato per ottenere l'indirizzo di ritorno (in main()) a cui frameloop()tornerà. Restituiamo questo indirizzo.
  • printf() per mostrare che siamo in loop
  • ora chiamiamo frameloop() con l'indirizzo di ritorno per la chiamata precedente. Esaminiamo lo stack per l'indirizzo di ritorno corrente e, quando lo troviamo, sostituiamo l'indirizzo di ritorno precedente.
  • Ritorniamo quindi dalla seconda frameloop()chiamata. Ma poiché l'indirizzo di ritorno è stato violato sopra, finiamo per tornare al punto in main()cui dovrebbe tornare la prima chiamata. Quindi finiamo in un ciclo.

La ricerca dell'indirizzo di ritorno nello stack sarebbe ovviamente più pulita come un ciclo, ma ho srotolato alcune iterazioni per il gusto di non eseguire alcun ciclo.

Produzione:

$ 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
$ 

2
simpatico! Mi chiedo perché quelle funzioni non facciano parte delle specifiche C? ;-D
Brian Minton,

4
@BrianMinton In realtà una cosa simile dovrebbe essere realizzabile con setjmp()/ longjmp(). Questi non sono nello standard c, ma sono nella libreria standard . Oggi mi è sembrato di mungere manualmente lo stack ;-)
Digital Trauma,

@BrianMinton La mia ipotesi è perché è nelle specifiche della CPU, il che rende dipendente dalla piattaforma (hardware). Ed è piuttosto pericoloso da usare quando lo stackframe viene generato automaticamente, non sarei sorpreso se AV piangesse per tale codice. Controlla questo o questo per le versioni x86 asm.
PTwr

27

Haskell

Il codice seguente non contiene alcuna funzione ricorsiva (anche indirettamente), nessuna primitiva ciclica e non chiama alcuna funzione ricorsiva incorporata (utilizza solo IOl'output e il binding), ma ripete in modo identico una determinata azione:

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" >>)

La funzione extractnon chiama nulla, ycchiama solo extracte mainchiama solo yce putStrLne >>, che non sono ricorsivi.

Spiegazione: Il trucco sta nel tipo di dati ricorsivo Strange. È un tipo di dati ricorsivo che si consuma e che, come mostrato nell'esempio, consente una ripetizione arbitraria. In primo luogo, possiamo costruire extract x, che essenzialmente esprime l'auto-applicazione x xnel calcolo lambda non tipizzato. E ciò consente di costruire il combinatore Y definito come λf.(λx.f(xx))(λx.f(xx)).


Aggiornamento: come suggerito, sto pubblicando una variante più vicina alla definizione di Y nel calcolo lambda non tipizzato:

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" >>)

3
Strutture di dati ricorsive invece di funzioni ricorsive ... bello.
Approaching

6
questo è vicino al mio cuore essendo qualcuno che è interessato alla programmazione funzionale totale. Hai appena mostrato come creare il combinatore a Y con un tipo di dati negativamente ricorrente. Questo è il motivo per cui le lingue totali richiedono tipi ricorrenti si verificano a destra della freccia e perché gli alberi di rose sono vietati. Ben fatto! Ho creato un account qui solo per votare questo!
Jake,

È possibile rimuovere l' letassociazione e definire yc f = extract $ C $ f.extract, poiché l' letassociazione probabilmente è una caratteristica del linguaggio che consente la ricorsione (classica let x = x in x). Questo riduce anche alcuni caratteri :)
Earth Engine

o ancheyc = extract . C . (.extract)
Earth Engine,

@EarthEngine Vero, volevo solo mantenere la struttura più vicina alla definizione originale di Y.
Petr Pudlák,

26

C ++

Di seguito viene visualizzato un conto alla rovescia da 10 a "Blast off!" utilizzando la metaprogrammazione del modello.

#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;
}

Potrebbe sembrare un classico esempio di ricorsione, ma in realtà non lo è, almeno tecnicamente, a seconda della tua definizione. Il compilatore genererà dieci diverse funzioni. countdown<10>stampa "T meno 10" e quindi chiama countdown<9>, e così via fino a countdown<0>, che stampa "Blast off!" e poi ritorna. La ricorsione si verifica quando si compila il codice, ma l'eseguibile non contiene alcuna struttura ciclica.

In C ++ 11 si possono ottenere effetti simili usando la constexprparola chiave, come questa funzione fattoriale. (Non è possibile implementare l'esempio del conto alla rovescia in questo modo, poiché le constexprfunzioni non possono avere effetti collaterali, ma penso che potrebbe essere possibile nel prossimo C ++ 14.)

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

Anche in questo caso Sembra veramente ricorsione, ma il compilatore si espanderà fuori factorial(10)in 10*9*8*7*6*5*4*3*2*1, e poi probabilmente sostituirlo con un valore costante di 3628800, quindi l'eseguibile non conterrà alcun loop o il codice ricorsivo.


4
Il secondo di questi è davvero pura e semplice ricorsione, non metaprogrammazione. Innanzitutto perché il compilatore (nel caso generale) emetterà un corpo di funzione regolare da usare con argomenti non costanti; e in secondo luogo perché quando esegue un'operazione in fase di compilazione, non esegue nessuna delle operazioni di "espansione" in stile modello, esegue una valutazione sul posto standard - la stessa di quella di runtime - per produrre 3628800direttamente senza un forma intermedia.
Leushenko,

@Leushenko sì, lo so. Ma ancora una volta l'esempio di esempio del modello fa la stessa cosa - usa una funzione ricorsiva in un linguaggio completo di Turing al momento della compilazione - l'unica differenza è che quella di uno dei due usa un linguaggio che assomiglia molto di più al C ++. Come per tutte le risposte, questa si piega alle regole e io sono solo sincero. constexprè stato appositamente progettato per rendere obsoleti (alcuni aspetti) della metaprogrammazione dei modelli, quindi sembra sicuramente degno di nota in un post sull'argomento.
Nathaniel,

1
+1: &countdown<N-1> != &countdown<N>.
Thomas Eding,

21

Giava

Giochiamo con il caricatore di classi Java e impostalo come suo genitore:

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());

    }
}

Questo loop è in realtà così forte che dovrai usare a kill -9per fermarlo :-)

Utilizza il 100,1% della CPU del mio Mac.

100,1% of CPU

Puoi provare a spostare la System.outfine della funzione principale per sperimentare un comportamento divertente alternativo.


lol. ottenere java bloccato in sé :)
masterX244

Adoro l'hack di caricamento ricorsivo JVM.
Isiah Meadows,

20

CSharp

Ancora uno e altrettanto malvagio ::

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>();
    }
}

Questa non è ricorsione ... questa è la reificazione dei modelli di codice. Mentre sembra che stiamo chiamando lo stesso metodo, il runtime crea costantemente nuovi metodi. Usiamo il parametro type di int, poiché questo lo costringe effettivamente a creare un nuovo tipo intero e ogni istanza del metodo deve modificare un nuovo metodo. Non può codificare la condivisione qui. Alla fine, uccidiamo lo stack di chiamate mentre attende all'infinito il ritorno di int che abbiamo promesso ma mai consegnato. Allo stesso modo, continuiamo a scrivere il tipo che abbiamo creato per renderlo interessante. Fondamentalmente ogni C che chiamiamo è un metodo completamente nuovo che ha solo lo stesso corpo. Ciò non è realmente possibile in un linguaggio come C ++ o D che esegue i propri modelli in fase di compilazione. Dal momento che C # JIT è super pigro, crea questa roba solo nell'ultimo momento possibile. Così,


14

Redcode 94 (Core War)

MOV 0, 1

Copia l'istruzione all'indirizzo zero per indirizzarne uno. Poiché in Core War tutti gli indirizzi sono relativi all'attuale indirizzo del PC e hanno le dimensioni del core, questo è un ciclo infinito in un'istruzione non salta.

Questo programma (guerriero) si chiama " Imp " ed è stato pubblicato per la prima volta da AK Dewdney.


3
Gli Imp marciano, preparano le tue porte, preparali o verrai schiacciato.
Seequ,

Pronto il tuo SPL 0, 0; MOV 1, -2davvero.
wberry,

Bello, speravo che questo non fosse stato ancora pubblicato. +1
mbomb007

14

Dardo

Immagino che questo sarebbe il modo classico di fare la ricorsione senza alcuna reale funzione ricorsiva. Nessuna funzione di seguito si riferisce a se stessa per nome, direttamente o indirettamente.

(Provalo su 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;
  });
}

6
Il combinatore Y?
aditsu,

5
Tecnicamente, immagino sia il combinatore Z perché è per un linguaggio rigoroso. Il combinatore Y richiede un linguaggio pigro per evitare il dispiegarsi infinito. L'unica differenza è che quest'ultima è espansa in eta.
lrn,

12

JS

Non molto originale ma piccolo. 20 caratteri.

setInterval(alert,1)

Puoi effettivamente rimuovere ,1e funzionerà ancora,
Derek 朕 會 功夫 l'

@Derek 朕 會 功夫 se lo faccio, ricevo solo un avviso su Firefox
xem

1
In Chrome funziona senza l'ultimo parametro. Il codice deve essere considerato valido se funziona in almeno un ambiente.
Derek 朕 會 功夫 l'

3
@Derek 朕 會 功夫setIntervalnon è un'affermazione, però; è solo una funzione. È usato all'interno di una dichiarazione di espressione e se non possiamo usare le espressioni di espressione, allora non lo so nemmeno più.
Appassionato

1
@Cory - Beh, immagino che sia valido allora!
Derek 功夫 會 功夫 il

12

Segnali in C

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

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

Il comportamento di questo programma è ovviamente molto indefinito, ma oggi sul mio computer continua a stampare "Ciao, mondo!".


11

Emacs Lisp

Questo è un ottimo momento per mostrare il potente design di Lisp in cui "il codice è dato e dati è codice". Certo, questi esempi sono molto inefficienti e questo non dovrebbe mai essere usato in un contesto reale.

Le macro generano il codice che è una versione non srotolata del ciclo presunto e quel codice generato è ciò che viene valutato in fase di esecuzione.

ripeti: consente di ripetere N volte

(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 ripetizione:

;; 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-da-con-index:

Questa macro è simile repeat-itma in realtà funziona proprio come la macro di loop comune do-times, consente di specificare un simbolo che verrà associato all'indice di loop. Utilizza un simbolo del tempo di espansione per garantire che la variabile indice sia impostata correttamente all'inizio di ciascun ciclo, indipendentemente dal fatto che si modifichi o meno il suo valore durante il corpo del ciclo.

(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 di ripetizione con indice:

Questo test mostra che:

  1. Il corpo valuta N volte

  2. la variabile indice è sempre impostata correttamente all'inizio di ogni iterazione

  3. cambiando il valore di un simbolo chiamato "fallback" non si scherza con l'indice

;; 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)))

11

Calcolo lambda non tipizzato

λf.(λx.f (x x)) (λx.f (x x))

3
Non sono sicuro se questo conta come ricorsione o no, quale sia la base teorica fondamentale per esso ... +1 comunque.
soffice

@fluffy Non è ricorsivo in sé, nessuna delle funzioni si chiama da sola (in particolare perché le funzioni non hanno un nome).
orgoglioso haskeller l'

IMHO, il calcolo lambda è un modello di calcolo e non è un linguaggio di programmazione (cioè senza un modello di macchina concreto, non possiamo considerare il calcolo lambda come un PL).
Ta Thanh Dinh,

Puoi assolutamente costruire una macchina che interpreta il calcolo lambda. E la sintassi può essere utilizzata come linguaggio di programmazione. Vedi per esempio github.com/MaiaVictor/caramel
Arthur B

10

Haskell, 24 personaggi

sequence_ (repeat (print "abc"))

o in forma condensata, con 24 caratteri

sequence_$repeat$print"" 

(Anche se il testo è cambiato, questo continuerà ad essere ripetuto - questo stamperà due virgolette e una nuova riga all'infinito)

spiegazione: print "abc" è fondamentalmente un'azione di I / O che stampa semplicemente "abc".
repeat è una funzione che accetta un valore x e restituisce un elenco infinito composto solo da x.
sequenza_ è una funzione che accetta un elenco di azioni I / o e restituisce un'azione I / o che esegue tutte le azioni in sequenza.

quindi, in sostanza, questo programma crea un elenco infinito di comandi "abc" di stampa e li esegue ripetutamente. senza loop o ricorsione.


4
In pratica avrei pubblicato la stessa risposta in Clojure, ma ho pensato che repeatsarebbe stato a programming language statement which allows code to be repeatedly executed.
Seequ,

3
fix(print"">>), ciò implica anche nessuna funzione di ripetizione denominata in modo esplicito.
mniip,

1
@TheRare Non so come sia in chiusura, ma nella ripetizione di Haskell non è "un'istruzione del linguaggio di programmazione che consente l'esecuzione ripetuta del codice" - è una funzione che genera infiniti elenchi. è un ciclo proprio come "int [] arr = {x, x, x};" è un ciclo.
orgoglioso haskeller il

1
sì, ma qualcosa deve essere implementato usando la ricorsione, perché senza di essa è sostanzialmente impossibile
orgoglioso haskeller il

3
In realtà, ogni funzione presente in questo codice è definita usando la ricorsione - anche stampa
orgoglioso haskeller il

10

ASM (x86 + I / O per Linux)

Non importa quanto i tuoi linguaggi di alto livello saranno difficili, sarà comunque solo una manipolazione nascosta del puntatore delle istruzioni. Alla fine sarà una sorta di "goto" (jmp), a meno che tu non sia abbastanza annoiato da srotolare il loop in runtime.

Puoi testare il codice su Ideone

Puoi anche dare un'occhiata alla versione più raffinata di questa idea nel codice DOS di Matteo Italia .

Inizia con una stringa di 0..9 e lo sostituisce con A..J, non viene utilizzato alcun salto diretto (quindi diciamo che non è accaduto alcun "goto"), nessuna ricorrenza.

Il codice probabilmente potrebbe essere più piccolo con qualche abuso nel calcolo dell'indirizzo, ma lavorare sul compilatore online è fastidioso, quindi lo lascerò così com'è.

Parte principale:

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

Codice intero

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

Stavo per chiamarlo un duplicato di codegolf.stackexchange.com/a/34298/11259 , ma vedo che questa è la risposta precedente. +1
Trauma digitale,

@DigitalTrauma oh, vedo qualcuno fare una versione raffinata della mia idea - vecchio trucco, ma nell'era del codice gestito le persone tendono a dimenticare come funzionano veramente le cose. (Non mi piace giocare a golf, troppo spesso si riduce a "guarda mamma! Posso far accadere le cose premendo un tasto!")
PTwr

9

C Preprocessore

Una piccola "tecnica" che mi è venuta in mente durante una sfida di offuscamento. Non c'è ricorsione di funzione, ma c'è ... ricorsione di file?

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

Ho scritto / testato usando gcc. Ovviamente il compilatore deve supportare la __INCLUDE_LEVEL__macro (o in alternativa la __COUNTER__macro con alcune modifiche) per poter compilare questo. Dovrebbe essere abbastanza ovvio come funziona, ma per divertimento, esegui il preprocessore senza compilare il codice (usa il -Eflag con gcc).


8

PHP

Eccone uno con PHP. Cicli includendo lo stesso file fino a quando il contatore raggiunge $ 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
?>

Lo stesso di un for-loop:

<?php
for ($i = 0; $i < 10; $i++) {
    echo "Iteration $i <br>\n";
}
die('done');
?>

Accidenti, anche questo conta come ricorsione, vero?
Pichan,

Non pensate che lo sia - la somiglianza viene in mente nell'esempio di @ Nathaniel: il preprocessore includerà questi file che verranno poi valutati contemporaneamente.
Eithed

@Pichan Direi che si sta svolgendo più di un ciclo, poiché finisci con copie di codice in memoria.
PTwr

Ho appena visto la domanda oggi e ho trovato un codice quasi identico. Troppo tardi per me!
TecBrat,

Viene header("Location: .?x=".$_GET['x']+1);conteggiato come ricorsione?
Charlie,

8

Pitone

Il seguente codice non contiene alcuna funzione ricorsiva (direttamente o indirettamente), nessuna primitiva ciclica e non chiama alcuna funzione incorporata (tranne 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)

Stampe "Ciao mondo!" un dato numero di volte.

Spiegazione: funzione zimplementa il combinatore a punto fisso Z rigoroso , che (sebbene non definito in modo ricorsivo) consente di esprimere qualsiasi algoritmo ricorsivo.


Definirei gmolto indirettamente ricorsivo.
Seequ,

@TheRare Why? Qual è il tuo argomento? Cosa gchiama di gnuovo quella chiamata ? Ovviamente il trucco è l'auto-applicazione g(g), ma non c'è ricorsione. Chiameresti gindirettamente ricorsivo se non lo avessi visto g(g)? Questo è il modo standard come farlo in lingue che non consentono definizioni ricorsive, come il calcolo lambda.
Petr Pudlák,

Dai gcome argomento xe poi chiami x(x).
Seequ,

2
@TheRare Una funzione (o un insieme di funzioni) non è ricorsiva o non ricorsiva dal modo in cui viene utilizzata, questo è determinato solo dalla sua definizione.
Petr Pudlák,

1
tutte le risposte imbrogliano in un modo o nell'altro: c'è sempre una ricorsione o un ciclo da qualche parte , se non nella risposta, quindi nel codice invoca la risposta. Mi piace il modo in cui questo bara.
Wayne Conrad,

8

codice macchina z80

In un ambiente in cui è possibile eseguire qualsiasi indirizzo e mappare la ROM ovunque, mappare 64kb di ROM riempiti di zero per l'intero spazio degli indirizzi.

Cosa fa: niente. Ripetutamente.

Come funziona: il processore inizierà l'esecuzione, il byte 00è nopun'istruzione, quindi continuerà a funzionare, raggiungerà l'indirizzo $ffff, andrà a capo $0000e continuerà l'esecuzionenop s fino a quando non viene ripristinato.

Per renderlo leggermente più interessante, riempire la memoria con qualche altro valore (fare attenzione a evitare le istruzioni del flusso di controllo).


Potresti riempire la memoria di zero e posizionare un vero programma lì da qualche parte.
Seequ,

Quindi potresti inserire un programma a 64k, senza diramazioni di sorta, e verrà eseguito ripetutamente?
Bill Woodger,

@BillWoodger potresti, soprattutto se non hai interruzioni sulla piattaforma (o nessuna abilitata)
harold,

Un po 'di divertimento :-)
Bill Woodger,

8

Perl-regex

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

dimostrazione

o provalo come:

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

Il (?!)mai abbinare. Quindi il motore regex cerca di far corrispondere ogni posizione di larghezza zero nella stringa corrispondente.

Lo (q x x x 10)è la stessa (" " x 10)- ripetere le spacedieci volte.

Modifica: ha cambiato i "caratteri" in posizioni di larghezza zero per essere più precisi per una migliore comprensibilità. Vedi le risposte a questa domanda StackOverflow .


6

T-SQL -12

print 1
GO 9

In realtà più di una stranezza di SQL Server Management Studio. GO è un separatore di script e non fa parte del linguaggio T-SQL. Se si specifica GO seguito da un numero, il blocco verrà eseguito più volte.


1
Uso T-SQL quasi ogni giorno e non avevo idea che tu potessi farlo con GO. +1
CailinP

Tecnicamente, questo non è T-SQL. GOè in realtà una direttiva SSMS, motivo per cui non è possibile inserirlo in oggetti con script T-SQL, ad esempio una procedura memorizzata.
RBarryYoung,

Sì, l'ho aggiunto nel mio commento sullo spoiler. Immagino che usare sqlcmd sarebbe troppo ingannevole.
Michael B,

6

C #

Stampa tutti i numeri interi da uint.MaxValue a 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--); }
   }

1
Non so davvero se questo conta. Stai chiamando esplicitamente i tempi di WriteLine01 Int.MaxValue. È appena esploso dietro un'enorme quantità di callstack.
Michael B,

Come non conta? Non c'è loop e nessuna ricorsione.
LVBen,

1
Inoltre, lo stack di chiamate non è da nessuna parte vicino massiccio a meno che forse non si consideri un alto 32 chiamate di essere massiccio.
LVBen,

1
Perché solo 32 volte anziché 4294967296 volte?
LVBen,

4
@ ja72 Se sto mai lavorando a un progetto open source in cui non riesco a usare loop o ricorsioni, allora contribuirò totalmente con questo codice!
LVBen,

6

JS (nel browser)

Cosa ne pensi di questo?

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

Stampa l'ora corrente e ricarica la pagina.


Oh spara. Ho appena pubblicato una risposta con lo stesso concetto di base. Stavo scansionando la pagina per "JavaScript" o qualsiasi cosa mostrasse tag HTML. Suppongo che potrei lasciare la mia risposta, solo perché gestisce il caso angolare in cui la posizione contiene un "#". Comunque, +1.
Appassionato

In Firefox 30:[Exception... "The operation is insecure." code: "18" nsresult: "0x80530012 (SecurityError)" location: "<unknown>"]
Alex Reynolds,

@AlexReynolds Huh, strano. Il mio funziona perfettamente su FF 30.
Pichan,

Ho solo copiato e incollato il tuo codice così come è stato scritto. Non funziona Forse hai alcune preferenze di sicurezza speciali abilitate per farlo funzionare?
Alex Reynolds,

@AlexReynolds No, non ha mai modificato alcuna impostazione di sicurezza. E funziona anche su Chrome.
Pichan,
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.