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 :

Appliquer une fonction à chaque constructeur d'un Type


Sujet :

Caml

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 9
    Points : 5
    Points
    5
    Par défaut Appliquer une fonction à chaque constructeur d'un Type
    Hello,
    Je vous passe directement mon sujet de partiel que j'ai foiré :
    http://imageshack.com/a/img855/3821/74is.png

    Donc, j'ai quelque peu réessayé de le faire en préparation de mes rattrapages.
    Pour l'Exercice 1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let conversion x = match x with
    	|(Gram n) -> (Cuiller (n/15))
    	|(Cuiller n) -> (Gram (n*15));;
     
    conversion (Gram 100);;
    Pour l'Exercice 2 :
    Les fonctions :

    prod:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let prod y x = match y with
    	|(Gram n) -> Gram (n*x)
    	|(Cuiller n) -> Cuiller (n*x);;
    divi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let divi y x = match y with
    	|(Gram n) -> Gram (n/x)
    	|(Cuiller n) -> Cuiller (n/x);;
    add :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let rec add x y = match x with
    	|(Gram n1) -> (match y with
    			|(Gram n2) -> (Gram (n1+n2))
    			|(Cuiller n2) -> add (Gram n1) (conversion (Cuiller n2)))
    	|(Cuiller n1) -> (match y with
    			|(Gram n2) -> add (conversion (Cuiller n1)) (Gram n2)
    			|(Cuiller n2) -> add (conversion(Cuiller n1)) (conversion (Cuiller n2)));;
    Déjà j’aimerais savoir si c'est bon ce que j'ai fait, car je suis parti à l'aveuglette, ne sachant pas comment utiliser les types.

    Pour l'Exercice 3, ça coince, on me demande d'appliquer une fonction (sûrement les fonctions "prod" et "divi") sur des éléments de type "t_recette".
    D'après ce que j'ai compris, si on se base sur le sujet, la recette mise en paramètre est une recette pour 6 personnes. On devra donc créer une fonction qui aura en paramètres une recette de type "t_recette" ainsi qu'un nombre. On devra prendre chaque constructeur de cette recette et le diviser par 6 (grâce à la fonction citée précédemment "divi") pour en faire une recette pour une personne. Puis on devra le multiplier par le nombre défini (grâce à la fonction "prod" cette fois-ci) en paramètre pour en faire une recette pour "n" personnes.
    De ce côté la, je pense avoir compris ce qu'on nous demande.
    Le problème c'est : Comment-faire, déjà pour créer une fonction qui admet comme arguments une recette de type t_recette ? Ensuite comment fera t'on pour appliquer ces deux fonctions (prod et divi) à chaque constructeur ?

  2. #2
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Bon, premièrement ta fonction de conversion fait le contraire de ce qu'indique le texte (tu fait 1 cuillère = 15 gr, alors que le texte dit 1 gr = 15 cuillères) mais cela semble plus raisonnable...

    Ta fonction add construit des tas de valeurs inutiles (Cuiller n2) est juste y par exemple et peut être abrégé en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    let rec add x y = match x with
    	|(Gram n1) -> (match y with
    			|(Gram n2) -> (Gram (n1+n2))
    			|_ -> add x (conversion y)
    	|(Cuiller _) -> add (conversion x) y
    Ou peut-être même :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    let rec add x y = match (x,y) with
    	|(Gram n1, Gram n2) -> (Gram (n1+n2))
            |(Gram _, _) -> add x (conversion y)
    	|(Cuiller _, _) -> add (conversion x) y
    Pour ce qui est de la suite, je te donne un exemple qui crée juste un record au contenu identique à l'original à toi de le modifier :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pour_n recette = {farine = recette.farine; sucre = recette.sucre; beurre = recette.beurre; oeuf  = recette.oeuf; sel = recette.sel; arome = recette.arome}
    ou tu peux faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pour_n {farine=f; sucre=su; beurre=b; oeuf=o; sel=se; arome=(nom,qte)} = {farine = f; sucre = su; beurre = b; oeuf  = o; sel = se; arome = (nom,qte)}
    --
    Jedaï

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Bah moi qui partait dans des grands match ... with, je suis déçu.

    J'ai compris qu'il n'y avait rien de compliqué en fait.
    J'avais un peu de mal autour des entiers, qu'il fallait convertir en float pour multiplier et diviser, et transformer le tout en entier.
    J'ai aussi fait une petite fonction pour le string*int, pour ne pas trop blinder la fonction principale. Pour ce qui est des optimisations, c'est pas trop mon fort, ça viendra sûrement avec le temps.
    Enfin bref, voilà la fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let prod_arome (x,y) z = (x,(int_of_float (((float_of_int y)/.6.)*.z)));;
     
    let pour_n re np = {farine = (prod (divi (re.farine) 6) np); sucre = (prod (divi (re.sucre) 6) np) ; beurre = (prod (divi (re.beurre) 6) np) ; oeuf = int_of_float (((float_of_int re.oeuf)/.6.)*.(float_of_int np)) ; sel = (prod (divi (re.sel) 6) np) ; arome = prod_arome (re.arome) (float_of_int np)};;
    J'ai aussi modifié la fonction add, effectivement je me suis compliqué la vie pour rien.
    Dit moi si quelque chose cloche, si j'en ai fait trop avec les float_of_int et int_of_float. Dans tous les cas, ma fonction... fonctionne, c'est tout ce qu'on lui demande. C'est juste histoire de gagner un peu de temps et ne pas trop se prendre la tête qu'on essaye de l'optimiser
    Merci encore pour l'aide personnalisée !

    Bon, question suivante !

  4. #4
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Note que si j'avais réellement une fonction type add à implémenter... Je ferais plutôt ça (même si la réutilisation de conversion est tentante dans le contexte d'un partiel) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    add x y = 
      let from_mass = function | Gram n -> n | Cuiller n -> n*15
      in Gram (from_mass x + from_mass y)
    Pour ce qui est de pour_n, tu devrais vraiment éviter de te répéter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    pour_n {farine=f; sucre=su; beurre=b; oeuf=o; sel=se; arome=(nom,qte)} n = 
      let chgMass m = divi (prod m n) 6
      and chgInt i = int_of_float (float_of_int i *. float_of_int n /. 6)
      in {farine = chgMass f; sucre = chgMass su; beurre = chgMass b; oeuf  = chgInt o; sel = chgMass se; arome = (nom, chgInt qte)}
    Sinon, ça a l'air pas mal, il te reste juste les deux questions finales.
    --
    Jedaï

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Hello,
    pour ce qui est de la fonction add, si on nous demande de créer des fonctions, ce n'est sûrement pas pour le plaisir, mais bien pour nous guider pour la suite. Enfin c'est ce que je pense, il est vrai que ton code est BEAUCOUP plus propre comme cela, mais on est pas encore arrivés à ce stade en cours
    En tout cas, en écrivant ces lignes, je viens de me rendre compte que, effectivement, peut-être fallait-il que j'utilise cette fonction add dans la dernière question. Ce que je n'ai pas fait.

    Bon pour ce qui est de la question 4 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let sansb l =
    let rec aux acc l = match l with
    	|[] -> acc
    	|h::t -> if (test h) then aux (acc@[h]) t
    	                     else aux acc t
    and test re = re.beurre = (Gram 0) or re.beurre = (Cuiller 0)
    in aux [] l ;;
    Et de la question 5 (qu'il faudra sûrement que je racourcisse, car je me répète trop) :

    Une première fonction pour transformer un type t_masse (_ n) en n (float)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    let rec m_to_float x = match x with
    	|(Gram n) -> float_of_int n
    	|(Cuiller n) -> m_to_float (conversion (Cuiller n));;
    Quatre autres pour chaque moyenne :
    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
    20
    21
    22
    23
    let moyenF l =
    let rec aux acc1 acc2 l = match l with
    	|[] -> acc1/.acc2
    	|h::t -> aux (acc1+.(m_to_float h.farine)) (acc2+.1.) t
    in aux 0. 0. l;;
     
    let moyenS l =
    let rec aux acc1 acc2 l = match l with
    	|[] -> acc1/.acc2
    	|h::t -> aux (acc1+.(m_to_float h.sucre)) (acc2+.1.) t
    in aux 0. 0. l;;
     
    let moyenB l =
    let rec aux acc1 acc2 l = match l with
    	|[] -> acc1/.acc2
    	|h::t -> aux (acc1+.(m_to_float h.beurre)) (acc2+.1.) t
    in aux 0. 0. l;;
     
    let moyenO l =
    let rec aux acc1 acc2 l = match l with
    	|[] -> acc1/.acc2
    	|h::t -> aux (acc1+.(float_of_int h.oeuf)) (acc2+.1.) t
    in aux 0. 0. l;;
    Et la dernière qui mélange le tout et qui me sort les moyennes de farine, de sucre, de beurre et d’œufs dans un quadruplé (je viens de douter, mais en fait non, on me demande bien un quadruplé de réels) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let moyen r = (moyenF r, moyenS r, moyenB r, moyenO r);;
    En sortie, j'ai donc un quadruplé de réels qui correspondent aux moyennes demandées. Donc je pense en avoir fini avec ce grand exercice.
    Je reviendrais si j'ai encore des soucis. Encore merci !

  6. #6
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let sansb l =
    let rec aux acc l = match l with
    	|[] -> acc
    	|h::t -> if (test h) then aux (acc@[h]) t
    	                     else aux acc t
    and test re = re.beurre = (Gram 0) or re.beurre = (Cuiller 0)
    in aux [] l ;;
    Évite absolument d'accumuler en ajoutant à la fin d'une liste (acc@[h]), surtout des éléments uniques... Tu passes d'une complexité de O(n) à O(n²) car chaque ajout en fin de liste est de l'ordre de O(n) (pour une liste de longueur n).

    Deux façon d'éviter cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let sansb rs =
      let rec aux acc rs = 
        match rs with
        |[] -> acc
        |h::t -> if test h 
    	     then aux (h :: acc) t
    	     else aux acc t
      and test re = re.beurre = (Gram 0) or re.beurre = (Cuiller 0)
      in List.rev (aux [] rs)
    Cela peut apparaître du gâchis de renverser la liste à la fin ainsi, mais c'est bien mieux que ta solution, au moins on reste en O(n). De plus cette solution reste "tail-recursive" et donc s'exécute en espace constant sur la pile. Si cette dernière considération n'est pas importante (liste courte, du moins par rapport à l'espace disponible sur la pile) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    let sansb' rs =
      let rec aux rs = 
        match rs with
        |[] -> []
        |h::t -> if test h 
    	     then h :: aux t
    	     else aux t
      and test re = re.beurre = (Gram 0) or re.beurre = (Cuiller 0)
      in aux rs
    Par ailleurs si tu as droit à tes fonctions standard, il s'agit simplement de filtrer la liste :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    let sansb rs = let test {beurre=b} = b = Gram 0 or b = Cuiller 0 in List.filter test rs

    Pour ce qui est des moyennes, tu vois toi-même que tu te répètes, tes 4 fonctions sont quasiment identiques ! A quoi bon utiliser un langage expressif comme OCaml si tu n'utilises pas ses capacités pour éviter de te répéter inutilement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    let moyen extract rs =
      let rec aux accValue accLen rs = match rs with
        |[] -> accValue /. accLen
        |h::t -> aux (accValue +. m_to_float (extract h)) (accLen +. 1.) t
      in aux 0. 0. rs
     
    let moyenF rs = moyen (fun r -> r.farine) rs
    J'en ai profité pour améliorer un peu les noms employés (en particulier pour les accumulateurs, pour éviter la confusion, ils ont le même type...) et évite "l" comme nom de variable, ça ressemble beaucoup trop à "1" dans beaucoup de polices. Une convention peut-être de donner un nom aux éléments (comme r ici pour une recette) et d'y rajouter un "s" pour les listes de ces éléments.

    Bonne chance pour ton examen final.

    --
    Jedaï

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2014
    Messages
    9
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2014
    Messages : 9
    Points : 5
    Points
    5
    Par défaut
    Merci beaucoup pour ces améliorations. Effectivement j'étais tellement pressé de passer a autre chose que j'ai choisi la voie de la facilité en copiant et en collant. Je ne referais plus la même erreur.
    En tout cas, l'examen final est dans quelques heures. Et pour l'instant la seule chose que je redoute c'est que ça sera sur feuille et non sur PC. Du coup pas le droit a l'erreur quant aux types. Le pc ne sera pas derrière moi pour me corriger.
    Mais franchement, si personne ne m'avait aidé ça ne serait pas le seul problème donc merci encore une fois. Je repasserais à l'occasion. Bonne journée.

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 03/07/2007, 15h03
  2. Réponses: 3
    Dernier message: 08/06/2007, 14h09
  3. appliquer une fonction à toutes les balises <a>
    Par trotters213 dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 30/10/2006, 17h49
  4. [MySQL] Appliquer une fonction sur un champ lors d'une requête
    Par Jérémy197 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 13/08/2006, 14h29
  5. Peut-on appliquer une fonction sur un champs ajouté?
    Par tinwul dans le forum MS SQL Server
    Réponses: 7
    Dernier message: 31/05/2006, 18h02

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