Boucle sans 'bouclage' [fermé]


85

Une question similaire à celle-ci a été posée il y a quelques années , mais celle-ci est encore plus délicate.

Le défi est simple. Ecrire un programme (en langue de votre choix) qui exécute de façon répétée le code sans utiliser de structures de répétition telles que while, for, do while, foreachou goto( Donc , pour tout ce que vous tatillons, vous ne pouvez pas utiliser une boucle ). Cependant, la récursion n’est pas autorisée, dans la fonction qui s’appelle sens (voir la définition ci-dessous) . Cela rendrait ce défi beaucoup trop facile.

Il n'y a aucune restriction sur ce qui doit être exécuté dans la boucle, mais postez une explication avec votre réponse afin que les autres puissent comprendre exactement ce qui est mis en œuvre.

Pour ceux qui peuvent être accrochés sur les définitions, la définition d'une boucle pour cette question est la suivante:

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

Et la définition de la récursivité pour cette question sera votre définition de fonction récursive standard:

A function that calls itself.

Winner sera la réponse qui aura le plus de votes positifs le 16 juillet à 10 heures, heure de l’Est. Bonne chance!

MISE À JOUR:

Pour calmer la confusion qui est toujours exprimée, ceci peut aider:

Règles comme indiqué ci-dessus:

  • Ne pas utiliser de boucles ou goto
  • Les fonctions ne peuvent pas s'appeler
  • Faites ce que vous voulez dans la "boucle"

Si vous voulez implémenter quelque chose et que les règles ne l'interdisent pas explicitement, allez-y et faites-le. Beaucoup de réponses ont déjà plié les règles.


27
Pour ceux qui veulent un tour facile, je ne peux pas être dérangé pour le poster: P Il suffit de faire 2 fonctions, des function Aappels function Bet des function Bappels function Apendant qu'une des fonctions exécute quelque chose. Puisque la fonction ne s'appelle pas elle-même, elle devrait être valide sur la base des critères ^. ^
Teun Pronk

2
"Changé en concours de popularité axé sur la créativité" Changer la question, c'est tricher!
CousinCocaine

4
La définition de "récursion" n'est pas très utile. Il serait préférable de ne pas autoriser les fonctions récursives , qui se réfèrent à elles-mêmes, directement ou indirectement.
lrn

3
Ce qui n'est pas clair, ce sont les "définitions" du constructeur de boucle et de la récursivité. Ni sont très précis. Exemple: rep(f){f();f();}- il s'agit d'une instruction (une déclaration de fonction est une instruction dans certaines langues) qui permet l'exécution de code à plusieurs reprises. Est-ce interdit? Vous demandez du code pour implémenter une boucle. Si ce code est syntaxiquement une instruction, vous venez de le refuser. Un autre exemple: f(b) { b(); g(b); }; g(b) { f(b); }. Je dirais que fc'est une fonction récursive (en étant mutuellement récursif avec g). Est-ce interdit?
lrn

3
@CailinP, ce que je suis « accroché sur » est que les questions sur le site devrait être sur le sujet pour le site: cela signifie avoir une spécification claire et objective, cette question qui ne fonctionne pas.
Peter Taylor

Réponses:


258

Rubis

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

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

ahem

Démo

Il s'éclaircit la gorge, imprime "Banana" 3070 fois et ajoute "Orange, tu es content de ne pas avoir dit banane?".

Ceci utilise la fonctionnalité ridicule de définition de méthode juste à temps de Ruby pour définir chaque méthode située alphabétiquement entre les mots "ahem" et "aussi" ("ahem", "ahen", "aheo", "ahep", "aheq", "aher", "ahes", "ahet", "aheu", "ahev" ...) pour imprimer d'abord Banana puis appeler le suivant dans la liste.


4
Il finit par frapper "aussi", ce qui est défini, et donc ne manque pas.
Histocrat

77
C'est hystérique.
Michael B

4
@barrycarter: En Ruby, String#nextappelé dans les method_missingfonctions, il s’agit plus ou moins d’ajouter 1 à un nombre, sauf que cela fonctionne avec tous les caractères alphanumériques (et les non-alnums s’ils sont les seuls caractères de la chaîne). Voir ruby-doc.org/core-2.1.2/String.html#method-i-next
3Doubloons le

2
@ NickT est utilisable dans des classes telles que les générateurs XML où vous pouvez utiliser n'importe quelle balise créée uniquement par b.my_tag. Il est également utilisé dans les modèles ActiveRecord ou OpenStruct. Dans 'Wat talk', il dit que le global method_missingest mauvais, mais que la portée est géniale.
Hauleth

