• [^] # Re: ouai

    Posté par (site web personnel) . En réponse au journal Données vs Code. Évalué à 5.

    Je ne vois pas bien la différence entre un type fantôme et un type (mais te fatigue pas je pense qu'il faudrait que je manipule tout ça pour commencer à comprendre _).

    Je te propose un exemple simple (celui avec lequel j'avais compris le concept).

    Imagine que tu ais deux tables :

    create table T1(idt1 text, lbl1 text);
    create table T2(idt2 text, lbl2 text);

    Tu veux faire un mapping sur ces deux tables, avec chacune une structure

    type t1 = {
    idt1 : string;
    lbl1 : string;
    }
    type t2 = {
    idt2 : string;
    lbl2 : string;
    }

    Le genre de problème qui m'est arrivé, c'est quand tu vas chercher une ligne de ta table, avec un select, tes données pour hydrater ta structure : tu est fatigué, tu fais pas attention et tu intervertis idt1 et lbl1.
    Erreur d'étourderie classique qui arrive à tout le monde.
    Comme c'est deux chaînes, tu te retrouves avec un bug 4 kilomètres plus loin, et tu cherches longtemps avant de trouver.
    <troll>Et là, tu te retrouves au moyen-âge, comme quand tu faisais du java</troll>

    La solution, c'est d'utiliser un phantom type :

    Si tout était simple, on pourrait faire ça, car c'est l'idée

    type id
    type lbl
    type 'a champBase = string

    Mais le compilateur reconnait que les id champBase et lbl champBase, c'est la même chose
    Donc, on le force :

    module T : sig
    (*on défini nos types spécialisés*)
     type id
     type lbl
     (*on devra passer par ces fonctions pour créer les chaines typées. *)
     val makeid : string -> id 
     val makelbl : string -> lbl 
     val fromid : id -> string
     val fromlbl : lbl -> string
    end = struct
     (*Nous sommes dans l'implémentation du module, on défini que nos types particuliers sont des chaînes*)
     type id = string
     type lbl = string
     (*la définition de type dans la signature nous garantie que l'on renvoi bien un type T, alors que l'implémentation est une bête fonction identité*)
     let makeid s = s
     let makelbl s = s
     let fromid s = s
     let fromlbl s = s
    end;;

    Du coup tu définis tes deux types avec

    type t1 = {
    idt1 : T.id ;
    lbl1 : T.lbl;
    }
    type t2 = {
    idt2 : T.id ;
    lbl2 : T.lbl;
    }

    Tu peux définir ta structure en utilisant les phantom-type

    { idt1 = T.makeid "456s" ; lbl1 = T.makelbl "456" };;

    Et voilà, tu es forcé par le compilateur de ne pas te tromper.
    C'est un peu chiant et lourd, mais ça évite plain de problèmes, car chaque chaîne est à sa place

    « Il n’y a pas de choix démocratiques contre les Traités européens » - Jean-Claude Junker