OCaml中的相互递归模块和函子 [英] Mutually recursive module and functor in OCaml

查看:61
本文介绍了OCaml中的相互递归模块和函子的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经定义了一个接口A,供多个函子使用,尤其是MyFunctor:

I have defined an interface A to be used by several functors, and notably by 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

现在,我想使用实现接口A的模块定义模块B.特别地,complex_func的实现应在MyFunctor中使用basic_funccomplex_impl:

Now I want to define a module B with implements the interface A. In particular, the implementation of complex_func should use 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

但是,由于BMyFunctor(B)的上下文中未完全声明,因此该代码无法编译.显然,B依赖于MyFunctor(B),而后者又依赖于B,因此我尝试在模块B上使用rec关键字,但没有成功.

However, this code doesn't compile as B is not fully declared in the context of MyFunctor(B). Obviously B depends on MyFunctor(B), which itself depends on B, so I tried to use the rec keyword on module B, but it didn't work out.

那么,有可能做这样的事情吗?这将很有用,因为我有几个模块B_1, ..., B_nB_k.basic_func方面使用B_k.complex_func的相同实现.

So, is it possible to do something like this ? It would be useful as I have several modules B_1, ..., B_n that use the same implementation of B_k.complex_func in terms of B_k.basic_func.

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

Or is there a better pattern for my problem ? I know that I can declare complex_impl as a regular function taking basic_func as a parameter, without using a functor at all :

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

但是在我的情况下,complex_impl使用了A的许多基本功能,我认为函子的范式更加清晰并且不易出错.

But in my case complex_impl uses many basic functions of A, and I think that the paradigm of functors is clearer and less error-prone.

我遵循了这个答案,但实际上,A使用了一些类型t专门用于B:

Edit : I followed this answer, but in fact, A uses some type t that is specialized in 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

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

And now I get the error (for x at line Impl.complex_impl x) :

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

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

Edit 2 : I solved this second problem with the following code :

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

推荐答案

您可以使用递归模块,就像编写递归let绑定

You can use recursive modules just like you'd write recursive let bindings

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)我需要为递归模块定义提供模块签名.

Note (a) the module rec bit in the definition of B and (b) that I am required to provide a module signature for a recursive module definition.

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

但是,有一点需要注意,因为签名A仅具有函数类型的值,所以这仅能起作用.因此,它被称为安全模块".如果basic_funccomplex_func是值而不是函数类型,则编译时将失败

There's a small caveat, however, in that this only works because the signature A has only values which are function types. It is thus known as a "safe module". If basic_func and complex_func were values instead of function types then it would fail upon compilation

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

这篇关于OCaml中的相互递归模块和函子的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