2
Je me souviens d'un vieux commentaire sur un autre programme de rubis: "Je l'aime parce qu'il contient de la méthamphétamine"
vidya sagar

82

Python - 16

ou toute autre langue avec eval.

exec"print 1;"*9

Pouvez-vous décrire ce que votre programme fait?
CailinP

10
Il faut une chaîne ( "print 1;"), la duplique 9 fois ( *9), puis exécute la chaîne résultante ( exec). Répéter un morceau de code sans faire de boucle.
Scragar

12
Yay pour la multiplication de chaîne!
Thane Brimhall

2
Fonctionne également en Ruby si vous changez le execpour eval ou le printà echo.
Ajedi32

80

CSharp

J'ai élargi le code de manière plus lisible car il ne s'agit plus de code de golf et j'ai ajouté un compteur d'incrément pour que les gens puissent réellement voir que ce programme fait quelque chose.

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

(Ne fais jamais ça s'il te plait).

Au démarrage, nous créons une nouvelle instance de la Pclasse qui, lorsque le programme tente de quitter, appelle le GC, qui appelle le finaliseur, qui crée une nouvelle instance de la Pclasse, qui, lorsqu'elle tente de nettoyer, en crée une nouvelle, Pqui appelle le finaliseur. .

Le programme meurt finalement.

Edit: Inexplicablement, cela ne dure que 45 000 fois environ avant de mourir. Je ne sais pas trop comment le GC a découvert ma boucle infinie délicate, mais c'est ce qui s'est passé. En bref, il semble qu'il ne l'ait pas compris et que le fil ait été tué après environ 2 secondes d'exécution: https://stackoverflow.com/questions/24662454/how-does-a-garbage-collector-avoid-an -infinite-loop-here

Edit2: Si vous pensez que cela ressemble un peu trop à la récursivité, considérez mon autre solution: https://codegolf.stackexchange.com/a/33268/23300

Il utilise la réification des méthodes génériques afin qu’au moment de l’exécution, il génère constamment de nouvelles méthodes et chaque méthode à terme appelle une méthode nouvellement créée. J'évite également d'utiliser referencedes paramètres de type, car normalement, le moteur d'exécution peut partager le code pour ces méthodes. Avec un valueparamètre de type, le moteur d'exécution est obligé de créer une nouvelle méthode.


20
Je ne savais même pas que C # avait des destructeurs. +1 pour m'apprendre.
seequ

4
@TheRare, c'est vrai, mais ils n'ont pas un caractère déterministe et ne peuvent jamais être appelés pendant l'exécution d'un programme. Ils sont implémentés en tant que substitution de la méthode virtuelle Finalize, ils sont donc parfois appelés finalizer. En vrai C #, vous devriez utiliser le IDisposablemotif.
Michael B

Il semble qu'il y ait un délai d'attente qui se produit à un moment donné. Je ne pense pas que le GC arrête votre cycle, mais que le système d’exploitation décide que votre programme prend trop de temps à s’achever.
LVBen

Je pense que c'est vraiment le temps d'exécution qui décide de tuer le programme, pas nécessairement le système d'exploitation. Le thread du ramasse-miettes appelé à la fin du programme se voit attribuer une limite de temps fixe d'environ 2 secondes avant d'être tué.
Michael B

Avec quelques modifications mineures (ne pas laisser le programme se terminer, relâcher le 1er objet P sur le GC et appeler à plusieurs reprises GC.Collect), je peux le faire fonctionner indéfiniment.
LVBen

53

Befunge

.

Les bons vieux Befunge affichent 0 (à partir d’une pile vide) assez longtemps, à mesure que les lignes s’enroulent


1
Ha! J'aime des trucs comme ça
CailinP

47

JS

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

Fonction fun!

Une fonction qui crée une autre fonction avec le même corps que lui, puis l'exécute.

Il affichera hi à la fin lorsque la limite de pile est atteinte et que tout s'effondre.

Clause de non-responsabilité: vous ne pourrez rien faire dans votre navigateur si la limite de pile est atteinte.


Et un autre, plus diabolique :

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

Il crée une fonction qui ouvre une fenêtre, puis crée une fonction dans cette fenêtre qui est une copie de la fonction, puis l'exécute.

Clause de non-responsabilité: si vous autorisez l'ouverture de fenêtres contextuelles, le seul moyen de terminer ce processus consiste à redémarrer votre ordinateur.


5
C'est pas mal méchant à coup sûr;)
CailinP

28
@CailinP Pretty eval à coup sûr.
seequ

Je pense que vous manquez un fà la fin de votre deuxième fonction. Ce devrait être }f()à la fin.
Chirag Bhatia - chirag64

