Version française
Home     About     Download     Resources     Contact us    
Browse thread
Functors + polymorphism = confusion
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Chris King <colanderman@g...>
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