This site is updated infrequently. For up-to-date information, please visit the new OCaml website at ocaml.org.

Functors + polymorphism = confusion
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
 Date: 2007-06-21 (14:08) From: Chris King Subject: Re: [Caml-list] Functors + polymorphism = confusion
```The important thing to remember with Caml modules is that it will hide
type relations unless you tell it otherwise:

On 6/21/07, Jonathan T Bryant <jtbryant@valdosta.edu> wrote:
> module BindFunction :
>   functor (F : PolyFunction) ->
>   functor (A : Message) ->
>   functor (B : Message) ->
>   Function

Recall your definition of Function above:

> module type Function =
>  sig
>    module A : Message
>    module B : Message
>    val f : A.t -> B.t
>  end

Here modules A and B are of type Message, which define an abstract
type t.  Caml doesn't automatically fill in this type definition for
you, so the module returned by BindFunction will only be able to
operate over a pair of abstract types.  Not good!

The solution to this (which you will see used in functorized library
modules such as Map and Set) is to add the derivation of types A.t and
B.t to your output signature using the "with" syntax:

module BindFunction :
functor (F : PolyFunction) ->
functor (A : Message) ->
functor (B : Message) ->
Function with type A.t = A.t and type B.t = B.t

This tells Caml to modify the Function signature so that, instead of
having abstract types A.t and B.t, it contains those type equations.
So the actual output signature will look like this:

sig
module A :
sig
type t = A.t
val to_string : t -> string
val of_string : string -> t
end
module B :
sig
type t = B.t
val to_string : t -> string
val of_string : string -> t
end
val f : A.t -> B.t
end

> module Parallelize : functor (F : Function) -> ParallelFunction

You'll need to do the same thing here, tell Caml that the abstract
types within ParallelFunction are really the same as the types in F:

module Parallelize : functor (F : Function) ->
ParallelFunction with type A.t = F.A.t and type B.t = F.B.t

Note that you can actually do this at the module level, too:

module Parallelize : functor (F : Function) ->
ParallelFunction with module A = F.A and module B = F.B

In this case it only serves to save a couple keystrokes but it is
useful if either (a) you have lots of types you want to copy en masse
to the output signature or (b) the output signature contains a
restricted form of one of the input modules and you want to retain the
extra types and values.

> module BindMessage =
>   functor (P : PolyMessage) ->
>   functor (M : Message) ->
>   struct
>     module P = P (M)
>     type t = M.t P.t
>     let to_string m = P.to_string m
>     let of_string s = P.of_string s
>   end

Because you are not restricting the output signatures in your
implementation, Caml preserves the type relationships (it only
discards them at the interface level).  However if you did specify the
output signature here (as the library modules do) you would need to
use the same construct.

Hope this helps... I can attest that this stuff is pretty confusing at first. :)

- Chris

```