Recursion OCaml中的递归函子
这个问题类似于,但我想声明一个递归函子,而不是递归模块。因此,我: 接口Recursion OCaml中的递归函子,recursion,module,ocaml,Recursion,Module,Ocaml,这个问题类似于,但我想声明一个递归函子,而不是递归模块。因此,我: 接口A: module type A = sig type t val basic_func: ... val complex_func: ... end 根据A.basic\u func实现A.complex\u func的函子ComplexImpl: module ComplexImpl (SomeA : A) = struct let complex_impl params =
A
:
module type A = sig
type t
val basic_func: ...
val complex_func: ...
end
根据A.basic\u func
实现A.complex\u func
的函子ComplexImpl
:
module ComplexImpl (SomeA : A) =
struct
let complex_impl params =
SomeA.basic_func ...
...
end
另一个界面I
:
module type I = sig
type t
...
end
以及一个函子B
,它接受类型为I
的参数,实现接口a
,并使用complementpl
实现复杂函数。我想这样写:
(* 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
module rec RealB = B(SomeI)(RealB)
module RealB = B(SomeI)
但我不能声明递归函子
我发现实现递归函子的唯一方法是自己对其进行参数化:
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
然后像这样使用它:
(* 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
module rec RealB = B(SomeI)(RealB)
module RealB = B(SomeI)
但是语法冗长,不太安全(如果有人输入的参数不同于RealB
),并且如果RealB
本身就是一个函子,那么它会变得非常棘手……我找到了一个解决方案:
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
我可以这样使用它:
(* 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
module rec RealB = B(SomeI)(RealB)
module RealB = B(SomeI)
递归模块具有以下形式的语法限制:
module rec Name : module_type = module_expr
这意味着递归函子不能使用以下命令声明:
module rec Name (Arg : module_type) : module_type = module_expr
但必须写下:
module rec Name : functor (Arg : module_type) -> module_type =
functor (Arg : module_type) -> module_expr
但是,这在我的例子中不起作用,因为B(SomeI)
的签名是A,类型为t=SomeI.t
。因此,就您的术语而言,Name
的module_type
依赖于Arg
,这是无效的(除非我遗漏了什么)。在您的情况下,它可以正常工作。名称
的模块类型
也将是函子(Arg:modtype)->modtype
(因为名称
的类型是函子类型)。我将更新我的答案以使其更清楚。在我的情况下,我得到以下错误:无法安全地评估递归定义的模块B的定义
您的代码不一定有充分的依据,因为B(SomeI)的定义涉及调用B(SomeI)。在您在问题中给出的解决方案中,您正在利用OCaml提供的一种变通方法——如果模块是一个只包含函数的结构,那么它允许潜在的无依据递归(如果它实际上是无依据的,则在运行时会引发异常)。函子不支持这种变通方法。就我个人而言,如果可能的话,我会避免使用递归模块。有时它们是不可避免的,但通常有一种更简单的方法没有它们。这只适用于函子不是真正递归的情况,但只有它的结果是递归的。一般的解决方案就是利奥所展示的。它允许函子应用自身,即使使用不同的参数。