2
Malheureusement, je l'ai remarqué parce que je l'ai essayé. : P
Chirag Bhatia - chirag64

7
-1 - c'est juste la récursivité.
user253751

39

Assemblage x86 / DOS

    org 100h

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

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

Ai-je dit non récursion de la queue inversée ? Ai-je? madame mim dragons violets

Comment ça fonctionne

L’ retinstruction, utilisée pour retourner d’une fonction, extrait en fait l’adresse de retour de la pile (qui y est normalement placée par le correspondant call) et y saute. Ici, à chaque itération, nous pushentrons l'adresse du point d'entrée sur la pile avant de retourner, générant ainsi une boucle infinie.


Je me demandais si cela était possible en assemblée.
Ian D. Scott


1
J'allais appeler codegolf.stackexchange.com/a/34295/11259 comme un dup de celui-ci, mais je vois que c'est en fait la réponse précédente
Digital Trauma

@ DigitalTrauma: Oui, j'ai remarqué après avoir posté mon article, mais je me suis attaché à la photo de Madame Mim. :-) Heureusement, il y a quelques différences (il est un peu plus obscur et fonctionne sous Linux 32 bits, le mien est joué directement sous DOS et n'a pas d'autre saut), si personne ne s'objecte, je le laisserais de toute façon.
Matteo Italia

@ MatteoItalia Pas obscurci, juste de la merde;) (bien que "add eax, 4" m'a confondu aussi, je ne pouvais pas trouver la table de taille d'opcode alors j'ai juste deviné la taille sauvage). Je l'ai fait dans un compilateur en ligne pendant que mon projet de travail était en train de compiler, donc ça a l'air horriblement. Excellente idée d'utiliser "start:".
PTwr

37

Java

Directement de XKCD

Collage

C'est un jeu de pêche sans fin entre un parent et un enfant!

La cible de CHILDest définie sur PARENTet la cible de PARENTest le CHILD. Lorsque les PARENTappels AIM, il lève l'instance de la BALLclasse et il est attrapé par l'instruction catch. La déclaration catch appelle alors PARENT.TARGET.AIMoù la cible est le CHILD. L' CHILDinstance fait la même chose et "renvoie la balle" au parent.


3
J'aime ces bandes dessinées!
Derek mardi

1
Ce serait mieux si la balle était effectivement lancée entre le parent et l'enfant. En l'état, la balle est toujours lancée et attrapée par la même "personne".
Ajedi32

@ Ajedi32 Il semblerait en fait qu'il le jette dans les deux sens; Parents Target est l'enfant et la cible de l'enfant est le parent. Le but est appelé le parent qui passe la balle et demande à l'enfant de lancer la balle, boucle de queue
Alex Coleman

12
@AlexColeman Ce code est analogue au fait que le parent jette la balle en l'air, la saisisse, puis la remette à l'enfant qui fait la même chose avant de rendre la balle au parent, et ainsi de suite.
Ajedi32

11
La commande TARGET.AIM(B);dans la méthode AIMest un appel récursif. Donc, cela viole la règle "les fonctions ne peuvent pas s'appeler".
Theodore Norvell

31

Bash, 3 personnages

yes

oui retournera à plusieurs reprises «y» à la console

Edit: tout le monde est invité à éditer cette ligne:

yes something | xargs someaction

(merci à Olivier Dulac)


1
Pourquoi cela va-t-il continuer? je ne le remets pas en question simplement pour essayer de comprendre pourquoi
Teun Pronk

2
@TeunPronk yesest une commande bash qui affiche le mot oui jusqu'à ce qu'il soit tué ou que le flux soit fermé. Si vous écrivez à l'écran, il ne s'arrêtera jamais tant que vous ne le tuez pas. C'est une sorte de triche cependant, puisqu'il s'agit d'une commande qui consiste essentiellement en une boucle sur printf.
Scragar

1
Plus amusant serait d'utiliser yespour garder une autre boucle en cours.
Trlkly

3
@izkata: mais alors vous pouvez:: yes something | xargs someactionpas de récursivité (vous pouvez même ajouter -n 1 à xargs pour avoir seulement 1 "quelque chose" par ligne, etc.). L'utilisation de xargs ouvre la voie à des comportements plus complexes (même ceux qui n'ont rien à voir avec la sortie yes)
Olivier Dulac

4
@scragar, vous auriez dû répondre yes.
daviewales

28

C, 35 caractères

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

Le programme s’exécute. Je ne sais pas si cela est considéré comme une récursion ou non.


4
@mniip Tail récursivité, alors, si elle s'appliquait au niveau du processus
Izkata

3
@Izkata Tail récursivité est toujours une récursivité, mais ce n'est pas une récursivité. La récursivité implique une fonction (ou un processus dans ce cas) 'en attente' d'une autre itération d'elle-même pour se terminer. Dans ce cas, execle nouveau processus remplace le processus d'origine, il n'y a donc pas de pile d'appels qui finira par retourner ou déborder.
Millinon

4
@millinon Dans un langage qui prend en charge l'optimisation, la récursion arrière remplace l'appel précédent dans la pile d'appels, de la même manière que execle processus précédent. Il ne débordera pas non plus.
Izkata

1
@millinon juste pour être super pédant et pour traîner cette discussion plus longtemps, dans le langage de programmation Scheme, cette optimisation est une fonctionnalité du langage. C'est dans la spécification que si vous effectuez un appel final, l'interpréteur / compilateur doit réutiliser le dernier cadre de la pile. Ceci est dû au fait que Scheme n'a pas de structure de boucle intégrée, aussi le seul moyen d'implémenter une boucle dans Scheme est de faire la récursion de la queue, et ce serait un peu nul si vous avez trop de pile pour essayer de faire une boucle trop souvent :)
Ord

2
Si vous voulez du pédantisme, Scheme n'a pas "l'optimisation des appels de queue", mais des "appels de queue appropriés". Ce n'est pas une optimisation, c'est une exigence de base du standard de langage et son absence est interdite. L'optimisation (ou la suggestion que cela a un rapport avec la récursion) est donc un terme fortement découragé.
Leushenko

28

C (avec les fonctions intégrées GCC - semble également fonctionner avec clang)

  • Pas de boucles explicites
  • Aucun gotos explicite
  • Pas de récursion
  • Juste du bon vieux jeu avec la pile (enfants, n'essayez pas ça à la maison sans surveillance):
#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);
    }
}

Explication:

  • main()premiers appels frameloop(NULL). Dans ce cas, utilisez la commande __builtin_return_address()intégrée pour obtenir l'adresse de retour (en main()) à laquelle frameloop()renvoyer. Nous retournons cette adresse.
  • printf() pour montrer que nous sommes en boucle
  • Maintenant, nous appelons frameloop()avec l'adresse de retour pour l'appel précédent. Nous examinons dans la pile l’adresse de retour actuelle et, lorsque nous la trouvons, nous substituons l’adresse de retour précédente.
  • Nous revenons ensuite du 2e frameloop()appel. Mais puisque l'adresse de retour a été piratée, nous finissons par revenir au point de retour main()du premier appel. Nous nous retrouvons donc dans une boucle.

La recherche de l'adresse de retour dans la pile serait bien sûr plus nette, mais j'ai déroulé quelques itérations afin d'éviter toute boucle.

Sortie:

$ 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
agréable! Je me demande pourquoi ces fonctions ne font pas partie de la spécification C? ;-D
Brian Minton

4
@BrianMinton En réalité, une chose similaire devrait être réalisable avec setjmp()/ longjmp(). Celles-ci ne sont pas dans la norme c, mais dans la bibliothèque standard . Cependant, j'avais envie de munger la pile manuellement aujourd'hui ;-)
Digital Trauma

@ BrianMinton J'imagine que c'est dans les spécifications du processeur, ce qui la rend dépendante de la plate-forme (matérielle). Et il est plutôt dangereux d'utiliser lorsque stackframe est généré automatiquement, je ne serais pas surpris si AV crierait à propos d'un tel code. Vérifiez ceci ou cela pour les versions x86 asm.
PTwr

27

Haskell

Le code suivant ne contient aucune fonction récursive (même indirectement), aucune primitive en boucle et n'appelle aucune fonction récursive intégrée (utilise uniquement IOla sortie et la liaison), mais répète une action donnée indéfiniment:

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

Function extractn'appelle rien, ycappelle juste extractet mainappelle juste ycet putStrLnet >>, qui ne sont pas récursifs.

Explication: L'astuce réside dans le type de données récursif Strange. C'est un type de données récursif qui se consomme lui-même et qui, comme le montre l'exemple, permet une répétition arbitraire. Premièrement, nous pouvons construire extract x, ce qui exprime essentiellement une auto-application x xdans le calcul lambda non typé. Et cela permet de construire le combinateur Y défini comme λf.(λx.f(xx))(λx.f(xx)).


Mise à jour: comme suggéré, je publie une variante plus proche de la définition de Y dans le calcul lambda non typé:

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
Des structures de données récursives au lieu de fonctions récursives ... bien.
ApproachingDarknessFish le

