在OCaml中是否可以在没有中间模块的情况下打开或使用函子?

在OCaml中是否可以在没有中间模块的情况下打开或使用函子?,ocaml,Ocaml,是否可以在没有中间模块的情况下打开或使用函子?例如,假设我们有以下一组模块和函子: 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

是否可以在没有中间模块的情况下打开或使用函子?例如,假设我们有以下一组模块和函子:

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
如果我们尝试

let _ = Bar(Foo1).apply 1
我们得到了错误

Error: Parse error: currified constructor
Error: This module is not a structure; it has type
       functor (Foo : FOO) -> sig val apply : int -> int end
当然,我们可以通过

let _ =
    let module Bar' = Bar(Foo1) in
    Bar'.apply 1
module Buz(Foo : FOO) = struct
    module M = Bar(Foo)
    open M
    let buz x = apply x
end
但是有点冗长。或者,如果我们定义一个使用函子的模块

module Buz(Foo : FOO) = struct
    open Bar(Foo) 
    let buz x = apply x
end
我们得到了错误

Error: Parse error: currified constructor
Error: This module is not a structure; it has type
       functor (Foo : FOO) -> sig val apply : int -> int end
同样,我们可以用

let _ =
    let module Bar' = Bar(Foo1) in
    Bar'.apply 1
module Buz(Foo : FOO) = struct
    module M = Bar(Foo)
    open M
    let buz x = apply x
end
但它更冗长。此外,我们在
Buz
中定义了一个新模块
M
,这在某种程度上污染了名称空间

module Buz :
  functor (Foo : FOO) ->
    sig module M : sig val apply : int -> int end val buz : int -> int end
真的,我只想
Buz
包括
Buz


基本上,我是在问是否有某种语法或技巧我不知道,让我们写一些东西,比如
Bar(Foo1)。应用
openbar(Foo1)

如果访问类型、模块类型或类类型,可以跳过functor的实例化。换句话说,只能在类型表达式内部执行。例如:

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
关于你问题的第二部分,如果你真的想“让Buz包含Buz”,那么你应该使用
include

 module Buz(Foo : FOO) = struct
    include Bar(Foo) 
    let buz x = apply x
 end
open
include
语句之间存在差异
openx
不会从
X
添加任何定义,只会将其添加到搜索路径中
include X
只会将
X
中的所有定义复制粘贴到包含它的点

如果您只想在模块中使用
buz
,除此之外,您可以使用模块签名将其隐藏:

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

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

在第二种情况下,如果可能的话,我根本不想要额外的定义。真的,我只想
buz
出现在签名中,这样做不需要手动定义新签名就好了。在OCaml中不能这样做。这是有原因的。主要原因是模块可以有任意的副作用和非平凡的表示。他们需要一个居住的地方。