模块和记录字段

Vic*_*let 5 ocaml field module record functor

我偶然发现了一个相当简单的OCaml问题,但我似乎无法找到一个优雅的解决方案.我正在使用应用于相对简单模块的函子(它们通常在该类型上定义类型和一些函数),并通过添加更复杂的函数,类型和模块来扩展这些简单模块.简化版本将是:

module type SIMPLE = sig
  type t
  val  to_string : t -> string
  val  of_string : string -> t
end

module Complex = functor (S:SIMPLE) -> struct
  include S
  let write db id t = db # write id (S.to_string t)
  let read db id = db # read id |> BatOption.map S.of_string
end 
Run Code Online (Sandbox Code Playgroud)

没有必要给简单模块命名,因为它的所有功能都存在于扩展模块中,而简单模块中的函数是由camlp4根据类型生成的.这些仿函数的惯用用法是:

module Int = Complex(struct
  type t = int
end)
Run Code Online (Sandbox Code Playgroud)

我在处理记录时出现问题:

module Point2D = Complex(struct
  type t = { x : int ; y : int }
end)

let (Some location) = Point2D.read db "location"
Run Code Online (Sandbox Code Playgroud)

似乎没有简单的方法从模块外部访问上面定义的xy字段Point2D,例如location.xlocation.Point2D.x.我怎样才能做到这一点?

编辑:根据要求,这是一个显示问题的完整最小示例:

module type TYPE = sig
  type t 
  val  default : t
end 

module Make = functor(Arg : TYPE) -> struct
  include Arg
  let get = function None -> default | Some x -> (x : t)
end

module Made = Make(struct
  type t = {a : int}
  let default = { a = 0 } (* <-- Generated by camlp4 based on type t above *)
end)

let _ = (Made.get None).a (* <-- ERROR *)
Run Code Online (Sandbox Code Playgroud)

gas*_*che 3

首先,在最后一个代码示例的最后一行中,您可能指的.a是而不是.x.

您的代码的问题在于,按照您定义Make函子的方式,该类型t是抽象的Made:实际上,函子使用TYPE密封{a : int}为抽象类型的签名。

下面的设计规避了这个问题,但是,它是一个不同的设计。

module type TYPE = sig
  type t 
  val  default : t
end 

module Extend = functor(Arg : TYPE) -> struct
  open Arg
  let get = function None -> default | Some x -> (x : t)
end

module T = struct
  type t = {a : int}
  let default = { a = 0 }
end

module Made = struct
  include T
  include Extend(T)
end

let _ = Made.((get None).a)
Run Code Online (Sandbox Code Playgroud)