Ocaml

Résolu/Fermé
katkacyt - Modifié par katkacyt le 18/04/2011 à 18:12
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 - 19 avril 2011 à 16:29
Bonjour,

je debut en ocaml et j'ai un probleme avec la fonction que j'ecris:


let deja_vu = Array.make_matrix monLaby.p monLaby.q 0 in  
let parent = Array.make_matrix monLaby.p monLaby.q (0,0) in  
let distance = Array.make_matrix monLaby.p monLaby.q (-1) in  
let file = !start::[] in  
while (List.length file != 0) do  
 let (i,j) = List.hd file;  
 file = List.tl file;  
 if i>0 && monLaby.v.(i).(j) && deja_vu.(i-1).(j)=0 then begin 
   distance.(i-1).(j)<-distance.(i-1).(j)+1;  
   deja_vu.(i-1).(j)<-1; 
   parent.(i-1).(j)<-(i,j); 
   file@(i-1,j); 
   end; 
 deja_vu.(i).(j)=2 
done;; 


j'ai droit a un joli 'syntax error' (ocaml indique que c'est sur la dernier ligne la ou y a done).. mais je ne comprends pas ce qui ne va pas??

merci de votre aide!

4 réponses

KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
18 avril 2011 à 20:17
Tu n'as pas mis tout ton code, il faut donc "deviner" ce que qu'est monLaby et start.
J'ai mis des trucs bidons qui semblent convenir, tu les changeras comme il faut...

L'usage de boucle est déconseillé en Caml, il vaut mieux penser aux algorithmes récursifs et au pattern matching, surtout pour traiter des listes comme tu le fais.

Autre chose, tu dis faire du OCaml mais tu utilises certaines notation de Caml Light (pour les références par exemple) ce que j'ai fait est du OCaml mais pour éviter les ambiguïtés je ne me suis pas servi des références.

Je pourrais également critiquer l'usage intensif de tes matrices qui n'aide pas à la compréhension de ton programme, mais vu que je ne voulais pas tout changer je les ai laissé comme ça. Par contre je n'ai pas mis de "in" partout, ils n'ont rien à faire ici.

Voici le code, il ne marche pas, mais c'est lié à mon initialisation bidon et/ou à des erreurs dans ta manipulation des tableaux

type laby = {p:int; q:int; v:bool array array};;
let monLaby = {p=0; q=0; v=Array.make_matrix 0 0 false};;
let start = (0,0);;

let deja_vu = Array.make_matrix monLaby.p monLaby.q 0;;
let parent = Array.make_matrix monLaby.p monLaby.q (0,0);;
let distance = Array.make_matrix monLaby.p monLaby.q (-1);;
let file = start::[];;

