Quyen
Quyen

Reputation: 1373

use first-class module in OCaml

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

Answers (1)

camlspotter
camlspotter

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

Related Questions