Making a StringSet with Base

I have the following code to create a StringSet module in base:

open Base

type t = Set.M(String).t

let empty = Set.empty (module String)
let of_list = Set.of_list (module String)
let diff = Set.diff
let inter = Set.inter
let to_list = Set.to_list 
let union = Set.union
let union_list = Set.union_list (module String)

which works, but I feel like I shouldn’t have to be explicitly reexporting every function from Set that I want in my interface. With core it was simply

open Core
module S = Set.Make(String)
include S


This discussion on stackoverflow might be an answer to your problem :

Hi Rémy,

I’m afraid that doesn’t solve my problem - using core, Set.Make(String) created a new module that satisfied the interface of Set, so that I could include it in my module and have it be a set. So I could say something like StringSet.of_list xs and it would work without needing to know that StringSet was derived from Set. In base since Set.M(String) does not return a Set I have to manually reexport the functions I want to use as

In general, in Base it shouldn’t be necessary to create a StringSet module the way you would in Core because (the moral equivalents of) all the values that would be in the StringSet module are just available directly via Set. What’s the use case where you need a StringSet module?

Unfortunately, Base doesn’t provide a functorized interface for creating sets and other ordered data structures, so you have to stick with the polymorphic sets and maps. If you want a monomorphic instance of Set, then you have to use Core_kernel or Core, where the good old Set.Make(String) will produce what you want.

As a minor point, most of these accessors can be defined by just writing:

include Set

The only ones which need to have (module String) included are the creator functions, because they don’t know what comparator to use. You can include Set.Accessors0, Set.Creators0, or Set.Creators_and_accessors0 (0 because there would be 0 type parameters) to help define your interface.

I have three main reasons for it:

  1. I have some other string-specific functions, e.g. converting all words to lowercase, or extracting word of certain length, that I have defined on the set. I would rather be consistent about using for all functions, not StringSet. for some and Set. for others.

  2. I want to encapsulate the fact that it’s a set of strings, and not have to pass in module String for functions like of_list when using the sets in other modules.

  3. I imagine monomorphic sets are more efficient, though I could be wrong about that.

It looks like my best bet is to just revert to using core rather than base.

thanks, I overlooked the Set.Creators and Set.Accessors modules!