let rec operation = function (* remplace la boucle while, de paramètre file *)
|(i,j)::q -> (* l'existence de (i,j) implique que la liste est non vide *)
	let f = (* f est la valeur de file après le passage dans le if *)
		if i>0 && monLaby.v.(i).(j) && deja_vu.(i-1).(j)=0
		then	begin 
			distance.(i-1).(j) <- distance.(i-1).(j)+1;  
			deja_vu.(i-1).(j) <- 1; 
			parent.(i-1).(j) <- (i,j); 
			q@[(i-1,j)]  
			end
		else q
	in 
	deja_vu.(i).(j) <- 2;
	operation f; (* on boucle sur f *)
|_ -> ();; (* condition d'arrêt *)

operation file;; (* utilise la fonction récursive sur file *)
1
bonjour
merci pour votre reponse!!
oui, j'ai poste qu'un morceau du code vu que programme est assez grand..
oui, j'utilise des references, mais c'est comme on nous a enseigne au cours?
quand aux matrices - je ne voit pas une meilleure solution, c'est implementation d'algo du dijkstra pour recherche du chemin dans un labyrinthe

je poste mon code en entier en attente d'eventuelles critiques (car je ne me sent pas tres a l'aise avec ocaml) et j'essaie d'arranger la solution que vous m'aviez indique
merci en tout cas pour lecture et le temps consacre!!

open Graphics;;
(*toutes les fonctions pour laby*)
type laby = { p: int; q: int; h: bool array array; v: bool array array};;
let constr_laby a b =  { p= a; q= b; h=Array.make_matrix a b false; v=Array.make_matrix a b false};;
type 'a set = Vois of int ref * 'a array;;
let creer_frontiere n x = let tab = Array.make n x in Vois(ref 0, tab);;
let ajout_elem (Vois(a, tab)) x = tab.(!a) <- x; a:=!a+1;;
let suppr_elem (Vois(a, tab)) x = for i=x to !a do tab.(i) <- tab.(i+1) done; a:=!a-1;;
let choix_elem (Vois(a, tab)) = Random.self_init(); let t = Random.int (!a) in tab.(t);;
let est_vide (Vois(a, tab)) = if !a==0 then true else false;;
let set_remove_all (Vois(a,tab)) f = let j=ref 0 in for i=0 to !a-1 do 	if f tab.(!j) then suppr_elem (Vois(a, tab)) !j else j:=!j+1 done;;  
let constr_I p q = Array.make_matrix p q false;;
let neighbours_outside laby en_I (i,j)= (if i>0 && not en_I.(i-1).(j) then [i-1,j] else [])@(if i<(laby.p-1) && not en_I.(i+1).(j) then [i+1, j] else [])@(if j>0 && not en_I.(i).(j-1) then [i, j-1] else [])@(if j<(laby.q-1) && not en_I.(i).(j+1) then [i, j+1] else []);;
let rand x = Random.self_init(); Random.int x;;
(*fin des fonctions*)


(*initialization du laby*)
let tailleLabyp=45;;
let tailleLabyq=30;;
let monLaby = constr_laby tailleLabyp tailleLabyq;;
let frontiere = creer_frontiere (monLaby.p*monLaby.q) (0,0);;
let ens_I = constr_I monLaby.p monLaby.q;;
(*fin d'initialization*)
(*choix au hasard d'une premiere case*)
let i=rand monLaby.p;;
let j=rand monLaby.q;;
ens_I.(i).(j)<-true;;
ajout_elem frontiere (i,j);; 
(*fin de choix de premiere case*)
(*boucle principale -> creation du laby*)
while not (est_vide frontiere) do
	let (x,y) = choix_elem frontiere in
	let listvois = neighbours_outside monLaby ens_I (x,y) in 
	let longeur= List.length listvois in
	let (a,b) = List.nth listvois (rand longeur) in 
	ens_I.(a).(b)<-true;
	if x=a then 
		(if b>y then monLaby.h.(a).(b)<-true else monLaby.h.(a).(b+1)<-true) 
	else (
		if x>a then monLaby.v.(a+1).(b)<-true else monLaby.v.(a).(b)<-true);
	ajout_elem frontiere (a, b);
	set_remove_all frontiere (fun e -> neighbours_outside monLaby ens_I e = [])	
done;;
(*fin de la boucle principale*)


(*choix de l'entree et du sortie*)
let stop = ref (0, 0);;
let start = ref (0, 0);;
let cote = rand 2 in if cote mod 2 = 0 then (start:=(0, rand monLaby.q); stop:=(monLaby.p-1, (rand monLaby.q))) else (start:=(0, rand monLaby.q); stop:=(monLaby.p-1, rand monLaby.q));;
(*fin de choix de l'entree et sortie*)

(*dessin du laby*)
let taille_carre=15 in 
let margin=10 in
open_graph "";
resize_window ((taille_carre*monLaby.p)+2*margin) ((taille_carre*monLaby.q)+2*margin);
draw_rect margin margin (taille_carre*monLaby.p) (taille_carre*monLaby.q);
(*dessine les lignes horizontaux*)
for i=1 to (monLaby.q-1) do
	moveto margin (margin+i*taille_carre);
	for j=0 to (monLaby.p-1) do
		if (monLaby.h.(j).(i)=false) then
			rlineto taille_carre 0 
		else rmoveto taille_carre 0; 
	done;
done;
(*dessine les lignes verticaux*)
for i=1 to (monLaby.p-1) do
	moveto (margin+i*taille_carre) margin;
	for j=0 to (monLaby.q-1) do
		if (monLaby.v.(i).(j)=false) then
			rlineto 0 taille_carre 
		else rmoveto 0 taille_carre; 
	done;
done;
set_color green;
(*dessine la case start*)
let e1 = fst !start in let e2 = snd !start in 
fill_rect (e1*taille_carre+margin+taille_carre/4) (e2*taille_carre+margin+taille_carre/4) (taille_carre/2) (taille_carre/2);
(*dessine la case stop*)
let s1 = fst !stop in let s2 = snd !stop in 
fill_rect (s1*taille_carre+margin+taille_carre/4) (s2*taille_carre+margin+taille_carre/4) (taille_carre/2) (taille_carre/2);;

(*solution de laby*)
LE MORCEAU QUE J'AI DEJA POSTE ET DONT JE VAIS M'OCCUPER A L'INSTANT 
(*fin de solution du laby*)
read_line();;
close_graph();;
(*fin du dessin du laby*)



cathy
0
finalement j'ai fait:

type colorGraph = Blanc|Gris|Noir;; 
let color = Array.make_matrix monLaby.p monLaby.q Blanc;; 
let parent = Array.make_matrix monLaby.p monLaby.q (0,0);; 
let distance = Array.make_matrix monLaby.p monLaby.q (-1);; 
let debut = !start::[];; 

color.(fst !start).(snd !start)<- Gris;; (*case du debut est deja vu*) 
distance.(fst !start).(snd !start)<-0;; (*elle est a distance 0 du debut*) 
parent.(fst !start).(snd !start)<-(fst !start, snd !start);; (*et elle est son parent*) 


let rec traitement_case voisins q i j = match voisins with 
(a, b)::r ->  
   distance.(a).(b) <- distance.(i).(j)+1;   
   color.(a).(b) <- Gris;  
   parent.(a).(b) <- (i,j); 
   traitement_case r q i j;  
|_ -> ();;  

let rec solution = function  
|(i,j)::q ->  
 let f =  
  (let v= ((if (i>0 && monLaby.v.(i).(j) && (color.(i-1).(j)= Blanc)) then [i-1, j] else [])@(if (i<(monLaby.p-1) &&  monLaby.v.(i+1).(j) && (color.(i+1).(j)= Blanc)) then [i+1, j] else [])@(if ((j>0) && (monLaby.h.(i).(j)) && (color.(i).(j-1)= Blanc)) then [i, j-1] else [])@(if (j<(monLaby.q-1) && monLaby.h.(i).(j+1) && (color.(i).(j+1)= Blanc)) then [i, j+1] else [])) in 
  traitement_case v q i j; 
  q@v 
  ) 
 in  
 color.(i).(j) <- Noir; 
 solution f;  
|_ -> ();;  

solution debut;; 


ca marche, mais point vu ocaml j' sais pas si c'est bien
en tout cas merci a KX!!
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
19 avril 2011 à 13:46
Si ça marche et que c'est comme ça que tu l'as vu tant mieux.
Avec OCaml on peut utiliser beaucoup de paradigme (impératif, objet...) mais le mieux est encore d'utiliser le style fonctionnel, tu ne t'en sers pas mais c'est ce qui rend Caml puissant !
0
alors je pense que je ne comprends pas bien ce qui veut dire utiliser le style fonctionnel...
je me suis basee sur la solution que tu m'a propose (pour la derniere partie que j'ai postee), est-ce que ca approche un peu programmation fonctionnel?

connais tu des liens ou je pourrais mieux comprendre comment BIEN programmer en (o)caml?
0
KX Messages postés 16752 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 août 2024 3 019
19 avril 2011 à 16:29
Ma solution n'était pas vraiment très "fonctionnelle" non plus, car j'ai essayé d'en modifier le moins possible pour pouvoir mettre ton code au milieu.
Mais l'utilisation de matrices globales que tu modifies dans des fonctions ce n'est pas vraiment ce dont on a l'habitude, car tu fais de la modification d'état de mémoire, ce qui relève plutôt de la programmation impérative... Cependant je reconnais que Dijkstra n'est pas vraiment le genre d'algorithme qui se prête à de la programmation fonctionnelle...

Pour les liens je ne sais pas trop, regarde sur Google, les liens qui sont issus d'universités sont généralement fiables, sinon j'ai déjà eu l'occasion de lire le tutoriel du site su Zéro il est plutôt bien malgré le fait que son écriture ait été interrompue, je te conseilles quand même de passer les premiers chapitres vu que tu connais déjà le langage ;)
0