wyer33
wyer33

Reputation: 6340

Is it possible to open or use a functor without an intermediate module in OCaml?

Is it possible to open or use a functor without an intermediate module? For example, say we have the following set of modules and functors:

module type FOO = sig
    val foo : int -> int
end
module Foo1 : FOO = struct
    let foo x = x+1
end
module Foo2 : FOO = struct
    let foo x = x+2
end

module Bar(Foo : FOO) = struct
    open Foo
    let apply x = foo x
end

If we try

let _ = Bar(Foo1).apply 1

we get the error

Error: Parse error: currified constructor

Certainly, we can accomplish this with

let _ =
    let module Bar' = Bar(Foo1) in
    Bar'.apply 1

but it's a little verbose. Alternatively, if we define a module that uses a functor

module Buz(Foo : FOO) = struct
    open Bar(Foo) 
    let buz x = apply x
end

we get the error

Error: This module is not a structure; it has type
       functor (Foo : FOO) -> sig val apply : int -> int end

Again, we can fix this with

module Buz(Foo : FOO) = struct
    module M = Bar(Foo)
    open M
    let buz x = apply x
end

but it's more verbose. In addition, we have a new module M defined in Buz, which sort of pollutes the namespace

module Buz :
  functor (Foo : FOO) ->
    sig module M : sig val apply : int -> int end val buz : int -> int end

Really, I just want Buz to include buz.

Basically, I'm asking if there's some sort of syntax or trick that I'm missing that let's us write things like Bar(Foo1).apply or open Bar(Foo1).

Upvotes: 4

Views: 1008

Answers (1)

ivg
ivg

Reputation: 35210

You can skip instantiation of a functor if you're accessing a type, module type, or class type. In other words it is possible only inside type expressions. Example:

module type T = sig type t end
module Pair (T : T) = struct type t = T.t * T.t end
module Int = struct type t = int end
type int_pair = Pair(Int).t

What concerning the second part of your question, then if you really want "want Buz to include buz.", then you should use include:

 module Buz(Foo : FOO) = struct
    include Bar(Foo) 
    let buz x = apply x
 end

There is difference between open and include statement. open X will not add any definitions from X, but just add it into a search path. include X will merely copy paste all definitions from X into the point where it is included.

If you want only buz in your module and nothing more, then you can hide it using module signatures:

module type Buz = sig val buz : int -> int end

module Buz(Foo : FOO) : Buz = struct
  include Bar(Foo)
  let buz = apply
end

Upvotes: 4

Related Questions