IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Caml Discussion :

[ocaml] Récursivité avec match sur des couples


Sujet :

Caml

  1. #1
    Membre actif Avatar de dragonfly
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    464
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 464
    Points : 240
    Points
    240
    Par défaut [ocaml] Récursivité avec match sur des couples
    Bonjour à tous,

    je débute en ocaml et j'ai un problème un peu simple j'ai l'impression, j'ai la fonction suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    let rec ajout_mur_droit m depart arrivee =
      match depart with
       | arrivee -> m.(fst(depart)).(snd(depart))<-1;
       | (fst(arrivee),_) -> 
            begin
               m.(fst(depart)).(snd(depart))<-1;
    		   let new_dep = (fst(depart),snd(depart) + 1) in
               ajout_mur_droit m new_dep arrivee;
    		end;
       | (_,snd(arrivee)) -> 
            begin
               m.(fst(depart)).(snd(depart))<-1;
    		   let new_dep = (fst(depart)+1,snd(depart) ) in
               ajout_mur_droit m new_dep arrivee;
    		end;;
    appelée de cette façon

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     
     ajout_mur_droit (10,10) (20,20);; (* idéalement vu que cela ne marche pas *)
    Lors de la tentative de compilation, j'ai l'erreur suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Characters 133-134:
         | (fst(arrivee),_) -> 
           ^
    Syntax error: ')' expected, the highlighted '(' might be unmatched
    depart et arrivee étant des paramètres couples (x,y), comment fonctionne le match sur ce type de data ?

  2. #2
    Membre actif Avatar de dragonfly
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    464
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 464
    Points : 240
    Points
    240
    Par défaut
    Finalement, j'ai trouve une réponse (il faut faire des petits arrangements pour gérer les listes) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    let rec ajout_mur_droit m depart arrivee =
      let i= fst(depart) in
      let j= snd(depart) in
      match (i,j) with
       | (a,b) when a=fst(arrivee) && b=snd(arrivee) -> m.(fst(depart)).(snd(depart))<-1;
       | (a,_) when a=fst(arrivee) -> 
            begin
               m.(fst(depart)).(snd(depart))<-1;
    		   let new_dep = (fst(depart),snd(depart) + 1) in
               ajout_mur_droit m new_dep arrivee;
    		end;
       | (_,a) when a=snd(arrivee) -> 
            begin
               m.(fst(depart)).(snd(depart))<-1;
    		   let new_dep = (fst(depart)+1,snd(depart) ) in
               ajout_mur_droit m new_dep arrivee;
    		end;
    	| (a,b) ->  print_string "default" ;;
    Ca fonctionne nickel, mais j'aurai une question : ce code est-il le plus propre ? (véritable obligation des découper les couples, etc...)

    Cdlt,
    Dragonfly

  3. #3
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut Pas de fonctions dans les motifs
    On peut capturer toutes les paires p avec | p -> ...p ... fst p ... snd p.
    On peut aussi capturer toutes les paires (x,y) avec | x,y -> ...x ...y.

    On a droit aux constantes dans les motifs.
    Par exemple le filtrage qui suit traite, dans l'ordre, le cas où y=0 puis x=0 puis le cas général x,y :
    Code OCaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    | x,0 -> ...
    | 0,y -> ...
    | x,y -> ...

    De plus:
    • L'ordre importe. Si plusieurs motifs se recouvrent c'est le premier qui l'emporte.
    • Il ne doit pas y avoir de fonction dans un motif de filtrage.
    • Toute variable dans un motif est une nouvelle variable qui prend la valeur qu'elle capture. La valeur des variables précédemment déclarées ne joue aucun rôle dans un motif.
    • On peut utiliser un motif comme paramètre formel d'une fonction.


    Ton code devrait ressembler à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let rec ajout_mur_droit m (dx,dy) (ax,ay) = ...
    Ou bien encore à ça, qui t'évite d'avoir à écrire (dx,dy) et (ax,ay) pour reconstruire les valeurs de depart et d'arrivee :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let rec ajout_mur_droit m (dx,dy as depart) (ax,ay as arrivee) =
       if depart = arrivee then (...)
       else if dx = ax then (...) 
       else if dy = ay then (...)
       else ...
    Du même auteur: mon projet, le dernier article publié, le blog dvp et le jeu vidéo.
    Avant de poser une question je lis les règles du forum.

  4. #4
    Membre actif Avatar de dragonfly
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    464
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 464
    Points : 240
    Points
    240
    Par défaut
    Merci pour ta réponse, après modifications, j'ai 2 versions qui fonctionnent mais je me pose la question de laquelle est la mieux (dans l'optique de partir dans les bonnes pratiques de codage en Ocaml => perso je suis plus fan de la première version (esthetique))

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    let rec ajout_mur_droit m (dx,dy) (ax,ay as arrivee) =
      match (dx,dy) with
       | (a,b) when a=ax && b=ay -> m.(dx).(dy)<-1;
       | (a,_) when a=ax -> 
            begin
               m.(dx).(dy)<-1;
               ajout_mur_droit m (dx,dy+1) arrivee;
    		end;
       | (_,b) when b=ay -> 
            begin
               m.(dx).(dy)<-1;
               ajout_mur_droit m (dx+1,dy) arrivee;
    		end;
    	| (a,b) ->  print_string "Il est pas droit ton mur !!" ;;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    let rec ajout_mur_droit m (dx,dy) (ax,ay as arrivee) =
       if depart = arrivee then m.(dx).(dy)<-1
       else if dx = ax then  
            begin
               m.(dx).(dy)<-1;
               ajout_mur_droit m (dx,dy+1) arrivee;
    		end
       else if dy = ay then 
            begin
               m.(dx).(dy)<-1;
               ajout_mur_droit m (dx+1,dy) arrivee;
    		end
       else print_string "Il est pas droit ton mur !!" ;;
    et quid de l'intérêt de passer à une récursivité terminale du genre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    let ajout_mur_droit m (dx,dy) (ax,ay) =
      let rec loop_ajout (dbx, dby)= 
       match (dbx,dby) with
       | (a,b) when a=ax && b=ay -> m.(dbx).(dby)<-1;
       | (a,_) when a=ax -> 
            begin
               m.(dbx).(dby)<-1;
               loop_ajout (dbx,dby+1) ;
    		end;
       | (_,b) when b=ay -> 
            begin
               m.(dbx).(dby)<-1;
               loop_ajout (dbx+1,dby) ;
    		end;
    	| (a,b) ->  print_string "Il est pas droit ton mur !!" ;
        in loop_ajout (dx,dy);;
    fonctionne mais je suis pas convaincu que le code soit optimal.

    Cdlt,
    Dragonfly

  5. #5
    Membre émérite
    Avatar de SpiceGuid
    Homme Profil pro
    Inscrit en
    Juin 2007
    Messages
    1 704
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 704
    Points : 2 990
    Points
    2 990
    Par défaut Tout est question de types
    Toutes tes versions sont déjà récursives terminales, pas besoin de changement pour ça.

    Tu peux rendre explicite le fait que ton match ne matche rien du tout :
    Code OCaml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let rec ajout_mur_droit m (dx,dy) (ax,ay as arrivee) =
       match () with
       | () when dx=ax && dy=ay -> m.(dx).(dy)<-1;
       | () when dx=ax -> 
               m.(dx).(dy)<-1;
               ajout_mur_droit m (dx,dy+1) arrivee;
       | () when dy=ay -> 
               m.(dx).(dy)<-1;
               ajout_mur_droit m (dx+1,dy) arrivee;
       | () -> print_string "Il est pas droit ton mur !!"

    La première bonne pratique en OCaml consiste avant tout à enrichir ton éventail de types.
    Il y a plein de types évolués en OCaml et tu ne les maîtrises sans doute pas encore tous.

    Par exemple (sauf oubli de ma part) je n'ai pas d'exemple de code qui me dise que tu maîtrises bien le type 'a list. L'intérêt du type 'a list c'est que tes match vont forcément devenir beaucoup plus intéressants.
    Du même auteur: mon projet, le dernier article publié, le blog dvp et le jeu vidéo.
    Avant de poser une question je lis les règles du forum.

  6. #6
    Membre actif Avatar de dragonfly
    Profil pro
    Inscrit en
    Janvier 2006
    Messages
    464
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Janvier 2006
    Messages : 464
    Points : 240
    Points
    240
    Par défaut
    OK, je pensais que la récursivité terminale impliquait forcement un appel in ... à la fin, mais au final j'ai plus l'impression qu'elle s'implique sur des trucs du genre du calcul récursif (factorielle, etc...)

    Pour les types 'a list, je commence (sauf erreur de ma part) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    let ajout_point_traj m (dx,dy) = 
       let rec loop_aj_p_tr liste = 
         match liste with
    	 | [] -> ()
    	 | t::q ->
    	    begin
    		  ajout_point m t 2;
    		  loop_aj_p_tr q;
    		end;
         in let listte = [(dx-1,dy);(dx+1, dy); (dx, dy-1); (dx,dy+1)] in
    	 loop_aj_p_tr listte;;
    P.S : C'est sympa le coup de pouvoir vider le match (après tout c'est assez logique au final).

    Je voudrais faire un algo de path finding via Dijkstra donc je pense pouvoir approfondir mon utilisation des différents types.

    En tout cas, je te remercie pour tes conseils (je reviendrais surement avec d'autres questions )

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. EXCEL SOMME.SI avec condition sur des dates
    Par cfhal dans le forum Excel
    Réponses: 7
    Dernier message: 15/10/2007, 08h21
  2. requete avec parametre sur des formulaires
    Par warix dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 12/09/2007, 17h48
  3. Tests unitaires avec vbUnit sur des contrôles utilisateurs
    Par Patrick Mortas dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 07/09/2006, 18h06
  4. requete sql avec between sur des champs de type Date
    Par ersoufiane dans le forum Langage SQL
    Réponses: 2
    Dernier message: 02/08/2006, 19h43
  5. Réponses: 7
    Dernier message: 09/12/2005, 23h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo