• [^] # Re: ouai

    Posté par . En réponse au journal Données vs Code. Évalué à 3. Dernière modification le 29 mars 2016 à 14:36.

    C'est ça ! C'est exactement la même "opacification" du type que l'on retrouve en POO classique avec ses "classes".

    Maintenant OCaml a aussi un système d'objet qui a un typage autrement plus complexe. Il vaut a lui seul le détour ;-) Par exemple, il n'y a pas de classe au sens POO du terme (=type) mais bien une correspondance par typage réel des méthodes avec évidemment une possibilité d'opacifier la représentation concrète si on veut.

    Donc bref une troisième solution serait d'utiliser les objets immédiats, qui nous affranchi du "problème" de pattern-matching de la solutions avec les types variants. Par exemple, avec des objets immédiats là on peut avoir un objet "validé" qui peut être utilisé à la plasse de l'objet non-validé sans devoir modifier le code utilisateur.

    let make_obj i = object val _v = i method get = i end;;
    (* val make_obj : 'a -> < get : 'a > = <fun> *)
    let make_validator f i = object(self) val _v = i#get method validate = if f _v then _v else failwith "invalid" method get = self#validate end;;
    (* val make_validator : ('a -> bool) -> < get : 'a; .. > -> < get : 'a; validate : 'a > = <fun> *)
    let use_string o = (o#get : string);;
    (* val use_string : < get : bytes; .. > -> bytes = <fun> *)
    let use_validable_string o = (o#validate:string);;
    (* val use_validable_string : < validate : bytes; .. > -> bytes = <fun> *)
    (* un validated_string peut être utilisé pour un string *)
    use_string (make_validator (fun _ -> true) (make_obj "password"));;
    (* - : bytes = "password" *)

    Note que j'utilise la méthode "validate" pour discriminer un objet validable, donc si j'oublie d'appeller validate je ne me rendrai pas compte que j'utilise le mauvais type... Note aussi que la solution reste polymorphique donc que tu peux construire n'importe quel type d'objet avec make_validator.

    Une autre solution c'est d'utilise les classes ocaml, qui ne sont pas encore tout à fait des classes au sens POO du terme mais qui permette de discriminer avec une contrainte de type (de nouveau, si on oublie cette annotation, ben ça ne sert à rien... le compilo ne peut pas se mettre à deviner ce que tu veux faire non plus :p). Je crois que c'est ce qui se rapproche le plus que ce que tu a demandé.

    class ['a] base i = object method get = (i:'a) end;;
    class ['a] validated f i = let _ = if not (f i) then failwith "invalid" in object inherit ['a] base i end;;
    let make_valid f o = new validated f o#get;;
    let use_valid_string (o : string #validated) = o#get;;
    let use_any_string o = print_endline o#get;;
    use_any_string (make_valid (fun _ -> false) (new base "god"));;
    (* Exception: Failure "invalid" *)

    Note que cela reste tout à fait polymorphique comme solution :)

    (Il y peut-être encore une solution possible avec les gadt pour émuler les types classes d'haskell mais cela dépasse mon niveau de compétence là...)