OCaml中的相互递归模块和函子 [英] Mutually recursive module and functor in 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_func
至complex_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
但是,由于B
在MyFunctor(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_n
在B_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
现在我得到了错误(对于x
在Impl.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_func
和complex_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屋!