* Functors + polymorphism = confusion
@ 2007-06-21 7:16 Jonathan T Bryant
2007-06-21 14:08 ` [Caml-list] " Chris King
0 siblings, 1 reply; 3+ messages in thread
From: Jonathan T Bryant @ 2007-06-21 7:16 UTC (permalink / raw)
To: caml-list
I'm having some trouble getting functors to play nice with polymorphism.
I'm using a functor to parallelize a function, so given a function
wrapped up in a module, I apply a functor to it get a module with
several parallel versions of the function. The in/output of the
functions have to be types wrapped up in a Message module (as they may
need to be serialized).
This is pretty trivial for monomorphic functions, but I can't seem to
define the Bind functor correctly to allow a polymorphic function
definition which is bound to two message types at functor application.
I've tried every variation on the theme I can think of, but I can't
seem to make it work.
Is what I'm trying to do possible? I think it is because I did
something similar for polymorphic messages (included in code, but not
used). Maybe someone could point out to me something I'm overlooking?
(Code inlined below)
Thanks,
--Jonathan
functor_test.mli
----------------
module type Message =
sig
type t
val to_string : t -> string
val of_string : string -> t
end
module type PolyMessage =
functor (M : Message) ->
sig
type 'a t
val to_string : M.t t -> string
val of_string : string -> M.t t
end
module BindMessage :
functor (P : PolyMessage) ->
functor (M : Message) ->
Message
module type Function =
sig
module A : Message
module B : Message
val f : A.t -> B.t
end
module type PolyFunction =
(*
functor (A : Message) ->
functor (B : Message) ->
*)
sig
(* val f : A.t -> B.t *)
val f : 'a -> 'b
end
module BindFunction :
functor (F : PolyFunction) ->
functor (A : Message) ->
functor (B : Message) ->
Function
module type ParallelFunction =
sig
module A : Message
module B : Message
val sequential : A.t -> B.t
val concurrent : A.t -> B.t
val parallel : A.t -> B.t
val remote : A.t -> B.t
end
module Parallelize : functor (F : Function) -> ParallelFunction
module IntMessage : Message
module FloatMessage : Message
module Double : Function
module Identity : PolyFunction
module BoundIdentity : Function
module ParallelDouble : ParallelFunction
module ParallelIdentity : ParallelFunction
functor_test.ml
----------------
module type Message =
sig
type t
val to_string : t -> string
val of_string : string -> t
end
module type PolyMessage = functor (M : Message) ->
sig
type 'a t
val to_string : M.t t -> string
val of_string : string -> M.t t
end
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
module type Function =
sig
module A : Message
module B : Message
val f : A.t -> B.t
end
module type PolyFunction =
(*
functor (A : Message) ->
functor (B : Message) ->
*)
sig
(* val f : A.t -> B.t *)
val f : 'a -> 'b
end
module BindFunction =
functor (F : PolyFunction) ->
functor (A : Message) ->
functor (B : Message) ->
struct
module A = A
module B = B
let f x = F.f x
end
module type ParallelFunction =
sig
module A : Message
module B : Message
val sequential : A.t -> B.t
val concurrent : A.t -> B.t
val parallel : A.t -> B.t
val remote : A.t -> B.t
end
module Parallelize = functor (F : Function) ->
struct
module A = F.A
module B = F.B
let sequential x = F.f x
let concurrent x = F.f x
let parallel x = F.f x
let remote x = F.f x
end
module IntMessage =
struct
type t = int
let to_string m = string_of_int m
let of_string s = int_of_string s
end
module FloatMessage =
struct
type t = float
let to_string m = string_of_float m
let of_string s = float_of_string s
end
module Double =
struct
module A = IntMessage
module B = IntMessage
let f x = 2 * x
end
module Identity =
(*
functor (A : Message) ->
functor (B : Message) ->
*)
struct
let f x = (Obj.magic x : 'b)
(* Fails type checking, why?
let f x = x
*)
end
module BoundIdentity = BindFunction (Identity) (IntMessage) (IntMessage)
(* Fails type checking, as it should:
module BoundIdentity = Bind (Identity) (IntMessage) (FloatMessage)
*)
module ParallelDouble = Parallelize (Double)
module ParallelIdentity = Parallelize (BoundIdentity)
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Caml-list] Functors + polymorphism = confusion
2007-06-21 7:16 Functors + polymorphism = confusion Jonathan T Bryant
@ 2007-06-21 14:08 ` Chris King
2007-06-22 2:45 ` Jonathan Bryant
0 siblings, 1 reply; 3+ messages in thread
From: Chris King @ 2007-06-21 14:08 UTC (permalink / raw)
To: Jonathan T Bryant; +Cc: caml-list
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
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Caml-list] Functors + polymorphism = confusion
2007-06-21 14:08 ` [Caml-list] " Chris King
@ 2007-06-22 2:45 ` Jonathan Bryant
0 siblings, 0 replies; 3+ messages in thread
From: Jonathan Bryant @ 2007-06-22 2:45 UTC (permalink / raw)
To: Chris King; +Cc: caml-list
On Jun 21, 2007, at 10:08 AM, Chris King wrote:
> The important thing to remember with Caml modules is that it will hide
> type relations unless you tell it otherwise:
>
> 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!
Ah, I see the error now!
>
> 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
>
Works perfectly! I had always been a little confused as to exactly
what the "with" syntax was accomplishing, and even with your
explanation it took a while for me to see how to use it. Thanks for
the clarification.
>
>> 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.
>
I have gone back and used the same "with" syntax on my prebuilt
messages and it solved another type issue I was having :)
I do specify the output signature (in the .mli file):
module BindMessage :
functor (P : PolyMessage) ->
functor (M : Message) ->
Message
but now it's:
module BindMessage :
functor (P : PolyMessage) ->
functor (M : Message) ->
Message with type t = M.t P(M).t
>
> Hope this helps... I can attest that this stuff is pretty confusing
> at first. :)
Yes. I am learning more about the module system than I think I ever
wanted to know. My project makes heavy use of (read: abuses) the
modules system :)
--Jonathan
>
> - Chris
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2007-06-22 2:45 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-06-21 7:16 Functors + polymorphism = confusion Jonathan T Bryant
2007-06-21 14:08 ` [Caml-list] " Chris King
2007-06-22 2:45 ` Jonathan Bryant
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox