Reputation: 1373
module type Arity =
sig
val arity : nat (* in my real code it has another type *)
end
module S =
functor (A : Arity) -> struct
let check = ...
end
I would like to use the function check
inside the functor S
without implement signature Arity
. I read the first-class module but still not understand how to write it (in practice). Here is my draft code:
let A = has type of (module Arity)
then
let M = S (A)
then I can call check
function by
M.check
I tried:
let f arity = (module (val arity : Arity) : Arity)
it returns : val f : (module Arity) -> (module Arity)
Could you please help me to write this first-class module? Am I able to write it in Ocaml
?
Also in (http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual021.html#toc81) section 7.14 it says :
"The module expression (val expr : package-type)
cannot be used in the body of a functor,..."
I am not understand it. Could you please help me understand by giving an example?
Thank you for your help.
Upvotes: 4
Views: 2388
Reputation: 9030
I do not understand clearly what you want to know here. Apparently you get confused with some words of the normal OCaml modules and functors and, rather newer "first class modules" of OCaml. Anyway, I give you a short working example with OCaml 4.00.1 (do not try with 3.12.1 since things are improved in 4), probably it would help you:
module type Arity = sig
val arity :int
end
module S = functor (A : Arity) -> struct
let check = A.arity = 2 (* or whatever *)
end
The above is what you gave us with some trivial fixes to get compiled. Normally to use check, you give an implementation of signature Arity and give it to the functor S:
module AR = struct
let arity = 3
end
module SAR = S(AR)
let () = Printf.printf "%b\n" SAR.check
Let's use first class modules:
let a = (module AR : Arity)
This translates the module AR to a value and bind it to the variable a. Note that the parens are mandatory for syntax. You also need to give the siganture Arity. You can also write as follows:
let a' : (module Arity) = (module AR)
So the type of a and a' are (module Arity) and you need to give it to the compiler somehow. Unfortunately the type inference does not help us here.
You can make the value back to a module as follows:
module A' = (val a)
Now you can also make a first class module value of the functor S:
module type RESULT = sig
val check : bool
end
let s (a : (module Arity)) =
let module A = (val a) in
let module SA = S(A) in
(module SA : RESULT)
What s does is: take a value, make it back to a module, apply the functor S to it, then make another value from the result of functor application. The singature RESULT is necessary for the conversion. You cannot write (module SA : sig val check bool end). I am not good at things around here, but the typing of first class module values are not structural but nominal, I heard. You need to give a name to the signature at (module M : X).
The s's type is (module Arity) -> (module RESULT). Let's apply s to a:
let m = s a
To access check inside m, you need to make it back a module:
let m_check =
let module M = (val m) in
M.check
You might be disappointed to see that value<->module conversions are explicit, but this is how it works...
Upvotes: 6