15
votes

It is well-known that OCaml has a parametric polymorphism and this leads to some limitations. Haskell, through its type classes, offers an ad hoc polymorphism, which is, obviously, very convenient in several situations. It is also well-known that the system of modules and functors of OCaml allows to create a kind of ad hoc polymorphism. See the great recent answer of Simon Shine here for instance.

My point is that it is possible in Haskell to create types that derive several types classes. For instance :

data Person = Person { firstName :: String
                 , lastName :: String
                 , age :: Int
                 } deriving (Eq, Show, Read)

This is very convenient to define types having several features (allowing values of type Person to support equality tests, be printable, and be readable in the given example).

My question is the following: Can we do the same, simply, in OCaml? By simply I mean with the ground syntax of the language and without many artifices.

To give a somewhat concrete example, suppose we have two OCaml signatures

module type Showable = sig
    type t
    val to_string : t -> string
end

module type Readable = sig
    type t
    val from_string : string -> t
end

The aim is to write a functor F parametrized by a module which implements both Showable and Readable.

1
This must be one of the best written question i've ever seen ! Hope someone will find an answer !Lhooq

1 Answers

13
votes

Sure, that's actually quite easy, use module inclusion.

module type S = sig
  include Showable
  include Readable with type t := t (* destructive substitution *)
end

module F ( M : S ) = struct
  let fake_id x = M.from_string @@ M.to_string x
end

Destructive substitution is explained in the manual: http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec234
The rest is regular module stuff (see the manual for a complete explanation)

Some functor-heavy library rely on this kind of structural subtyping quite a lot. For example, each functor in ocamlgraph define its own module type argument. Here is an example with the Kruskal module. The functor expect a module of type Kruskal.G, which implements a subsignature of Sig.G (which is implemented by most graph modules).