6
Celui-ci me tient à cœur en tant que personne intéressée par la programmation fonctionnelle totale. Vous venez de montrer comment créer le combineur en Y avec un type de données récurrent négatif. C'est pourquoi le nombre total de langues nécessite que des types récurrents se produisent à droite de la flèche et que les rosiers soient interdits. Joli! J'ai fait un compte ici juste pour upvote cela!
Jake

Vous pouvez supprimer la letliaison et définir yc f = extract $ C $ f.extract, puisque la letliaison est une fonctionnalité de langage qui permet la récursion (classique let x = x in x). Cela réduit également certains caractères :)
Earth Engine

ou mêmeyc = extract . C . (.extract)
Earth Engine

@EarthEngine C'est vrai, je voulais juste garder la structure plus proche de la définition originale de Y.
Petr Pudlák

26

C ++

Ce qui suit génère un compte à rebours de 10 à "Blast off!" en utilisant un modèle de métaprogrammation.

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

Cela peut ressembler à un exemple classique de récursivité, mais ce n’est pas le cas, du moins techniquement, selon votre définition. Le compilateur générera dix fonctions différentes . countdown<10>imprime "T moins 10" puis appelle countdown<9>, et ainsi de suite, pour countdown<0>imprimer "Blast off!" et revient ensuite. La récursivité se produit lorsque vous compilez le code, mais l'exécutable ne contient aucune structure en boucle.

En C ++ 11, on peut obtenir des effets similaires en utilisant le constexprmot clé, tel que cette fonction factorielle. (Il n'est pas possible d'implémenter l'exemple de compte à rebours de cette façon, car les constexprfonctions ne peuvent pas avoir d'effets secondaires, mais je pense que cela pourrait être possible dans le prochain C ++ 14.)

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

Encore une fois cela ressemble vraiment récursion, mais le compilateur étendra sur factorial(10)dans 10*9*8*7*6*5*4*3*2*1, puis remplacez probablement avec une valeur constante de 3628800, de sorte que l'exécutable ne contient aucune mise en boucle ou un code récursif.


4
La seconde est vraiment la récursivité pure et simple, pas la métaprogrammation. D'abord parce que le compilateur émettra (dans le cas général) un corps de fonction régulier que vous pourrez utiliser avec des arguments non constants; et deuxièmement parce que lorsqu'il effectue une opération au moment de la compilation, il ne fait rien de ce type "d'expansion" de style template, il exécute une évaluation standard sur place - identique à celle d'exécution - pour produire 3628800directement sans forme intermédiaire.
Leushenko

@ Leushenko ouais je sais. Mais là encore, l'exemple de modèle fait la même chose - utilise une fonction récursive dans un langage complet de Turing au moment de la compilation - la seule différence est que celui de constexpr utilise un langage qui ressemble beaucoup plus à C ++. Comme pour toutes les réponses, celle-ci déroge aux règles et je suis tout à fait honnête à ce sujet. constexpra été spécialement conçu pour rendre obsolètes certains aspects de la métaprogrammation des modèles.
Nathaniel

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

21

Java

Jouons avec le chargeur de classes Java et définissons-le comme son propre parent:

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

    }
}

En fait, cette boucle est si puissante que vous devrez utiliser un kill -9bouton pour l'arrêter :-)

Il utilise 100,1% du processeur de mon Mac.

100,1% de la CPU

Vous pouvez essayer de déplacer le System.outà la fin de la fonction principale pour expérimenter un autre comportement amusant.


lol. obtenir java coincé dans lui-même :)
masterX244

Aimez le hack de chargement récursif de la machine virtuelle Java.
Isiah Meadows le

20

CSharp

Un de plus et tout aussi méchant:

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

Ce n'est pas une récursion ... c'est une réification des modèles de code. Bien qu'il semble que nous appelions la même méthode, le moteur d'exécution crée constamment de nouvelles méthodes. Nous utilisons le paramètre type de int, car cela l’oblige à créer un tout nouveau type et chaque instance de la méthode doit remplacer une nouvelle méthode. Il ne peut pas partager de code ici. Finalement, nous éliminons la pile d’appels car elle attend indéfiniment le retour de l’int qui a été promis mais jamais livré. De la même manière, nous continuons à écrire le type que nous avons créé pour le garder intéressant. En gros, chaque C que nous appelons est une méthode totalement nouvelle qui a juste le même corps. Ce n'est pas vraiment possible dans un langage comme C ++ ou D qui font leurs templates lors de la compilation. Depuis, C # JIT est super paresseux, il ne crée ce contenu qu’au dernier moment. Ainsi,


14

Redcode 94 (Core War)

MOV 0, 1

