Comment peut-on mettre une variable locale dans une fonction en lisp ?
Merci d'avance
Version imprimable
Comment peut-on mettre une variable locale dans une fonction en lisp ?
Merci d'avance
Avec un let : http://www.cc.gatech.edu/classes/AY2...pTutorial.html
J'avais essayé avec ca,
mais le problème est que la variable locale créée avec un "let" est modifiée par les appels récursifs,
en gros c'est la même variable qui est utilisé par tous les appels récursifs...
Voilà le code...
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 (defun minmax (plateau joueur joueur_evalue profondeur opt) (let ((result '(0 (0 0))) (copie nil) (liste_coups (liste_coups_possibles plateau joueur)) (opt_virt 0) (coup_a_jouer nil) (fils '(0 (0 0))) ) (cond ((or (null liste_coups) (equal profondeur 0)) (setf (car result) (evaluation plateau joueur_evalue)) ;(print plateau) (print joueur) (print joueur_evalue) (print profondeur) (print opt) ) (t (cond ((equal opt 1) (setf (car result) -100000) (dolist (coup_a_jouer liste_coups) ;(print plateau) (setf copie '((0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0))) (copie_plateau plateau copie) (update copie coup_a_jouer joueur);(print copie) (print plateau)(print " ") (setf fils (minmax copie (- 3 joueur) joueur_evalue (- profondeur 1) (- 1 opt))) (cond ((> (car fils) (car result)) (setf (car result) (car fils)) (setf (cadr result) coup_a_jouer))) ) ) ((equal opt 0) (setf (car result) 100000) (dolist (coup_a_jouer liste_coups);(print plateau) (setf copie '((0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0))) (copie_plateau plateau copie);(print copie)(print plateau) (update copie coup_a_jouer joueur);(print copie)(print plateau)(print " ") (setf fils (minmax copie (- 3 joueur) joueur_evalue (- profondeur 1) (- 1 opt))) (cond ((< (car fils) (car result)) (setf (car result) (car fils)) (setf (cadr result) coup_a_jouer))) ) ) ) ) ) result ))
L'appel récursif modifie la variable locale "result"...
Il faut appuyer sur le bouton # de l'éditeur pour avoir les balises [CODE]
Ok merci.
Bonjour,
1. je ne sais pas si tu _veux_ comprendre ce que tu as fait...
Supposons que ce soit le cas.
Il se trouve que tu as construit (bien involontairement, je suppose) ce qu'on appelle une "closure".
En voici un exemple très simple:
Ca ressemble énormément à une variable globale (quoique pas accessible globalement) et ça ressemble encore plus à ce qu'on appelle une variable locale statique (dans d'autres langages (comme C)).Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 (defun foo (x) (let ((closevar '(0))) (setf (car closevar) (+ (car closevar) x)) (car closevar))) ? (foo 0) => 0 ? (foo 1) => 1 ? (foo 0) => 1 ? (foo 1) => 2 ? (foo 0) => 2
En fait, le bout de code avec le "setf" modifie physiquement la donnée " '(0) " (qui est un cons dont le car est 0, AVANT TOUT APPEL DE LA FONCTION, et dont le cdr est NIL) qui est incluse dans le code de la fonction.
Ce qui revient à dire que le code se modifie lui-même!
(tu peux le vérifier en pretty-printant le code de la fonction (avec ^P en Le_Lisp))
Si tu compiles la fonction en Le_Lisp et que tu regardes la plist du symbole foo, tu verras où la donnée encapsulée est conservée à la compilation.
2. Pour résoudre à moindres frais ton problème, il suffit juste (mais ce n'est certainement pas la meilleure solution!!! (et j'avoue que je n'ai pas essayé de comprendre ton code (ni, bien sûr, de vérifier si ma solution marche vraiment (mais j'ai plutôt bon espoir...)))) que tu mettes un "copy" devant _toutes_ les données incluses dans ton code.
Par exemple:
3. Evidemment, tu peux aussi envosager d'écrire ton code différemment, comme le suggère justement Garulfo.Code:
1
2
3
4
5 (defun minmax (plateau joueur joueur_evalue profondeur opt) (let ((result (copy '(0 (0 0)))) ... (setf copie (copy '((0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)(0 0 0 0 0 0 0 0)))) ...
4. Personnellement, je le réécrirais en objet (en CLOS ou Smeci, par exemple), en tentant d'être clair sur les objets manipulés (plateau, joueur, coup, resultat, etc.).
HTH
)jack(
Juste deux petites remarques :
1) toute fonction est une fermeture en lisp, constituée d'un environnement et de son corps;
2) En plus ton exemple est un très mauvais choix. Ça marche par une propriété de l'implémentation des listes (une très mauvaise chose dans CLISP et Scheme d'ailleurs mais heureusement corrigé dans le R6RS de Scheme avec la distinction entre liste mutable et non mutable). Si tu prenais autre chose qu'une liste ou si tu ne modifiais pas le car mais la liste, ta fonction ne marchait plus.
Avec ces fonctions par exemple ne fonctionnent pas
Ainsi ce que tu dis devient faux de manière général, car ce n'est plus à chaque fois qu'on peut y penser comme une variable statique. J'aurais plutôt écrit ton exemple ainsiCode:
1
2 (defun foo (x) (let ((v 0)) (setf v (+ v x)) v)) (defun foo (x) (let ((v '(0))) (setf v (list (+ (car v) x))) (car v)))
Code:
1
2 (setf f (let ((v 0)) (lambda (x) (setf v (+ v x)) v))) (defun foo (x) (funcall f x))