OCaml 中的递归函子

Ste*_*fly 6 recursion ocaml module

这个问题类似于这一个,但我要声明一个递归函数对象,而不是递归模块。所以我有 :

一个界面A

module type A = sig
    type t
    val basic_func: ...
    val complex_func: ...
end
Run Code Online (Sandbox Code Playgroud)

在以下方面ComplexImpl实现的函子:A.complex_funcA.basic_func

module ComplexImpl (SomeA : A) =
struct
    let complex_impl params =
        SomeA.basic_func ...
        ...
end
Run Code Online (Sandbox Code Playgroud)

另一个界面I

module type I = sig
    type t
    ...
end
Run Code Online (Sandbox Code Playgroud)

以及一个B接受类型参数的函子I,实现接口A并用于ComplexImpl实现complex_func。我想写这样的东西:

(* I can't write 'rec' here *)
module rec B (SomeI : I) :
    A with type t = SomeI.t
= struct
    type t = SomeI.t
    (* this line does not work *)
    module Impl = ComplexImpl(B(I))

    let basic_func (x : t) = ...
    let complex_func (x : t) =
        Impl.complex_impl x
end
Run Code Online (Sandbox Code Playgroud)

但是我不能声明一个递归函子......


我发现实现递归函子的唯一方法是自行对其进行参数化:

module B (SomeI : I) (CopyOfB : A with type t = SomeI.t) :
    A with type t = SomeI.t
= struct
    type t = SomeI.t
    (* this line works *)
    module Impl = ComplexImpl(CopyOfB)

    let basic_func (x : t) = ...
    let complex_func (x : t) =
        Impl.complex_impl x
end
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

module rec RealB = B(SomeI)(RealB)
Run Code Online (Sandbox Code Playgroud)

但是语法很冗长,不是很安全(如果有人把一个不同于 的参数怎么办RealB)而且如果RealB它本身是一个函子,它就会变得非常棘手......

Leo*_*ite 5

递归模块有一个语法限制,其形式为:

module rec Name : module_type = module_expr
Run Code Online (Sandbox Code Playgroud)

这意味着不能使用以下方式声明递归函子:

module rec Name (Arg : module_type) : module_type = module_expr
Run Code Online (Sandbox Code Playgroud)

但必须写成:

module rec Name : functor (Arg : module_type) -> module_type =
  functor (Arg : module_type) -> module_expr
Run Code Online (Sandbox Code Playgroud)


Ste*_*fly 4

我找到了一个解决方案:

module B (SomeI : I) = struct
    (* introduce a recursive module Implementation *)
    module rec Implementation :
        A with type t = SomeI.t
    = struct
        type t = SomeI.t
        (* use Implementation here *)
        module Impl = ComplexImpl(Implementation)

        let basic_func (x : t) = ...
        let complex_func (x : t) =
            Impl.complex_impl x
    end

    (* include the code of Implementation here *)
    include Implementation
end
Run Code Online (Sandbox Code Playgroud)

我可以这样使用它:

module RealB = B(SomeI)
Run Code Online (Sandbox Code Playgroud)

  • 仅当函子实际上不是递归的,但只有它的 _result_ 是递归时,这才有效。一般的解决方案就是 Leo 所展示的。它允许函子应用自身,即使有不同的参数。 (2认同)