ocamlfunctor

Implementing functions in module types


I have the following module type:

module type Element = sig
  type t
  type mystruct = {x: int; y: int}
  val (<) : t -> t -> bool
  val string_of_element : t -> string
  (* val (>) : t -> t -> bool = not (<) *)
end

Where as you can see, I want the type t to be generic but I want mystruct to have a specific structure. The problem is that when I create a module MyInteger that "implements" module Element as follow:

module MyInteger = struct
  type t = int
  let (<) a b = a < b
  let string_of_element = string_of_int
end

It complains that

The type `mystruct' is required but not provided

And it does not work unless I redefine type mystruct in this module.

I don't understand why it just don't use the type I defined in the module type? Is there a way I can make it do that?

Same thing with function (>), how can I make OCaml consider (>) the opposite of (<) whatever it is?


Solution

  • You were on the right track by tagging "functor." When the definition of some other function is dependent on another, functors are a good fit.

    In the following I only define the less than predicate, but the functor uses that to generate greater than and equal predicates.

    # module type COMPARABLE = sig
        type t
        val lt : t -> t -> bool
      end;;
    module type COMPARABLE = sig type t val lt : t -> t -> bool end
    # module Compare (M : COMPARABLE) = struct
        type t = M.t
        let lt = M.lt
        let gt a b = lt b a
        let eq a b = not (lt a b) && not (gt a b)
      end;;
    module Compare :
      functor (M : COMPARABLE) ->
        sig
          type t = M.t
          val lt : t -> t -> bool
          val gt : t -> t -> bool
          val eq : t -> t -> bool
        end
    # module A = Compare (struct type t = int let lt a b = a < b end);;
    module A :
      sig
        type t = int
        val lt : t -> t -> bool
        val gt : t -> t -> bool
        val eq : t -> t -> bool
      end
    # A.(lt 4 5, gt 4 5, eq 4 5);;
    - : bool * bool * bool = (true, false, false)
    

    Now, because the first part of the definition of the Compare functor is just aliasing the contents of the COMPARABLE module passed to it as M, we can use include instead.

    # module Compare (M : COMPARABLE) = struct
        include M
        let gt a b = lt b a
        let eq a b = not (lt a b) && not (gt a b)
      end;;
    module Compare :
      functor (M : COMPARABLE) ->
        sig
          type t = M.t
          val lt : t -> t -> bool
          val gt : t -> t -> bool
          val eq : t -> t -> bool
        end
    

    We could carry this further to define ge and le functions as well. All based on the less than predicate being defined.

    # module Compare (M : COMPARABLE) = struct
        include M
        let gt a b = lt b a
        let eq a b = not (lt a b) && not (gt a b)
        let le a b = lt a b || eq a b
        let ge a b = gt a b || eq a b
      end;;
    module Compare :
      functor (M : COMPARABLE) ->
        sig
          type t = M.t
          val lt : t -> t -> bool
          val gt : t -> t -> bool
          val eq : t -> t -> bool
          val le : t -> t -> bool
          val ge : t -> t -> bool
        end