Reference current module in functor?

Want to pass the current Module to a Module Function
The goal is to reuse shared methods with other modules that only differ on t type while keeping it restricted to specific t of each module

type t

module parametricModule = CommonModule.make(<currentModule>)

include parametricModule

another option would be to pass only the type t to the Module Function but it requires to something that carries t type is it possible to pass pure types without params?

Can you show the code you tried? I’m not sure to follow.

There is a Module Function which has js bindings for HTML Canvas2D, it lists the common methods between Context2D and Path2D

the bindings for both Context2D and Path2D are exactly the same, they only differ on the t receiver, so the Module Function gets a type t from the Module param with type ModuleWithT
Fragment of the common Module Function

module type ModuleWithT = {
  type t
}

module MakeCanvasPath = (M: ModuleWithT) => {
  // type t = M.t
  /** https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc */
  @send
  external arc: (
    M.t,
    ~x: float,
    ~y: float,
    ~r: float,
    ~a1: float,
    ~a2: float,
    ~ccw: bool=?,
    unit,
  ) => unit = "arc"

  /** https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arcTo */
  @send
  external arcTo: (M.t, ~x1: float, ~y1: float, ~x2: float, ~y2: float, ~r: float) => unit = "arcTo"

The on the consumer module, which will reuse those bindings, im forced to create a submodule, to pass the current type to the Module Function and include it’s content

module Path2DType = {
  type t = t
}

// Here want to pass
include CanvasCommon.MakeCanvasPath(Path2DType)

The issue is that type t is aliased in submodule, want the t of the main module, without aliasing in submodule

can’t you just not alias the type t in your module function? playground link

module type WithTypeT = {
  type t
}

module CanvasCommon = {
  module MakeBindings = (M: WithTypeT) => {
    @val external make: unit => M.t = "make"
    @send external bar: M.t => string = "bar"
  }
}

type t

module Path2DType = {
  type t = t
}

include CanvasCommon.MakeBindings(Path2DType)
2 Likes

Another solution if you have multiple types t that share common behavior would be to have a parametric type t like this:

module CanvasCommon = {
  type kind = [#Path2DType | #Other]
  type t<'a>
  module Bindings = {
    @send external foo: t<[< kind]> => int = "foo"
    @send external bar: t<[< kind]> => string = "bar"
  }
}

module Path2DType = {
  type t = CanvasCommon.t<[#Path2DType]>
  @val external make: unit => t = "make"
  include CanvasCommon.Bindings
}

let path2DType = Path2DType.make()

playground link

2 Likes