在OCaml中使用一流的模块

Quy*_*yen 4 ocaml module functor

module type Arity =
sig 
   val arity : nat (* in my real code it has another type *)
end

module S =
 functor (A : Arity) -> struct
   let check = ...
end
Run Code Online (Sandbox Code Playgroud)

我想checkS没有实现签名的情况下使用函子内部的函数Arity.我读了一流的模块,但仍然不明白如何编写它(在实践中).这是我的草案代码:

let A = has type of (module Arity)
Run Code Online (Sandbox Code Playgroud)

然后

let M = S (A)
Run Code Online (Sandbox Code Playgroud)

然后我可以调用check函数

M.check 
Run Code Online (Sandbox Code Playgroud)

我试过了:

let f arity = (module (val arity : Arity) : Arity)
Run Code Online (Sandbox Code Playgroud)

它返回: val f : (module Arity) -> (module Arity)

你能帮我写一下这个一流的模块吗?我能把它写进来Ocaml吗?

同样在(http://caml.inria.fr/pub/docs/manual-ocaml-4.00/manual021.html#toc81)第7.14节中它说:

"模块表达式(val expr : package-type)不能在函子体中使用,......"

我不明白.举个例子,请你帮我理解一下吗?

谢谢您的帮助.

cam*_*ter 5

我不清楚你在这里想知道什么.显然你会对正常的OCaml模块和仿函数以及OCaml的更新"一流模块"中的一些词语感到困惑.无论如何,我给你一个OCaml 4.00.1的简短工作示例(不要尝试使用3.12.1,因为事情在4中有所改进),可能它会帮助你:

module type Arity = sig
  val arity :int
end

module S = functor (A : Arity) -> struct
  let check = A.arity = 2 (* or whatever *)
end
Run Code Online (Sandbox Code Playgroud)

以上就是你给我们提供的一些简单的修补程序来编译.通常使用check,你给出一个签名Arity的实现并将它交给functor S:

module AR = struct
  let arity = 3
end

module SAR = S(AR)

let () = Printf.printf "%b\n" SAR.check
Run Code Online (Sandbox Code Playgroud)

让我们使用一流的模块:

let a = (module AR : Arity)
Run Code Online (Sandbox Code Playgroud)

这会将模块AR转换为值并将其绑定到变量a.请注意,parens对于语法是必需的.你还需要给予siganture Arity.你也可以这样写:

let a' : (module Arity) = (module AR)
Run Code Online (Sandbox Code Playgroud)

所以a和a的类型是(模块Arity),你需要以某种方式将它提供给编译器.不幸的是,类型推断对我们没有帮助.

您可以将值重新设置为模块,如下所示:

module A' = (val a)
Run Code Online (Sandbox Code Playgroud)

现在您还可以创建仿函数S的第一个类模块值:

module type RESULT = sig
  val check : bool
end

let s (a : (module Arity)) = 
  let module A = (val a) in
  let module SA = S(A) in
  (module SA : RESULT)
Run Code Online (Sandbox Code Playgroud)

它的作用是:获取一个值,使其返回模块,将仿函数S应用于它,然后从仿函数应用程序的结果中创建另一个值.单个RESULT是转换所必需的.你不能写(模块SA:sig val check bool end).我不擅长这里的事情,但我听说,第一类模块值的输入不是结构性的,而是名义上的.您需要在(模块M:X)处为签名命名.

s的类型是(模块Arity) - >(模块RESULT).我们将s应用于:

let m = s a
Run Code Online (Sandbox Code Playgroud)

要访问m内部的检查,您需要将其恢复为模块:

let m_check =
  let module M = (val m) in
  M.check
Run Code Online (Sandbox Code Playgroud)

您可能会失望地看到值< - >模块转换是明确的,但这是它的工作原理......

  • 第一类模块是正常的OCaml值:例如,您可以将它们放在列表中.参考手册显示了这样的示例:根据设备选择不同的模块实现.普通模块不是一流的.它们不是价值观,我们能做的是有限的. (2认同)