Modules and Record Fields

I ran into a pretty simple OCaml problem, but I cannot find an elegant solution. I work with functors that apply to relatively simple modules (they usually define the type and several functions of this type) and extend these simple modules by adding additional more complex functions, types and modules. Simplified version:

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 

There is no need to specify the name of a simple module, because all its functions are present in the extended module, and functions in the simple module are generated by camlp4 based on the type. Idiomatic use of these functors:

module Int = Complex(struct
  type t = int
end)

The problem occurs when I work with records:

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

let (Some location) = Point2D.read db "location"

There seems to be no easy way to access the fields xand y, as defined above, outside the module Point2D, like location.xor location.Point2D.x. How can I achieve this?

: , :

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 *)
+5
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)
+3

. , , , , .

module Make : functor (Arg : TYPE) -> sig
  type t = Arg.t
  val default : t
  val get : t option -> t
end
module Made : sig
  type t
  val default : t
  val get : t option -> t
end

, Make(A).t = A.t ( Make(A).t ), Made.t . , Made , .

. . - , , , .

, , Made:

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

Made1.t Made2.t, . , .

Made.t , . . , , - .

, , . Ocaml . , , , .

module Made_object = Make(struct
    type t = <a : int>
    let default = object method a = 0 end
  end)

, , , .

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

, Make(A) , .

module MadeA1 = Make(A)
module MadeA2 = Make(A)

(, , MadeA1 MakeA2, Made1 Made2 . , : MadeA1.t = Make(A).t.)

+4

, OCaml t ( , ) Made. :

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

module Made = Make(F)

let _ = (Made.get None).F.a (* <-- WORKS *)

You can also explicitly declare a type outside of a functional application:

type rcd = {a : int}

module Made = Make(struct
  type t = rcd
  let default = { a = 0 }
end)

let _ = (Made.get None).a (* <-- WORKS *)
+1
source

All Articles