2017-09-08 4 views
1

ツバメI持って次は、そのタイプ

最初と最後の名前を取得するためのメソッドを持つPersonモジュールタイプ:name機能をPersonを拡張する

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

PersonUtilsファンクタを:

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 

Mainモジュールは、次のように

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 

、私は追加のloud_first_name機能を追加したい:私は署名し、モジュールに次の行を追加します。

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 

はしかし、loud_first_nameはもはや私の構造を知っていることを表示されませんtと入力して、エラーUnbound record field firstが残っています。

私の質問は、どうすればloud_first_nameのようなメソッドを作成して、自分のレコードフィールドにアクセスできるようにすることができますか?私はt型をレベルアップさせようとしましたが、私のファンクタの引数でそれを使うのは問題でした。

答えて

1

type nonrec t = tの組み合わせ(感謝Étienne Millon)のように見えるとを含みます、モジュールの署名がの場合、問題が修正されました。

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

あなたのタイプが同じであることを示す必要があります。あなたのタイプが同じであれば、その情報は失われます。

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 

別のアプローチ(私はお勧めウィッヒは)あなたのモジュールタイプ宣言にwith句を追加することです。

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 

情報は、署名宣言で直接見えないが、それはあなたが個別にあなたの署名とあなた数子を宣言することができます:

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

ありがとうございます!私は最後の例でシグネチャの不一致を取り除くことができました。しかし、 'type t = t_'を避ける方法はありますか?私がインラインで 't = {first:string; ...} '私の' loud_first_name'メソッドはまだそのフィールドを見ることができません。 –

+2

'type nonrec t = t'を試すことができます。それは定義されているのではなく、範囲内の 't 'を参照します。 –

+0

ありがとう@ÉtienneMillon!私はその構文について知らなかった。それでも、私が含むモジュールは、私の型 't'が重複するようにします(そして私はエラーメッセージを受け取ります)。おそらく私は 'include'を間違って使っていますか? –

関連する問題