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 :

fonction qui modifie ses arguments d'entrée


Sujet :

Caml

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    63
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2007
    Messages : 63
    Points : 54
    Points
    54
    Par défaut fonction qui modifie ses arguments d'entrée
    Bonjour à tous,

    Je voudrais qu'une fonction puisse me modifier plusieurs variables de types différents.

    Je m'explique: j'entre comme argument de ma fonction a et b,
    Pour faire simple, mettons que a soit un int , b une array
    et que ma fonction modifie les 2.

    Ce que je fais usuellement, c'est définir a et b en dehors de la fonction, qui est insérée dans une boucle et je les modifie à chaque passage dans la boucle, par exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     
    let a = ref 0 in
    let b = Array.make 5 0 in
    for i=0 to 100
    do
    let ran = Random.int 5 in
    if b.(ran) == 0 then begin a:=!a+1; b.(ran) <- 1; end
                    else begin a:=!a-1; b.(ran) <- 0; end
    done;;
    Mais là, je compte utiliser ma fonction dans plusieurs parties différentes de mon code.
    Alors j'aimerais qu'elle ne soit pas insérée dans une boucle mais indépendante.
    Donc j'aurais besoin par exemple de pouvoir faire quelque chose équivalent à: je mets a et b en arguments de ma fonction et ils ressortent modifiés.

    C'est possible?

  2. #2
    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
    Si tu donnes une référence en argument à une fonction, et que la fonction modifie cette référence, alors la référence externe sera modifiée elle aussi. Donc oui, c'est possible, il suffit de passer des types modifiables (références ou tableaux par exemple) en paramètre. Attention, si tu passes juste un tableau, tu pourras modifier le contenu des cases, mais pas la taille du tableau. Si tu veux aussi pouvoir le redimensionner il faut passer une référence vers un tableau ('a array ref).

    Cependant, utiliser des effets de bords (modification locale de variables globales dans ton cas) est une très mauvaise pratique. En OCaml, comme dans la plupart des langages fonctionnels, on essaie de modifier les variables le moins possible. Il existe sans doute une solution à ton problème qui n'utilise pas ce genre de choses, et qui est plus jolie/simple/correcte.

    Qu'est-ce que tu veux faire ?

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    63
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2007
    Messages : 63
    Points : 54
    Points
    54
    Par défaut
    ah oui, effectivement, si je fais juste:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    let aux a b=
    for i=0 to 100
    do
    let ran = Random.int 5 in
    if b.(ran) == 0 then begin a:=!a+1; b.(ran) <- 1; end
                    else begin a:=!a-1; b.(ran) <- 0; end
    done;;
     
    let entier =ref 0 in
    let tableau = Array.make 5 0 in
    aux entier tableau;;
    Ca fait ce que je voulais...
    J'aurais quand même du m'en douter
    En tous cas, merci bluestorm.

    Ca m'est difficile d'expliquer dans le détail ce que je veux faire car le code commence à être assez compliqué.

    Disons que je manipule des graphes (type tableau de listes) et que j'effectue des permutations sur les liens de mes graphes, ce qui revient en pratique à retirer un élément de la liste et à en ajouter un autre.

    Pour le coup ça me paraît difficile de ne pas faire ce type de modifs. Peux-tu m'expliquer le risque de ce genre de pratiques?

  4. #4
    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
    Petite note de style : tu devrais indenter correctement ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let aux a b=
      for i=0 to 100 do
        let ran = Random.int 5 in
        if b.(ran) == 0
        then begin a := !a + 1; b.(ran) <- 1 end
        else begin a := !a - 1; b.(ran) <- 0 end
      done;;
    J'ai aussi changé les retour à la ligne autour de for ... do et if..then, mais ça c'est une question de goût, tu fais comme tu sens. Ensuite j'ai enlevé les ";" inutile avant le "end" (; sert à séparer des expressions, pas la peine d'en mettre devant une "parenthèse fermante" puisqu'il n'y a rien à séparer), et mit des espaces autour des symboles infixes (+, =, etc.), parce que "a + !b" marche mais pas "a+!b", donc prudence.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     Pour le coup ça me paraît difficile de ne pas faire ce type de modifs.
    Effectivement dans ce cas (= avec cette représentation des données) tu vas forcément avoir des modifications au niveau du tableau. Par contre, tu n'as pas besoin de références ou quoi pour manipuler les listes. Mais peut-être que pour des permutations des liens, une représentation par matrices d'adjacence serait plus adaptée ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Peux-tu m'expliquer le risque de ce genre de pratiques?
    Quand tu trimballes de variables modifiables d'un endroit à un autre de ton code, il y a des risques qu'elle se retrouve à des endroits où tu ne t'y attends pas, et qu'elle soit modifiée d'une manière que tu n'as pas prévue. Ça donne des bugs parfois particulièrement difficiles à détecter puisqu'ils ne sont pas "locaux", il dépendent de ce que tu fais à des endroits très éloignés de ton programme.

    Un petit exemple, très classique (donc peut-être peu convaincant si tu connais pas), mais qui surprend toujours la première fois :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let len = 3;;
    let mat = Array.make len (Array.make len (0, 0));;
     
    (* poum poum plein de code compliqué *)
     
    for i = 0 to len - 1 do
        for j = 0 to len - 1 do
          mat.(i).(j) <- (i, j)
        done
      done;;
    Le contenu de "mat" ne convient pas.

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    63
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2007
    Messages : 63
    Points : 54
    Points
    54
    Par défaut
    Effectivement dans ce cas (= avec cette représentation des données) tu vas forcément avoir des modifications au niveau du tableau. Par contre, tu n'as pas besoin de références ou quoi pour manipuler les listes. Mais peut-être que pour des permutations des liens, une représentation par matrices d'adjacence serait plus adaptée ?
    En pricipe oui (en fait c'est un graphe biparti, donc tout est au format liste des voisins de i sur la ligne i, qui est le plus naturel à mes yeux).
    Mais maintenant, ça me coûterait trop cher de changer mon format des données pour des matrices d'adjacence.

    Quand tu trimballes de variables modifiables d'un endroit à un autre de ton code, il y a des risques qu'elle se retrouve à des endroits où tu ne t'y attends pas, et qu'elle soit modifiée d'une manière que tu n'as pas prévue. Ça donne des bugs parfois particulièrement difficiles à détecter puisqu'ils ne sont pas "locaux", il dépendent de ce que tu fais à des endroits très éloignés de ton programme.
    Ok, je vois l'idée maintenant.
    C'est curieux d'ailleurs: j'avais déjà fait ce genre l'erreur que tu donnes en exemple (comme quoi...).
    Mais tant que je ne fais pas l'effort de me dire qu'il faut vraiment reprendre depuis le début et reformuler, je continue de me débrouiller avec les petits bouts de codes foireux dont je sais qu'ils marchent à peu près (je ne dois pas être programmeur dans l'âme ).

  6. #6
    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
    En pricipe oui (en fait c'est un graphe biparti, donc tout est au format liste des voisins de i sur la ligne i, qui est le plus naturel à mes yeux).
    Mais maintenant, ça me coûterait trop cher de changer mon format des données pour des matrices d'adjacence.
    À toi de voir, mais si j'ai bien compris tu retires/ajoute souvent des arrêtes de ton graphe, opération qui est linéaire (en le nombre de sommet du noeud) avec des listes d'adjacence, et en temps constant avec une matrice. Ça représente quand même un gain non négligeable (et d'ailleurs, si c'est tellement dur de changer de représentation, c'est que ton code est crade, nah ).

  7. #7
    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
    Tu as oublié le ==. En OCaml, c'est =. Le ==, ça pue vraiment en OCaml, même si le compilateur en est bourré...

    Citation Envoyé par bluestorm Voir le message
    Petite note de style : tu devrais indenter correctement ton code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let aux a b=
      for i=0 to 100 do
        let ran = Random.int 5 in
        if b.(ran) = 0
        then begin a := !a + 1; b.(ran) <- 1 end
        else begin a := !a - 1; b.(ran) <- 0 end
      done;;

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    63
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2007
    Messages : 63
    Points : 54
    Points
    54
    Par défaut
    Tiens à propos, je vois dans la doc que
    if (a == b) est un test d'égalité physique
    if (a = b) un test d'égalité structurelle
    Qu'est-ce que ça veut dire précisément?

    Au passage, bonne année à tous.

  9. #9
    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
    Bonne année

    a == b est le test d'égalité superficielle (comparaison de l'adresse)
    a = b est le test d'égalité profonde (comparaison récursive de la valeur)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    # Some 1 == Some 1;;
    - : bool = false
    # Some 1 = Some 1;;
    - : bool = true

  10. #10
    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
    En pratique c'est important quand tu as des variables mutables : a = b te dit si à un instant, elles ont la même valeur, et a == b te dit qu'elles auront toujours la même valeur (si tu modifies l'une, l'autre change aussi) :

    Code ocaml : 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 a = ref 1;; (* a est une référence *)
    val a : int ref = {contents = 1}
    # let b = ref 1;; (* b une autre référence *)
    val b : int ref = {contents = 1}
    # let c = a;; (* c est la même référence que a *)
    val c : int ref = {contents = 1}
    # a = b;; (* a,b et c sont égales *)
    - : bool = true
    # a == b;; (* a et b ne sont pas physiquement égales *)
    - : bool = false
    # a == c;; (* a et c le sont *)
    - : bool = true
    # a := 2;; (* on modifie a *)
    - : unit = ()
    # !a, !b, !c;;
    - : int * int * int = (2, 1, 2)
    (* la valeur de b n'as pas changé, celle de c si *)

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

Discussions similaires

  1. Création d'une fonction qui prend en argument une liste de cellule
    Par Dereck07 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 29/12/2007, 20h49
  2. fonction qui modifie le margin-left
    Par ipeteivince dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 15/11/2007, 09h40
  3. Fonction qui modifie une chaine de caractère
    Par condor_01 dans le forum Débuter
    Réponses: 7
    Dernier message: 05/11/2007, 18h32
  4. fonction qui modifie les valeurs de combos <select>
    Par NicoO_O dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 16/05/2007, 13h02
  5. Réponses: 11
    Dernier message: 14/10/2006, 21h26

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