Version française
Home     About     Download     Resources     Contact us    
Browse thread
Module type of a structure returned by functor
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Jacques Garrigue <garrigue@m...>
Subject: Re: [Caml-list] Module type of a structure returned by functor
From: Dawid Toton <d0@wp.pl>
> 1. The following piece of code contains illegal constructs. These are
> functor applications marked with (* ? *).
>     Basically, I need module type of what is produced by functor.
>     My first question is: what is the proper, "canonical" workaround for
>     unavailability of applications marked (* ? *) ?
> 
> module type Big = sig type t type u end
> module type Small = sig type t end
> 
> module type MakeEdge = functor (Big : Big) -> sig val foo : Big.t
> option end
> module MakeEdge = functor (Big : Big) -> struct let foo = None end
> 
> module type Add_boilerplate = functor (Small:Small) -> sig type t end
> module Add_boilerplate = functor (Small:Small) -> struct type t =
> Small.t type u = t end
> 
> module type ConvenientEdge = functor (Small:Small) -> MakeEdge
> (Add_boilerplate (Small)) (* ? *)
> module ConvenientEdge = functor (Small:Small) -> MakeEdge
> (Add_boilerplate (Small))
> 
> module SmallX = struct type t = int end
> module EdgeX = ConvenientEdge (SmallX)
> module type EdgeX = ConvenientEdge (SmallX) (* ? *)
> 
> module Algorithm = functor (EdgeX : EdgeX) -> struct let doit =
> EdgeX.foo end
> 
> 2. And the related question: why one can't do functor applications in
> module types as in above lines marked with (* ? *) ? Is there some
> theoretical reason?

You are mixing two things: the signature of a functor (which cannot be
applied to anything, since it is a signature, not a functor), and a
functor returning a signature.
Using ocaml 3.11, you have to wrap the returned signature inside a
structure:

(* Signature wrapped inside a structure *)
module MakeEdgeSig (Big : Big) = struct
  module type S = sig val foo : Big.t option end
end
module MakeEdge (Big : Big) = struct let foo = None end

module Add_boilerplate (Small:Small) =
  struct type t = Small.t type u = t end

module ConvenientEdgeSig (Small:Small) = MakeEdgeSig (Add_boilerplate (Small))
module ConvenientEdge (Small:Small) = MakeEdge (Add_boilerplate (Small))

module SmallX = struct type t = int end
module EdgeX = ConvenientEdge (SmallX)
(* Build the corresponding signature *)
module type EdgeX = ConvenientEdgeSig(SmallX).S

module Algorithm (EdgeX : EdgeX) = struct let doit = EdgeX.foo end

> 3. Will the "module type of..." feature of 3.12 help with this? I can
> imagine e.g.:
> 
> module type EdgeX = (module type of (ConvenientEdge (SmallX)))

Indeed, if your only goal is to obtain this specific signature, this
does the trick. But if you want to specify signatures independently of
implementations, you can also use the new destructive substitution
mechanism.

(* Requires ocaml 3.12 *)
(* New signature Edge, parameterized with t *)
module type Edge = sig type t val foo : t option end

(* Edge with type t := Big.t  ==  sig val foo : Big.t option end *)
module MakeEdge (Big : Big) : Edge with type t := Big.t =
  struct let foo = None end

module Add_boilerplate (Small:Small) =
  struct type t = Small.t type u = t end

module ConvenientEdge (Small:Small) : Edge with type t := Small.t =
  MakeEdge(Add_boilerplate (Small))

module SmallX = struct type t = int end
module EdgeX = ConvenientEdge (SmallX)
(* Build the result signature by instantiating Edge signature *)
module type EdgeX = Edge with type t := SmallX.t
(* Alternative approach, obtain the same signature from EdgeX itself *)
module type EdgeX' = module type of EdgeX

module Algorithm(EdgeX : EdgeX) = struct let doit = EdgeX.foo end


Hope this helps,

Jacques Garrigue