Set.Make2 for functorial cartesian product #504

Merged
merged 3 commits into from Apr 17, 2015

3 participants

@c-cube
ocaml-batteries-team member

See #441. I had to build all three sets (domains and product) because otherwise the abstraction barrier would become unbreakable (product on abstract set implementation is better solved using Enum, I believe).

@c-cube
ocaml-batteries-team member

All agree to integrate this? #441 is still relevant.

@gasche
ocaml-batteries-team member

You shouldn't take silence as agreement by default, but you're right to ping again on the issue. When I first read the patch I was unsure whether that separate-binary-functor design was better or worse than adding a currified functor to the Set.S signature.

After giving it more thought I think the difference are not huge, and this one seems to be simpler. There is however one non-neglectible difference: if a library author were to expose a Set signature instantiated with Batteries' Make functor, a library user could not necessarily use the Make2 functor in a compatible way, because the original OrderedType module may not be exported.

Consider the following signature, for example:

module IntSet : Set.S with type elt = int

how would you create a cartesian product function that can be used with pairs of an IntSet.t and some other set? Note that in the next version of OCaml, the following should be usable as a signature:

module IntSet = Set.Make(Int)

solving this problem. In the meantime, we could maybe choose to support both choices: have a S2 signature that contains the interface of the binary functions, and then both a currified Bin functor in Set.S, and a Make2 functor, that export this interface.

@c-cube
ocaml-batteries-team member

The implementation only makes sense for sets that are known to be instances of Set.Make(), because it relies on the inner structure (balanced search tree). For more general-purpose cartesian product, the algorithm is more naive and less efficient - still we should provide it, I agree.

@jpdeplaix

module IntSet = Set.Make(Int)

You can already do: module IntSet : module type of Set.Make(Int). No need to wait the next version (even if it's a bit more optimized in ocaml 4.02).

@c-cube
ocaml-batteries-team member

@gasche did my answer convince you? I think providing a dedicated product functor (by opposition to using Enum and converting back to a set) really makes sense only when the implementation makes it more efficient. In this case, it's because we know we can convert sets to balanced trees internally.

@gasche
ocaml-batteries-team member

No, your answer did not convince me. Today if I write in a .ml file

module IntSet = BatSet.Make(BatInt)

then the most precise signature I can export in a .mli is BatSet.S with type t = int. I won't be able to make a product out of it after the fact, if cartesian product is only proposed as an external (to BatSet.S) bifunctor.

If I add two partial-application functors to S in Batteries, I could use IntSet.ProdLeft(Bool) to build my cartesian product. This is why I think the external bifunctor is the simpler design and a good choice in most situations, but also strictly less expressive so we should consider doing both.

@gasche gasche merged commit f758686 into ocaml-batteries-team:master Apr 17, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment