OCaml 中的相互递归模块和仿函数

Mutually recursive module and functor in 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

现在我想定义一个模块 B 来实现接口 A。特别是, complex_func 的实现应该使用 basic_func through complex_impl in MyFunctor :

module B = struct
    let basic_func = ...

    let complex_func ... =
        let module Impl = MyFunctor(B) in
        Impl.complex_impl ...
end

但是,此代码无法编译,因为 B 未在 MyFunctor(B) 的上下文中完全声明。很明显B依赖MyFunctor(B),而MyFunctor(B)本身又依赖B,所以我尝试在模块B上使用rec关键字,但是没有用出。

那么,是否可以做这样的事情?这将很有用,因为我有几个模块 B_1, ..., B_nB_k.basic_func.

方面使用 B_k.complex_func 的相同实现

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

let complex_impl basic_func params =
    ...
    basic_func ...
    ...

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

编辑: 我遵循了 ,但实际上,A 使用了一些专门用于 [=18= 的类型 t ] :

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

现在我收到错误(xImpl.complex_impl x):

This expression has type t = int but an expression was expected of type B.t

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

module rec B :
    A with type t = int
= struct
    type t = int
    ...
end

您可以像编写递归 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

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

# B.basic_func ();;
- : int = 0
# B.complex_func ();;
- : int = 0

但是,有一点需要注意,因为签名 A 只有值是函数类型,所以这才有效。因此它被称为 "safe module"。如果 basic_funccomplex_func 是值而不是函数类型,那么它会在编译时失败

Error: Cannot safely evaluate the definition
       of the recursively-defined module B