Types 包含一个模块将吞咽其类型

Types 包含一个模块将吞咽其类型,types,module,ocaml,Types,Module,Ocaml,我有以下资料: 带有获取姓名方法的人员模块类型: module type Person = sig type t val first : t -> string val last : t -> string end PersonUtilsfunctor,用于使用name函数扩展Person: module PersonUtils (Person: Person) : sig type t val name : t -> string end = struc

我有以下资料:

带有获取姓名方法的
人员
模块类型:

module type Person = sig
  type t
  val first : t -> string
  val last : t -> string
end
PersonUtils
functor,用于使用
name
函数扩展
Person

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
模块,如下所示:

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
Main
中,我想添加一个额外的
loud\u first\u 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\u first\u name
似乎不再知道我的类型
t
的结构,因此我只剩下错误
Unbound record field first

我的问题是:如何创建像
loud\u first\u name
这样的方法,以便它们仍然可以访问我的记录字段?我试图将我的
t
类型向上移动一个级别,但在我的函子的参数中使用它时遇到了问题

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

您必须在签名中指出您的类型是相同的,如果您仅在结构中指出,则信息将丢失

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

看起来像是
类型nonrec t=t
(谢谢)的组合,包括带有签名的模块修复了我的问题

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

谢谢在上一个示例中,我能够消除签名不匹配。但是有什么方法可以避免t=t类型?如果我内联
type t={first:string;…}
那么我的
loud\u first\u name
方法仍然无法查看其字段。您可以尝试
type nonrec t=t
。它将引用范围中的
t
,而不是定义中的。谢谢@ÉtienneMillon!我不知道这个语法。不过,我包含的模块会导致我的type
t
重复(并且我会收到一条错误消息)。也许我使用的
包括
不正确?明白了<代码>包含
ing my module
:类型为t:=t的Sig
修复了该问题以及类型为nonrec t=t
。非常感谢!