Copie l'instruction à l'adresse zéro pour en adresser une. Parce que dans Core War, toutes les adresses sont relatives à l'adresse actuelle du PC et modulo à la taille du noyau. Il s'agit d'une boucle infinie dans une instruction unique.

Ce programme (guerrier) s’appelle " Imp " et a été publié pour la première fois par AK Dewdney.


3
Les lutins doivent marcher, préparez vos portes, préparez-les sinon vous serez écrasés.
seequ

Préparez votre SPL 0, 0; MOV 1, -2effet.
Wberry

Bien, j'espérais que cela n'avait pas encore été posté. +1
mbomb007

14

Dard

Je suppose que ce serait la manière classique de faire de la récursivité sans aucune fonction récursive réelle. Aucune fonction ci-dessous ne se désigne par son nom, directement ou indirectement.

(Essayez-le à 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
Le combinateur Y?
Aditsu

5
Techniquement, je suppose que c'est le combinateur Z parce que c'est pour un langage strict. Le combinateur Y nécessite un langage paresseux pour éviter un déroulement infini. La seule différence est que sa dernière partie est eta-expand.
lrn

12

JS

Pas très original mais petit. 20 caractères.

setInterval(alert,1)

Vous pouvez réellement supprimer ,1et cela fonctionnera toujours,
Derek mercredi

@Derek 功夫 會 功夫 si je fais cela, je ne reçois qu'une alerte sur Firefox
xem

1
En chrome cela fonctionne sans le dernier paramètre. Le code doit être considéré comme valide s'il fonctionne dans au moins un environnement.
Derek mercredi

3
@Derek 朕 會 功夫setIntervaln'est pas une déclaration, cependant; c'est seulement une fonction. Il est utilisé dans une déclaration d'expression, et si nous ne pouvons pas utiliser des déclarations d'expression, je ne le sais même plus.
Keen

1
@Cory - Eh bien, je suppose que c'est valable alors!
Derek vendredi

12

Signaux en C

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

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

Le comportement de ce programme est évidemment très indéfini, mais aujourd’hui, sur mon ordinateur, il continue d’imprimer «Hello, world!».


11

Emacs Lisp

C’est le moment idéal pour montrer la conception puissante de Lisp où "le code est constitué de données et les données sont le code". Certes, ces exemples sont très inefficaces et cela ne devrait jamais être utilisé dans un contexte réel.

Les macros génèrent du code qui est une version non déroulée de la boucle supposée et ce code généré correspond à ce qui est évalué au moment de l'exécution.

repeat-it: permet de boucler N fois

(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 de répétition:

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

Cette macro est semblable à la précédente, repeat-itmais elle fonctionne exactement comme la macro en boucle courante. do-timesElle vous permet de spécifier un symbole qui sera lié à l’index de la boucle. Il utilise un symbole de temps d'expansion pour s'assurer que la variable d'index est définie correctement au début de chaque boucle, que vous modifiiez ou non sa valeur pendant le corps de la boucle.

(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 de répétition avec index:

Ce test montre que:

  1. Le corps évalue N fois

  2. la variable d'index est toujours définie correctement au début de chaque itération

  3. changer la valeur d'un symbole nommé "repli" ne gâchera pas l'index

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

Calcul lambda non typé

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

3
Je ne suis pas sûr si cela compte comme une récursion ou non, qu'est-ce qui en est la base théorique fondamentale ... +1 de toute façon.
moelleux

@fluffy Ce n'est pas récursif en soi, aucune des fonctions ne s'appelle (en particulier parce que les fonctions ne sont pas nommées).
fier haskeller

IMHO, le lambda calcul est un modèle de calcul et n'est pas un langage de programmation (c'est-à-dire sans un modèle de machine concret, nous ne pouvons pas considérer le lambda calcul comme un PL).
Ta Thanh Dinh

Vous pouvez absolument construire une machine qui interprète le calcul lambda. Et la syntaxe peut être utilisée comme langage de programmation. Voir, par exemple, github.com/MaiaVictor/caramel
Arthur B

10

Haskell, 24 caractères

sequence_ (repeat (print "abc"))

ou sous forme condensée, avec 24 caractères

sequence_$repeat$print"" 

(bien que le texte soit modifié, cela restera en boucle - cela imprimera deux guillemets et une nouvelle ligne à l'infini)

explication: print "abc" est fondamentalement une action d'E / S qui imprime simplement "abc".
repeat est une fonction qui prend une valeur x et retourne une liste infinie composée uniquement de x.
séquence_ est une fonction qui prend une liste d'actions I / O et renvoie une action I / O qui effectue toutes les actions de manière séquentielle.

donc, fondamentalement, ce programme dresse une liste infinie de commandes print "abc" et les exécute à plusieurs reprises. sans boucles ni récursivité.


4
J'allais publier essentiellement la même réponse dans Clojure, mais je pensais repeatque oui a programming language statement which allows code to be repeatedly executed.
seequ

3
fix(print"">>), cela n’implique pas non plus de fonctions de répétition nommées explicitement.
mniip

1
@TheRare Je ne sais pas comment il est en train de se fermer, mais dans Haskell, repeat n'est pas "une instruction de langage de programmation permettant l'exécution répétée du code" - c'est une fonction qui génère des listes infinies. c'est une boucle comme "int [] arr = {x, x, x};" est une boucle.
fier haskeller

1
oui, mais quelque chose doit être implémenté en utilisant la récursivité, car sans elle, il est fondamentalement impossible
fier haskeller

3
En fait, chaque fonction de ce code est définie à l'aide de la récursivité, voire de l'impression
fier haskeller

10

ASM (x86 + I / O pour Linux)

Peu importe combien vos langages de haut niveau insupportables vont lutter, ce sera toujours une manipulation cachée du pointeur d’instructions. En fin de compte, ce sera une sorte de "goto" (jmp), à moins que vous ne soyez assez ennuyé pour dérouler la boucle au moment de l'exécution.

Vous pouvez tester le code sur Ideone

Vous pouvez également consulter une version plus raffinée de cette idée dans le code DOS de Matteo Italia .

Il commence par la chaîne 0..9 et le remplace par A..J. Aucun saut direct n’est utilisé (disons qu’il n’ya pas eu de "goto"), pas de récurrence non plus.

Le code pourrait probablement être plus petit avec un certain abus de calcul d'adresse, mais travailler sur un compilateur en ligne est gênant, donc je vais le laisser tel quel.

Partie centrale:

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

Code entier

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

J'allais appeler cela comme un dup de codegolf.stackexchange.com/a/34298/11259 , mais je vois que c'est la réponse précédente. +1
Digital Trauma

@ DigitalTrauma oh, je vois quelqu'un qui a élaboré une version plus raffinée de mon idée - vieux truc, mais à l'ère du code géré, les gens ont tendance à oublier comment les choses fonctionnent réellement. (Je n'aime pas le golf, il est bien trop souvent réduit à "regarde maman! Je peux faire bouger les choses en appuyant sur une touche!")
PTwr

9

C préprocesseur

Une petite "technique" que j'ai imaginée lors d'un défi d'obscurcissement. Il n'y a pas de récursion de fonction, mais il y a ... récursion de fichier?

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

J'ai écrit / testé cela en utilisant gcc. Il est évident que votre compilateur doit prendre en charge la __INCLUDE_LEVEL__macro (ou la __COUNTER__macro avec quelques modifications) pour que celle-ci soit compilée. Cela devrait être assez évident de savoir comment cela fonctionne, mais pour le plaisir, lancez le préprocesseur sans compiler le code (utilisez le -Edrapeau avec gcc).


8

PHP

En voici un avec PHP. Boucle en incluant le même fichier jusqu'à ce que le compteur atteigne $ 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
?>

La même chose qu'une boucle for:

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

Bon sang, cela compte aussi comme une récursion, n'est-ce pas?
Pichan

Ne croyez pas que ce soit le cas - la similitude vient à l’esprit de l’exemple de @ Nathaniel: le préprocesseur inclura ces fichiers qui sont ensuite évalués simultanément.
Départ le

@Pichan Je dirais qu'il s'agit davantage d'un déploiement de boucle, car vous vous retrouvez avec des copies de code en mémoire.
PTwr

Je viens de voir la question aujourd'hui et suis arrivé avec un code presque identique. Trop tard pour moi!
TecBrat

Est header("Location: .?x=".$_GET['x']+1);compté comme récursion?
Charlie

8

Python

Le code suivant ne contient aucune fonction récursive (directe ou indirecte), aucune primitive en boucle et n'appelle aucune fonction intégrée (à l'exception de 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)

Imprime "Bonjour tout le monde!" un nombre de fois donné.

Explanation: Function zimplémente le combinateur strict de points Z qui, sans être défini de manière récursive, permet d'exprimer tout algorithme récursif.


J'appellerais gtrès indirectement récursif.
seequ

@TheRare Pourquoi? Quel est ton argument? Qu'est-ce que cet gappel appelle à gnouveau? Bien sûr, le truc est l’application automatique g(g), mais il n’ya pas de récursivité. Souhaitez-vous appeler gindirectement récursif si vous n'avez pas vu g(g)? C’est le moyen standard de le faire dans des langues qui ne permettent pas de définitions récursives, telles que le lambda calcul.
Petr Pudlák

Vous donnez gcomme argument xet ensuite appelez x(x).
seequ

2
@TheRare Une fonction (ou un ensemble de fonctions) n'est ni récursive ni non récursive par son utilisation, elle est simplement déterminée par sa définition.
Petr Pudlák

1
toutes les réponses trichent d'une manière ou d'une autre: il y a toujours une récursion ou une boucle quelque part , sinon dans la réponse, alors dans le code, la réponse appelle. J'aime la façon dont celui-ci triche.
Wayne Conrad

8

code machine z80

Dans un environnement où vous pouvez exécuter à chaque adresse et mapper la ROM partout, mappez 64 Ko de ROM remplie de zéros sur l'espace d'adressage entier.

Ce qu'il fait: rien. À plusieurs reprises.

Comment ça marche: le processeur va commencer à s’exécuter, l’octet 00est une nopinstruction, il va donc continuer, atteindre l’adresse $ffff, se boucler $0000et continuer à exécuter nops jusqu’à ce que vous le réinitialisiez.

Pour le rendre légèrement plus intéressant, remplissez la mémoire avec une autre valeur (veillez à éviter les instructions de flux de contrôle).


Vous pouvez remplir la mémoire avec des zéros et y placer un vrai programme quelque part.
seequ

Donc, vous pourriez mettre dans un programme 64k, sans aucune branche, et il serait juste exécuter à plusieurs reprises?
Bill Woodger

@ BillWoodger, vous pourriez le faire, surtout si vous n'avez aucune interruption sur la plate-forme (ou si aucune n'est activée)
harold

Un peu de plaisir :-)
Bill Woodger

8

Perl-regex

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

démo

ou essayez comme:

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

Le (?!)jamais correspondre. Le moteur des expressions rationnelles essaie donc de faire correspondre chaque position de largeur zéro dans la chaîne correspondante.

Le (q x x x 10)est le même que (" " x 10)- répétez les spacedix fois.

Edit: modification des "caractères" en position de largeur zéro afin d’être plus précis pour une meilleure compréhension. Voir les réponses à cette question de stackoverflow .


6

T-SQL -12

print 1
GO 9

En fait, il s’agit plutôt d’une bizarrerie de Sql Server Management Studio. GO est un séparateur de script et ne fait pas partie du langage T-SQL. Si vous spécifiez GO suivi d'un numéro, le bloc sera exécuté autant de fois.


1
J'utilise T-SQL presque tous les jours et je ne savais pas que vous pouviez le faire avec GO. +1
CailinP

Techniquement, ce n'est pas T-SQL. GOest en fait une directive SSMS, raison pour laquelle vous ne pouvez pas la mettre dans des objets scriptés T-SQL, comme par exemple une procédure stockée.
RBarryYoung

Oui, j'ai ajouté ça dans mon commentaire de spoiler. J'imagine que l'utilisation de sqlcmd serait trop de tricherie.
Michael B

6

C #

Imprime tous les entiers de uint.MaxValue à 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
Je ne sais pas vraiment si cela compte. Vous appelez explicitement WriteLine01 Int.MaxValue times. Il vient d'exploser derrière une énorme quantité d'appels.
Michael B

Comment ça compte pas? Il n'y a pas de boucle et pas de récursivité.
LVBen

1
En outre, la pile d’appels n’est pas très importante, sauf si vous considérez peut-être un appel de 32 appels de haut.
LVBen

1
Pourquoi seulement 32 fois au lieu de 4294967296?
LVBen

4
@ ja72 Si je travaille sur un projet open source dans lequel je ne peux pas utiliser de boucles ou de récursions, je vais totalement contribuer à un code comme celui-ci!
LVBen

6

JS (dans le navigateur)

Que dis-tu de ça?

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

Imprime l'heure actuelle et recharge la page.


Oh, tire. Je viens de poster une réponse avec le même concept de base. J'avais scanné la page pour "JavaScript" ou n'importe quoi montrant des balises HTML. Je suppose que je pourrais laisser ma réponse en suspens, simplement parce qu’elle gère le coin où l’emplacement contient un "#". Quoi qu'il en soit, +1.
Keen

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

@ AlexReynolds Hein, bizarre. Le mien fonctionne très bien sur FF 30.
Pichan

J'ai seulement copié et collé dans votre code tel qu'il a été écrit. Ça ne marche pas Peut-être avez-vous des préférences de sécurité spéciales activées pour que cela fonctionne?
Alex Reynolds

@AlexReynolds Nope, jamais modifié les paramètres de sécurité. Et cela fonctionne aussi sur Chrome.
Pichan
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.