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)
似乎没有简单的方法从模块外部访问上面定义的x
和y
字段Point2D
,例如location.x
或location.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)
首先,在最后一个代码示例的最后一行中,您可能指的.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)