OCaml 中的相互递归模块和函子

Ste*_*fly 1 ocaml

我已经定义了一个A由几个函子使用的接口,特别是MyFunctor

module type A = sig
    val basic_func: ...
    val complex_func: ...
end

module MyFunctor :
    functor (SomeA : A) ->
struct
    ...
    let complex_impl params =
        ...
        (* Here I call 'basic_func' from SomeA *)
        SomeA.basic_func ...
        ...
end
Run Code Online (Sandbox Code Playgroud)

现在我想定义一个B实现接口的模块A。特别是, 的实现complex_func应该使用basic_functhrough complex_implin MyFunctor

module B = struct
    let basic_func = ...

    let complex_func ... =
        let module Impl = MyFunctor(B) in
        Impl.complex_impl ...
end
Run Code Online (Sandbox Code Playgroud)

但是,此代码无法编译,因为BMyFunctor(B). 显然B取决于MyFunctor(B),它本身取决于B,所以我尝试rec在 module 上使用关键字B,但没有成功。

那么,有可能做这样的事情吗?因为我有几个模块,这将是有益的B_1, ..., B_n,使用相同的实施B_k.complex_func来讲B_k.basic_func

或者我的问题有更好的模式吗?我知道我可以声明complex_impl为一个常规函数basic_func作为参数,而根本不使用函子:

let complex_impl basic_func params =
    ...
    basic_func ...
    ...
Run Code Online (Sandbox Code Playgroud)

但是在我的例子中complex_impl使用了 的许多基本函数A,我认为函子的范式更清晰,更不容易出错。

编辑:我遵循了这个答案,但实际上,A使用了一些t专门用于B以下方面的类型:

module type A = sig
    type t
    val basic_func: t -> unit
    val complex_func: t -> unit
end

module MyFunctor :
    functor (SomeA : A) ->
struct
    let complex_impl (x : SomeA.t) =
        SomeA.basic_func x
        ...
end

module rec B : A = struct
    type t = int
    val basic_func (x : t) = ...
    val complex_func (x : t) =
        let module Impl = MyFunctor(B) in
        Impl.complex_impl x
end
Run Code Online (Sandbox Code Playgroud)

现在我得到了错误(对于x在线Impl.complex_impl x):

This expression has type t = int but an expression was expected of type B.t
Run Code Online (Sandbox Code Playgroud)

编辑 2:我用以下代码解决了第二个问题:

module rec B :
    A with type t = int
= struct
    type t = int
    ...
end
Run Code Online (Sandbox Code Playgroud)

J. *_*son 5

您可以像编写递归let绑定一样使用递归模块

module type A = sig
    val basic_func   : unit -> int
    val complex_func : unit -> int
end

module MyFunctor =
  functor (SomeA : A) ->
  struct
    let complex_impl = SomeA.basic_func
end

module rec B : A = struct
    let basic_func () = 0
    let complex_func () =
      let module Impl = MyFunctor(B) in
      Impl.complex_impl ()
end
Run Code Online (Sandbox Code Playgroud)

注意 (a)和 (b)module rec的定义中的位B,我需要为递归模块定义提供模块签名。

# B.basic_func ();;
- : int = 0
# B.complex_func ();;
- : int = 0
Run Code Online (Sandbox Code Playgroud)

但是,有一个小警告,因为这仅有效,因为签名A只有函数类型的值。因此,它被称为“安全模块”。如果basic_funccomplex_func是值而不是函数类型,那么它会在编译时失败

Error: Cannot safely evaluate the definition
       of the recursively-defined module B
Run Code Online (Sandbox Code Playgroud)