在OCaml中使用一流模块

4
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

我希望在实现签名Arity的情况下,在函数对象S内使用check函数。 我阅读了一等模块,但仍不理解如何编写(实际操作中)。这是我草稿代码:

let A = has type of (module Arity)

那么。
let M = S (A)

那么我可以通过以下方式调用check函数:

M.check 

我尝试过:

let f arity = (module (val arity : Arity) : Arity)

它返回: 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)不能在函数器的主体中使用..."

我不太理解。您可以通过举个例子来帮助我理解吗?

感谢您的帮助。

1个回答

6

我不太清楚你想了解什么。显然,你对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

以上是您提供给我们的内容,经过一些微小的修正后得以编译。通常情况下,要使用check函数,您需要提供一个Arity签名的实现,并将其提供给S函数对象:

module AR = struct
  let arity = 3
end

module SAR = S(AR)

let () = Printf.printf "%b\n" SAR.check

让我们使用一流的模块:

let a = (module AR : Arity)

这将模块AR转换为一个值并将其绑定到变量a。请注意,括号在语法上是强制的。您还需要给出签名Arity。您也可以按以下方式编写:

let a' : (module Arity) = (module AR)

因此,a和a'的类型是(模块Arity),您需要以某种方式将其提供给编译器。不幸的是,在这里类型推断无法帮助我们。

您可以按以下方式将该值转换回模块:

module A' = (val a)

现在,您也可以将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)

s的作用是:接收一个值,将其转换为模块,对其应用函数器S,然后从函数器应用结果中创建另一个值。签名RESULT对于转换是必要的。你不能写成(module SA : sig val check bool end)。我不擅长这方面的事情,但是我听说一级模块值的类型检查不是结构性的而是命名的。在(module M : X)处需要给签名一个名称。
s的类型是(module Arity) -> (module RESULT)。让我们将s应用于a:
let m = s a

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

let m_check =
  let module M = (val m) in
  M.check

你可能会失望地发现,value<->module之间的转换是明确的,但这就是它的工作方式...


那么这意味着即使我使用一流的模块或不使用,我都必须为签名[Arity]定义一个实现模块[AR],是吗? - Quyen
这正是我不理解的关键。你的意思是,用非模块化的语言来说,“我想在一个函数 [let s a = let check = ...] 中使用/调用 [check],而不给出实际的[a]”。我的答案是“不行。没有将[s]应用到某些东西,[check]就永远不会被使用/调用”。但是也许你所谓的“使用/调用”是指其他不同的事情。 - camlspotter
我明白了,因为我想知道是否有一种方法可以在不实现“Arity”的情况下访问“check”函数。那么,一级模块的优点是什么呢?因为似乎第一种方法“module SAR = S(AR)”比一级模块简单得多。 - Quyen
2
一等模块是普通的OCaml值:例如,您可以将它们放在列表中。参考手册显示了这样的示例:根据设备选择不同的模块实现。普通模块不是一等公民。它们不是值,我们所能做的事情是有限的。 - camlspotter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接