SoftTimur
SoftTimur

Reputation: 5540

How to extend Map.Make functor

I can write my own extension for List module of OCaml, by defining a file lib.ml and including List module:

module List =
struct
  include List

  (* remove l x returns the list l without the first element x found or *) 
  (* returns l if no element is equal to x. *)
  (* Elements are compared using ( = ). *)
  let rec remove (l : 'a list)  (x : 'a) : 'a list =
    match l with
    | [] -> []
    | hd :: tl ->
      if hd = x then
        tl else
        hd :: remove tl x

  ...
end

Then I can call Lib.List.remove ... in other files.

Now I would like to write my own extension for Map.Make functor, I tried something like follows in lib.ml:

module Make (Ord : Map.OrderedType with type key = Ord.t) =
struct
  include Map.Make(Ord)
  let aaa = 1
end

However, the compilation gives an error Error: The signature constrained by 'with' has no component named key.

Does anyone know how to do it?

Upvotes: 4

Views: 522

Answers (2)

Jonathan Protzenko
Jonathan Protzenko

Reputation: 1739

The right way to do this is to follow the structure of Map.mli, with an S module followed by a Make module.

myMap.mli

module type S = sig
  include Map.S
  val keys: 'a t -> key list
end

module Make (Ord: Map.OrderedType): S with type key = Ord.t

you were right about the "with" constraints but you put it in the wrong position.

Then, in myMap.ml:

module type S = sig
  include Map.S
  val keys: 'a t -> key list
end

module Make = functor (Ord: Map.OrderedType) -> struct
  module Map = Map.Make(Ord)
  include Map
  let keys m =
    Map.fold (fun k _ acc -> k :: acc) m []
end

Hope that helps!

Upvotes: 1

Virgile
Virgile

Reputation: 10158

Why would you want to constraint the signature of the argument of your functor? You don't need any with type here:

module Make (Ord : Map.OrderedType) =
struct
  include Map.Make(Ord)
  let aaa = 1
end

gives you a functor Make that given an implementation of Map.OrderedType returns a module with all the functions of Map.S, a type key equal to Ord.t, and a value aaa of type int.

If you want to force the result of your functor to adhere to a certain signature, then you might indeed need to add type constraints, e.g.

module type MyMap = sig include Map.S val aaa: int end
module MakeAbstract (Ord : Map.OrderedType): MyMap with type key = Ord.t =
struct
  include Map.Make(Ord)
  let aaa = 1
end

There's one difference between Make and MakeAbstract. The former has a type t equal to MapMake(Ord).t while the latter has an abstract type t

Upvotes: 2

Related Questions