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 :

Bonne pratique du type Option


Sujet :

Caml

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 147
    Points : 102
    Points
    102
    Par défaut Bonne pratique du type Option
    Bonjour à tous,

    depuis un moment, je ne sais comment écrire un code en O'Caml. Alors je l'ai écrit d'une façon mais cela ne me semble pas être une bonne pratique.

    Voici comment j'extraie une clé d'une table de hachage en fonction de la valeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    let get_key path_target =
      let key = ref None in 
        Hashtbl.iter (fun wd fi -> if fi.path = path_target then key := (Some wd)) ht_iwatched;
     
        match !key with
          | None -> let err = ("error get_key with "^path_target^" not found") in Report.report (Log err) ; raise No_Result
          | Some k -> k
    ;;
    L'utilisation de ce "ref None" est-elle correcte ? N'y aurait-il pas possibilité de faire autrement ?

    Est-il possible de déclarer une variable à un type bien précis mais sans lui donner de valeur et sans passer par le type Option ?

    Dest.

  2. #2
    Membre éprouvé
    Avatar de Cacophrene
    Homme Profil pro
    Biologiste
    Inscrit en
    Janvier 2009
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Biologiste

    Informations forums :
    Inscription : Janvier 2009
    Messages : 535
    Points : 1 125
    Points
    1 125
    Par défaut
    Bonjour,

    Citation Envoyé par dest
    L'utilisation de ce "ref None" est-elle correcte ? N'y aurait-il pas possibilité de faire autrement ?
    Il faut bien voir que, dans ce code, la fonction Hashtbl.iter n'est pas interrompue par le changement de valeur de la référence. En conséquence, tous les couples (clef, valeur) seront analysés même si le premier est celui que tu cherches. Si tu veux arrêter la recherche dès que la bonne clef est trouvée, tu peux utiliser des exceptions :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    exception Found of string
    
    let get_key path_target =
      try
        Hashtbl.iter (fun wd fi ->
          if fi.path = path_target then raise (Found wd)
        ) ht_iwatched;
        raise Not_found
      with 
      | Found k -> k
      | Not_found -> (* ... *)
    Citation Envoyé par dest
    Est-il possible de déclarer une variable à un type bien précis mais sans lui donner de valeur et sans passer par le type Option ?
    Cela s'appelle un pointeur NULL et ça n'existe pas en Caml. Dès que tu crées une variable, tu dois lui attribuer une valeur, ce qui permet d'inférer tout ou partie (par ex. cas des variables faiblement polymorphes comme '_a option) de son type. Une variable de type connu mais sans valeur associée représente une faille de sécurité non négligeable... car on finit tous, tôt ou tard, par oublier de l'initialiser avant de s'en servir.

    Cordialement,
    Cacophrène

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 147
    Points : 102
    Points
    102
    Par défaut
    Bonjour Cacophrène,
    merci pour le conseil pour interrompre la table de Hachage.

    Concernant le pointeur NULL, je me doutais de ce que tu allais dire. Aurais-tu un projet à me conseiller où je puisse lire du code accessible ? En fait, je pense que j'ai besoin de lire du code pour avancer dans mes problématiques.

  4. #4
    Membre éprouvé
    Avatar de Cacophrene
    Homme Profil pro
    Biologiste
    Inscrit en
    Janvier 2009
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Biologiste

    Informations forums :
    Inscription : Janvier 2009
    Messages : 535
    Points : 1 125
    Points
    1 125
    Par défaut
    Bonsoir,

    Citation Envoyé par dest
    Concernant le pointeur NULL, je me doutais de ce que tu allais dire. Aurais-tu un projet à me conseiller où je puisse lire du code accessible ? En fait, je pense que j'ai besoin de lire du code pour avancer dans mes problématiques.
    C'est toujours un peu difficile de lire le code des autres. Je ne sais pas exactement dans quel domaine tu codes mais peut-être qu'il y a des choses intéressantes sur la bosse Caml. Mais essayer de résoudre soi-même des problèmes et demander de l'aide quand on bute est déjà une excellente école.

    Cordialement,
    Cacophrène

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 147
    Points : 102
    Points
    102
    Par défaut
    Citation Envoyé par Cacophrene Voir le message
    Bonsoir,


    C'est toujours un peu difficile de lire le code des autres. Je ne sais pas exactement dans quel domaine tu codes mais peut-être qu'il y a des choses intéressantes sur la bosse Caml. Mais essayer de résoudre soi-même des problèmes et demander de l'aide quand on bute est déjà une excellente école.

    Cordialement,
    Cacophrène
    En fait, je développe un petit programme qui fonctionne pour remplir un besoin perso mais j'aimerais m'inspirer de programmes déjà existants pour corriger à la fois la structure du code (bonne pratique de rédaction de codes), corriger des idées mal conçues, ...

    Bien que la programme fonctionne, ce n'est pas suffisant. J'aimerais m'améliorer, moi. Et pour cela, j'ai besoin de me confronter à l'existant.
    Je ne sais pas si c'est clair.
    En fait, je pourrais probablement partiellement obtenir ce que je cherche si c'était du dev collaboratif mais je suis seul.

  6. #6
    Membre éprouvé
    Avatar de InOCamlWeTrust
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 036
    Points : 1 284
    Points
    1 284
    Par défaut
    Dans l'existant, il y a de tout et surtout du mauvais. La meilleure façon de programmer en OCaml, c'est de rester simple. Pas de fioritures, pas d'identificateurs de trop, pas de lignes ne servant à rien. Et surtout un usage très modéré des exceptions.
    When Colt produced the first practical repeating handgun, it gave rise to the saying God created men, but Colt made them equal.

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    147
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 147
    Points : 102
    Points
    102
    Par défaut
    Citation Envoyé par InOCamlWeTrust Voir le message
    Dans l'existant, il y a de tout et surtout du mauvais. La meilleure façon de programmer en OCaml, c'est de rester simple. Pas de fioritures, pas d'identificateurs de trop, pas de lignes ne servant à rien. Et surtout un usage très modéré des exceptions.
    Salut IOWT,

    c'est justement parce que je suis convaincu de faire du mauvais que je souhaite m'améliorer. Et puis même dans des programmes dit mauvais, je peux y trouver des choses intéressantes.

  8. #8
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Bonsoir,

    Je n'utilise pas OCaml mais la curiosité me pousse à poser cette question:

    N'y a-t-il pas moyen de s'en sortir sans itérations inutiles ET sans utiliser les exceptions, ce qui pour moi ressemble à un "hack" (ce que semble confirmer la remarque de IOCWT) ?

    En Haskell, la paresse ferait que le problème ne se pose même pas, mais je suppose que ce n'est pas applicable en OCaml ?

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    Je ne pense pas que l'utilisation des exceptions soit un hack. Les exceptions ont précisément cet effet sur le flôt de contrôle, qui permet la terminaison prématurée d'une évaluation, donc il n'est pas du tout illogique de l'utiliser dans ce cadre.

    C'est même assez idiomatique en Caml, en tout cas chez une partie des utilisateurs Caml. L'important c'est que ce soit bien clair et qu'il n'y ait pas de confusion avec l'autre rôle des exceptions, à savoir signaler les situations erronées et/ou exceptionnelles. Pour cela, quelques conseils :
    - utiliser une exception qui n'a pas un nom d'erreur (on évite Out_of_memory, Failure ...); j'utilise toujours Exit quand c'est pour du flot de contrôle
    - faire ce genre de choses le plus localement possible : éviter que l'exception flôt-de-contrôle passe par un appel d'une fonction qui n'est pas déclarée localement : en gros il faut toujours que le(s) "raise" soit syntaxiquementre entre "try" et "with"

    Si tu veux une méthode d'itération qui soit pensée pour être interruptible (sans exceptions ni continuations), il ne faut pas utiliser la fonction `iter`, mais une autre pensée pour permettre la terminaison. Par exemple, avec la signature suivante, et qui s'arrête dès que la fonction d'itération renvoie `false`:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    val terminable_iter : ('a -> bool) -> 'a t -> unit

  10. #10
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    Citation Envoyé par dividee Voir le message
    N'y a-t-il pas moyen de s'en sortir sans itérations inutiles ET sans utiliser les exceptions, ce qui pour moi ressemble à un "hack" (ce que semble confirmer la remarque de IOCWT) ?
    Non.

    Si les choses étaient bien faites, il y aurait d'autres fonctions disponibles. Hélas, le module Hashtbl (comme beaucoup d'autres) de Caml est extrêmement pauvre.

    [Edit] Je trouve ça dommage d'être obligé de passer par une exception ici. Mais sinon, je suis d'accord avec Bluestorm. Les exceptions ne sont pas moches et s'intègrent bien à Caml (mieux même que dans la plupart des autres langages).

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    Pour ce genre de choses (que l'on peut implémenter de façon efficace sans casser l'abstraction du module) il est facile d'étendre le module Hashtbl avec le comportement que tu veux.

    Code pas testé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    module MyHashtbl = struct
      include Hashtbl
      exception Terminate
      let terminable_iter f t =
        try iter (fun x -> if not f x then raise Terminate) t
        with Terminate -> ()
    end

  12. #12
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Merci bluestorm & LLB.

    Cela m'aide à comprendre le style de programmation en OCaml et les compromis qu'il faut envisager.

  13. #13
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    309
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 309
    Points : 928
    Points
    928
    Par défaut
    J'ajouterai qu'en plus, les exceptions sont très efficace en caml. Donc pas de soucis de ce coté là.

  14. #14
    Membre éprouvé
    Avatar de InOCamlWeTrust
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 036
    Points : 1 284
    Points
    1 284
    Par défaut
    Citation Envoyé par TropMDR Voir le message
    J'ajouterai qu'en plus, les exceptions sont très efficace en caml. Donc pas de soucis de ce coté là.
    Justement non. Le facteur est relativement énorme, du genre x10 ou x20.

    Je me souviens d'un test effectué avec mes AVL et la fonction de recherche d'un élément dans l'un de ces arbres, une fonction de même comportement que l'horrible super cradosse déguelis find de Map, puis l'utilisation conjointe de deux fonctions, l'une testant la présence et l'autre la première évoquée, le clone de find. Le résultat était sans appel, y compris avec ce mauvais algorithme. Le plus simple, serait d'implanter un find qui retourne un 'a option, ce qui permettrait une programmation plus fine. Les exceptions, ce ne sont en fait que de mauvais goto déguisés.
    When Colt produced the first practical repeating handgun, it gave rise to the saying God created men, but Colt made them equal.

  15. #15
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    Ça me semble assez curieux, normalement le coût d'un raise est de l'ordre de celui d'un appel de fonction. Je pense que c'est plutôt une erreur spécifique au code que tu as écris (par exemple est-ce que tu as cassé la tail-récursivité avec ton try..with ?) ou alors peut-être une question d'options de compilation (c'est peut-être plus couteux en bytecode, et si tu lances avec les options de debugging, il y a peut-être un coût supplémentaire lié aux backtraces).

    Bref, je pense que cette observation ne devrait pas être généralisée. De toute façon ce ne sont pas les performances qui gouvernent mes choix en général.

  16. #16
    LLB
    LLB est déconnecté
    Membre expérimenté
    Inscrit en
    Mars 2002
    Messages
    967
    Détails du profil
    Informations forums :
    Inscription : Mars 2002
    Messages : 967
    Points : 1 410
    Points
    1 410
    Par défaut
    J'avais fait des tests de performance des exceptions dans plusieurs langages. En Caml, c'était bien plus rapide que les autres, plus qu'en C++ (compilé avec g++). Mon test était peut-être biaisé, mais c'était aussi rapide que du code sans exception.

    Évidemment, si la backtrace est activée, ça peut changer beaucoup de choses... (ça expliquerait le facteur 10)

  17. #17
    Membre habitué
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2009
    Messages : 128
    Points : 146
    Points
    146
    Par défaut
    Je suis assez d'accord avec IOWT pour dire que l'usage qui est fait des exceptions d'OCaml ressemblent souvent à des GOTO travestis en quelque chose qui se voudrait présentable...

    Mais pour en revenir à la question d'origine, utiliser une exception Found est une solution utilisée couramment en OCaml et il ne faut pas forcément chercher à être trop perfectionniste, parfois une solution impérative mais avec un code très simple et localisé peut être tout à fait acceptable, et c'est pour ça qu'OCaml est un langage fonctionnel impur.
    Cependant dest, puisque ta question est de chercher à t'améliorer je formulerais la remarque suivante. En principe une table de hachage est une structure de donnée d'où on est sensé récupérer les éléments par leur clé. Si tu te retrouves dans la situation où tu recherches un élément par sa valeur associée, il s'agit peut-être d'un signe indiquant que tu ne résous pas le problème de la bonne manière. Mais pour être sûr de çà et être plus précis il faudrait avoir plus d'éléments.

    Aussi pour s'améliorer lire du code tiers n'est pas une mauvaise idée. Même s'il y a du bon et du mauvais je pense que n'importe qui qui lit le code d'autrui est capable d'avoir un regard critique. D'autre part l'utilisation de l'exception Found est quelque chose qu'on peut trouver en lisant du code référencé sur le Hump.

  18. #18
    Membre éprouvé
    Avatar de Cacophrene
    Homme Profil pro
    Biologiste
    Inscrit en
    Janvier 2009
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Biologiste

    Informations forums :
    Inscription : Janvier 2009
    Messages : 535
    Points : 1 125
    Points
    1 125
    Par défaut
    Bonsoir tout le monde,

    Je me range du côté de bluestorm et adtunum : il faut savoir transiger avec son code comme avec tout autre chose. Je préfère passer 90% de mon temps sur les 10% du code qui méritent vraiment d'être travaillés et retravaillés encore, quitte à les repenser une bonne dizaine de fois, et traiter les 90% restants pour ce qu'ils sont : de l'enrobage. Mais attention : je ne dis pas qu'il faut tout se permettre pour autant. Naturellement il y a une limite entre « vite » et « mal » que je ne souhaite pas franchir.

    Cordialement,
    Cacophrène

  19. #19
    Membre éprouvé
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    832
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 832
    Points : 1 104
    Points
    1 104
    Par défaut
    Citation Envoyé par adtunum
    Je suis assez d'accord avec IOWT pour dire que l'usage qui est fait des exceptions d'OCaml ressemblent souvent à des GOTO travestis en quelque chose qui se voudrait présentable...
    Oui, mais on peut aussi dire ça des appels terminaux, des continuations ou bien de la simple récursion.
    Tout cela n'est qu'une manière de gérer le flôt de contrôle. Il faut éviter si possible d'avoir un flôt de contrôle plus compliqué que ce que requiert l'application, mais parfois on en a besoin, on n'a pas le choix et il faut s'y mettre (et à ce moment là que ce soit fait avec des exceptions, des flags booléens, call/cc ou un goto ne changera pas grand chose).
    Ce qui est vrai c'est qu'il est intéressant de factoriser les flots de contrôles les plus courants en des fonctions d'ordre supérieur réutilisables, comme fold_left, fold_right et compagnie.
    Dans la même veine, avoir une version interruptible des fonctions d'itération serait une bonne chose, mais en attendant, si on peut les recoder avec une primitive de flôt de contrôle plus puissante, ça ne peut être qu'un plus.

    Donc oui, les exceptions c'est comme GOTO ou la récursivité : il faut éviter de les utiliser pour faire les choses simples pour lesquelles des outils moins puissants suffisent, mais il y a aussi des cas où on ne peut pas facilement faire autrement (par manque d'outils adaptés) et c'est alors la manière la plus simple et la plus claire d'écrire le code.

  20. #20
    Membre éprouvé
    Avatar de InOCamlWeTrust
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    1 036
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 1 036
    Points : 1 284
    Points
    1 284
    Par défaut
    Citation Envoyé par bluestorm Voir le message
    Ça me semble assez curieux, normalement le coût d'un raise est de l'ordre de celui d'un appel de fonction. Je pense que c'est plutôt une erreur spécifique au code que tu as écris (par exemple est-ce que tu as cassé la tail-récursivité avec ton try..with ?)
    Le raise tout comme le try sont relativement coûteux, puisqu'ils demandent une sauvegarde et une restauration de l'environnement d'exécution, un peu à la manière de getenv() et setenv() en C et leurs appels plus bas niveau. Le code était bien-sûr compilé à l'époque en natif grâce à ocamlopt.

    Une exception porte bien son nom, EXCEPTION, et doit donc être utilisée de façon exceptionnelle pour rompre un flot d'exécution lors de la survenue d'un évènement exceptionnel. Ne pas trouver une valeur dans une table de hachage, ça n'a rien d'exceptionnel. Une simple fonction find retournant None lorsqu'il n'y a pas d'association ou Some e lorsqu'il y en a une est 1 000 fois plus propre et beaucoup plus efficace.
    When Colt produced the first practical repeating handgun, it gave rise to the saying God created men, but Colt made them equal.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Bonnes pratiques de protections individuelles
    Par Community Management dans le forum Sécurité
    Réponses: 22
    Dernier message: 05/04/2013, 12h47
  2. Réponses: 7
    Dernier message: 02/11/2005, 16h30
  3. [Bonne pratique]Stratégie d'allocation
    Par jowo dans le forum C
    Réponses: 1
    Dernier message: 05/10/2005, 15h47
  4. [FOREIGN K] Valeur de champ = nom de table. Bonne pratique ?
    Par Seb des Monts dans le forum Langage SQL
    Réponses: 9
    Dernier message: 17/05/2005, 11h56

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