Functors + polymorphism = confusion

Jonathan T Bryant
 Chris King
[
Home
]
[ Index:
by date

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