2017-09-08 5 views
1

je les suivantes:Y compris un module engloutit son type

Un type de module Person avec des méthodes pour obtenir le nom et prénom:

module type Person = sig 
    type t 
    val first : t -> string 
    val last : t -> string 
end 

Un foncteur PersonUtils d'étendre Person avec une fonction name:

module PersonUtils (Person: Person) : sig 
    type t 
    val name : t -> string 
end = struct 
    include Person 
    let name p = Person.first p^" "^Person.last p 
end 

et un module Main comme suit:

module Main : sig 
    type t 
    val name : t -> string 
end = struct 
    include PersonUtils(struct 
     type t = { 
     first: string; 
     last: string; 
     } 

     let first p = p.first 
     let last p = p.last 
    end) 
end 

En Main, je voudrais ajouter une fonction loud_first_name supplémentaire: donc j'ajouter ce qui suit à la signature et le module:

module Main : sig 
    type t 
    val name : t -> string 

    (* New *) 
    val loud_first_name : t -> string 
end = struct 
    include PersonUtils(struct 
     type t = { 
     first: string; 
     last: string; 
     } 

     let first p = p.first 
     let last p = p.last 
    end) 

    (* New *) 
    let loud_first_name p = String.uppercase p.first 
end 

Cependant, il semble que loud_first_name ne sait plus la structure de mon tapez t, donc je suis à gauche avec l'erreur Unbound record field first.

Ma question est: comment puis-je créer des méthodes telles que loud_first_name afin qu'ils puissent toujours accéder à mes champs d'enregistrement? J'ai essayé de déplacer mon niveau t, mais j'ai eu du mal à l'utiliser dans l'argument de mon foncteur.

module Main : sig 
    type t 
    val name : t -> string 
    val loud_first_name : t -> string 
end = struct 
    type t_ = { 
    first: string; 
    last: string; 
    } 

    include PersonUtils(struct 
     type t = t_ 

     let first p = p.first 
     let last p = p.last 
    end) 

    (* Signature mismatch: 
     ... 
     Values do not match: 
     val loud_first_name : t_ -> string 
     is not included in 
     val loud_first_name : t -> string 
    *) 
    let loud_first_name p = String.uppercase p.first 
end 

Répondre

1

On dirait une combinaison de type nonrec t = t (grâce Étienne Millon) et comprenant le module avec une signature a corrigé mon problème.

module type PUSig = sig 
    type t 
    val name : t -> string 
end 

module PersonUtils (Person: Person) : PUSig with type t = Person.t = struct 
    include Person 
    let name p = Person.first p^" "^Person.last p 
end 

module Main : sig 
    type t = { 
    first: string; 
    last: string; 
    } 
    val loud_first_name : t -> string 
end = struct 
    type t = { 
    first: string; 
    last: string; 
    } 

    include (PersonUtils(struct 
      type nonrec t = t 
      let first p = p.first 
      let last p = p.last 
      end) : PUSig with type t := t) 

    (* New *) 
    let loud_first_name p = String.uppercase_ascii p.first 
end 
0

Vous devez indiquer dans votre signature que votre type est le même, si vous ne l'indiquer dans la structure, les informations seront perdues.

module PersonUtils (Person: Person) : sig 
    type t = Person.t 
    val name : t -> string 
end 
= struct 
    include Person 
    let name p = Person.first p^" "^Person.last p 
end 

Une autre approche (wich je recommande) est d'ajouter une clause with à votre déclaration de type de module.

module PersonUtils (Person: Person) : sig 
    type t 
    val name : t -> string 
end 
with type t = Person.t 
= struct 
    include Person 
    let name p = Person.first p^" "^Person.last p 
end 

Bien que les informations ne sont pas directement visibles dans la déclaration de la signature, il vous permet de déclarer séparément votre signature et votre foncteur:

module type Personutils_T = sig 
    type t 
    val name : t -> string 
end 

module PersonUtils (Person: Person) : Personutils_T 
with type t = Person.t 
= struct 
    include Person 
    let name p = Person.first p^" "^Person.last p 
end 
+0

Merci! J'ai été capable de me débarrasser de la non-concordance des signatures dans mon dernier exemple. Mais est-il possible d'éviter le type t = t_'? Si j'inline 'tape t = {first: string; ...} 'alors ma méthode' loud_first_name' est toujours incapable de voir ses champs. –

+2

Vous pouvez essayer 'type nonrec t = t'. Il se référera au 't 'dans la portée, pas à celui qui est défini. –

+0

Merci @ ÉtienneMillon! Je ne connaissais pas cette syntaxe. Pourtant, le module que j'inclus fait que mon type 't' soit un doublon (et j'obtiens un message d'erreur). Peut-être que j'utilise incorrectement 'include'? –