Bonjour,
je cherche l'equivalent syntaxique de l'instruction "goto" de Pascal en Lisp.
plus plus de clarté je vous montre un exemple que je veux traduire en Lisp:
merci pour votre aide.Code:
1
2
3
4 Etiquette: i=i+1; if |f|==20 then goto Etiquette;
Version imprimable
Bonjour,
je cherche l'equivalent syntaxique de l'instruction "goto" de Pascal en Lisp.
plus plus de clarté je vous montre un exemple que je veux traduire en Lisp:
merci pour votre aide.Code:
1
2
3
4 Etiquette: i=i+1; if |f|==20 then goto Etiquette;
Lisp a pas de goto, utilise une boucle ou de la récursivité.
Ok,merci.
Et j'ajouterai : quelque soit le langage, même s'il a un "goto", ne l'utilise pas !
http://xkcd.com/292/
Au temps pour moi : excepté en assembleur, il ne *faut pas* utiliser de goto :)
Avantage du goto : aucun
Désaventages :
- flot de donnée imbitable (aussi appelé "code spagetti". Bref, illisible, non maintenanble, beurk)
- moins bonne optimisation par le compilo (il ne faut pas oublier que plus on tente de se "rapprocher de la machine", moins on laisse de flexibilité au compilo et moins il peut optimiser.)
- risque de se faire bouffer par un raptor.
Fuyez le comme la peste (voir même un peu plus vite encore, la peste, ça peut potentiellement se soigner :-p)
alex_pi: http://kerneltrap.org/node/553/2131
N'as tu jamais utilisée un switch..case ? C'est un goto en fait, certes balisé, mais c'est un goto. Bien utilisé ça peut rendre du code très clair. Le lien de GNU_Vince montre qu'il y a certain où le goto peut se poser en solution appropriée. Mais je suis d'accord que rare sont ceux qui l'utilisent avec parcimonie et qu'en général, c'est un remède au manque de structuration de sa pensée. C'est la raison pour laquelle, à ma connaissance, c'est toujours interdit dans les cours de programmation.
Lorsque j'utilise un swicth..case, je met un break à la fin de chaque cas, pour que ce soit sémentiquement équivalent à un filtrage, et que ça reste donc de la programmation structurée. Après, évidement, c'est compilé avec des sauts, donc équivalent à un certain nombre de goto. Mais un while aussi est compilé avec des sauts.
Sur le fait que "dans certains rare cas, ça peut être mieux", je suis raisonnablement d'acord, mais on voit dans le lien que la personne qui dit ça affirme aussi s'être servi de deux goto dans sa vie de programmeur. Pour un hacker du noyau Linux, on peut imaginer qu'il a du programmer pas mal, et pourtant, deux gotos seulement...
Je pense que pour un débutant, il faut lui dire "n'utilise jamais de goto", et le jour où il aura une expérience suffisante de la programmation, il pourra découvrir par lui même que dans certains cas exceptionnels, il peut être judicieux de mettre un goto. Il est toujours beaucoup plus simple de commencer à coder le plus proprement possible, quite à faire plus tard des encarts au dogme que de commencer à coder comme un porc pour ensuite tenter de perdre ses mauvaises habitudes.
Et quand on écrit "incrémenter i tant que f vaut 20" avec un goto, c'est qu'on a de très très mauvaises habitudes de programmation (et/ou qu'on utilise un langage ignoble).
Il y a beaucoup de choses qui sont utilisées en programmation qui pourraient être considérée comme étant aussi maléfique que goto. Je pense notament à la modification des variables. Et pourtant, on s'en sert (des fois à tort et à travers), parce que des fois, c'est la façon la plus simple, la plus claire, la plus efficace d'effectuer une opération.
Oui, on ne devrait pas utiliser le goto, mais quand les alternatives rendent le code moins lisible, c'est vraiment un mal?
Le « break » est aussi un « goto ». La sémantique peut être correcte ou non, ça n'a aucun rapport.
Tu n'as jamais mis un « return » dans un « while » ?? Si tu l'as fait, te rends tu compte que ça viole les principes de la programmation structurée ? C'est un saut en dehors de la fonction. Reste que ça peut être très propre. Par exemple en code d'aucun langage ( ;) )
On devrait le réécrire autrement pour respecter la programmation structurée. Par exempleCode:
1
2
3
4
5
6
7
8
9
10 while ( !e.non_vide() ) { prochain := e.next() if ( prochain = 0 ) return 0 resultat := resultat * prochain } store ( DB, resultat ); return resultat ;
Bien sûr la traduction est d'autant plus simple que l'exemple est bêbêtte.Code:
1
2
3
4
5
6
7
8
9
10
11
12 while ( !e.non_vide() && prochain != 0) { prochain := e.next() resultat := resultat * prochain } if ( prochain = 0 ) resultat = 0 else store ( DB, resultat ); return resultat ;
Mais honnêtement, lequel aurais tu fait ?
C'est très compréhensible d'utiliser des « return » bien placés, mais c'est une forme de « goto ». En cours, dans le premier cours de programmation, nous imposons aux étudiants une seule utilisation du « return » à la fin de la fonction, jusqu'à environ la mi-session. Là, nous traitons du problème de la gestion des erreurs, et on revoit cette règle. D'une certaine façon donc, on accepte l'utilisation d'un saut dans le code.
Ça aussi c'est :resolu: je suppose.
Bon, on est pour et contre le goto, c'est une question de goût...:mrgreen:.
Mais n'oublions pas que LISP est écrit en LISP... Donc si vous voulez écrire l'opérateur spécial while à l'aide d'une macro, vous risquez fort d'être un peu coince-coince...
La structure est (TAGBODY) qui fait partie des fonctions de base. cf http://www.ida.liu.se/imported/cltl/clm/node91.html
Quand à son utilisation dans une application, libre à chacun... :mouarf:
Common lisp permet grâce au mot clé 'labels' de définir des fonctions locales dans le corps d'une fonction.
Ceci permet un style de programmation 'à la goto'.
Code:
1
2
3
4
5
6
7
8
9
10
11 (defun myreverse (list) (labels ((myreverse-acc (list acc) (let ((head (car list)) (rest (cdr list))) (cond (head (cond ((atom head) (myreverse-acc rest (cons head acc))) (t (myreverse-acc rest (cons (myreverse-acc head nil) acc))))) (t acc))))) (myreverse-acc list nil)))
Mhhh, il y a guère de goto, c'est plutôt une bonne vieille fonction recursive et un flet aurait été plus approprié vu qu'il n'y a qu'une fonction.
pour le goto il s'agit de (GO tag).
Attention... ne pas oublier que tagbody ne stocke pas le résultat des évaluations et retourne NIL.Code:
1
2
3
4
5
6
7
8
9
10 ;;;; while à la C (defmacro while (cond &rest blocks) `(tagbody loop (if ,cond (progn (progn ,@blocks) (go loop))) ))
Par contre on peut sortir du bloc (evidemment pas y entrer) si le tag est lexicalement accessible.
Ensuite petit problème GO est une forme spéciale, tag n'est donc pas évalué. Mais on peut tout faire en LISP... ;)