Module types, functors and types

Hi everyone,

While developing my small app, I’m facing an issue that is sticking me.

The application draws KiCad electronic schematics, and for this, a module Painter abstracts a canevas and the functions to draw on it:

module type Painter = sig
  (** A module able to paint a canvas with several graphic primitives
      and then to process the canvas into a picture file format.  The
      functions are supposed to be pure *)

  (** the canvas of the painter *)
  type t

  val get_context : unit -> t
  (** [get_context ()]
      @return a new painting canvas *)

  ... primitives functions
end

This module was manipulated by the interpreter of a given version V5 of the schematic file. (No so) Recently, a new file format V6 for schematics was introduced. So I introduced a schematic painter type to abstract the schematic format:

module type SchPainter = sig
  (** A module able to paint a schematic file in a painter context *)

  (** the schematic context *)
  type schContext

  (** the underlying context *)
  type painterContext

  val initial_context : ?allow_missing_component:bool -> revision -> schContext
  (** [initial_context allow_missing_component revision]
      @return an new empty context *)

  val parse_sheet : schContext -> String.t -> schContext
  (** [parse_line content context] parse a [content] of schematic and
      update [context].
      @return the updated context *)

  val output_context : schContext -> painterContext
  (** [output_context context output] write the [context] as a image
      format to [output] *)
end

Which are created via functors whose type is:

module type KicadSchHandler = sig

  module MakeSchPainter: functor (P: Painter) -> SchPainter

end

Then I can create the two formats:

module MakeSchPainter (P : Painter) :
  SchPainter with type painterContext = P.t = struct 
  
  type painterContext = P.t

  ... Implementation
end

So far, so good. But at some point, I create a SchPainter from a SvgPainter , and I want to get back the SVG content of the canevas as a string :

  let schHandler =
    if String.ends_with ~suffix:".sch" sch then
      (module Kicadsch.V5: Kicadsch.Sigs.KicadSchHandler)
    else if String.ends_with ~suffix:".kicad_sch" sch then
      (module Kicadsch.V6: Kicadsch.Sigs.KicadSchHandler)
    else
      failwith ("unknown file extenstion for " ^ sch) in
  let module SchPainter = (val schHandler) in
  let module SvgSchModule = SchPainter.MakeSchPainter(SvgPainter) in
  let open SvgSchModule in
  let initctx = initial_context No_Rev in
  let fileout = build_outputfilename outdir sch in
  let%lwt o = Lwt_io.open_file ~mode:Lwt_io.Output fileout in
  let%lwt i = Lwt_io.open_file ~mode:Lwt_io.Input sch in
  let%lwt contents = Lwt_io.read i in
  let endcontext = parse_sheet initctx contents in
  let canvas = output_context endcontext in
  let%lwt () = Lwt_io.write o (SvgPainter.write canvas) in
  let%lwt () = Lwt_io.close i in
  Lwt_io.close o

But the type checker chokes the line SvgPainter.write canvas

I understand that the functor eliminates the original painterContext type in the generated SchPainter, but I don’t really see how to get it back for my own manipulation.

Have you tried reexporting the type equality between painterContext and P.t?

module MakeSchPainter(P : Painter) : SchPainter with type painterContext = P.t

Cheers,
Nicolas

1 Like

Thank your for your reply! It gave me a good hint and I added this type equality in the mli files of V5 and V6.

It worked!