我想澄清一点:目前,在我看来,在声明仿函数的同时,必须将三重签名重复,只要我们将其导出到.mli文件中即可。这是一个例子:

假设我们有一个仿函数Make,它生成一个由A参数化的SigA模块(我能想到的最简单的示例)。因此,在.mli文件中,我们具有:

module type A = sig
    type a
    val identity : a -> a
end

module type SigA = sig
    type a
end

module Make (MA:SigA) :
    A with type a := MA.a

现在,我了解到我们必须在.ml文件中编写一个实现:
module Make (MA:SigA) = struct
    type a = MA.a

    let identity obj = obj
end

到目前为止一切都很好,对吗?不!原来,我们必须将ASigA的声明逐字复制到.ml文件中:
module type A = sig
    type a

    val identity : a -> a
end

module type SigA = sig
    type a
end

module Make (MA:SigA) = struct
    type a = MA.a

    let identity obj = obj
end

虽然我(模糊地)理解了复制SigA的基本原理(毕竟,在源代码中已经提到过),但是复制A定义对我来说似乎完全没有意义。
我已经简要浏览了Core代码库,一旦将它们导出到单独的.mli中,它们似乎要么将其复制到小型模块中,要么复制到更大的模块中,该.mli可从.ml和.mli中使用。

那仅仅是一种状况吗?每个人都可以复制模块签名3次吗(一次在.mli文件中,一次在.ml文件中两次:声明和定义!)
目前,我正在考虑完全放弃.mli文件,并使用.ml文件中的签名限制模块导出。

编辑:是的,我知道我可以通过在.mli文件中的A内声明Make内联接口(interface)来避免此问题。但是,如果我想从该模块外部使用该接口(interface),这对我没有帮助。

最佳答案

这是因为一对ML和MLI文件的行为就像一个结构以及与其匹配的相应签名。

避免两次写出模块类型的通常方法是在一个单独的ML文件中对其进行定义。例如,

(* sig.ml *)
module type A = sig
  type a
end

module type B = sig
  type b
  val identity : b -> b
end

(* make.mli *)
module Make (A : Sig.A) : Sig.B with type b = A.a

(* make.ml *)
module Make (A : Sig.A) =
struct
  type b = A.a
  let identity x = x
end

在不隐藏任何内容的情况下,最好忽略MLI文件,例如上面的Sig模块。

在其他情况下,将签名与实现分开写入是一项功能,而不是真正的重复-它定义了模块的导出,通常,这只是实现中的一小部分。

关于ocaml - OCaml中的仿函数: triple code duplication necessary?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22348341/

10-13 06:01