参数化仿函数

Parameterized functors

假设我有这些签名:

module type CharS = sig
type c
  type t = BoW | C of c | EoW

  val compare : t -> t -> int

  val print : Format.formatter -> t -> unit
end

module type GraphemS = sig

  type c
  type t

  val compare : t -> t -> int
  val print : Format.formatter -> t -> unit
end

还有这两个函子:

module MakeDiGraphem (C : CharS) : GraphemS with type c = C.t = struct

  type c = C.t
  type t = c * c

  let compare (cb1, ce1) (cb2, ce2) =
    let r1 = C.compare cb1 cb2 in
    if r1 = 0 then
      C.compare ce1 ce2
    else r1

  let print fmt (cb, ce) =
    Format.fprintf fmt "@[%a%a@]@," C.print cb C.print ce

end

module MakeMonoGraphem (C : CharS) : GraphemS with type c = C.t = struct

  type c = C.t
  type t = c

  let compare c1 c2 = C.compare c1 c2

  let print fmt c =
    Format.fprintf fmt "@[%a@]@," C.print c

end

现在,我想要一个仿函数,它允许我用第一个或第二个仿函数创建一个 GraphemS 类型的模块。我所做的是这样的:

module type SizeS = sig
  type t = int

  val param : int
end

module MakeGraphem (C : CharS) (I : SizeS) : GraphemS with type c = C.t = struct
  module MonoGraphem = MakeMonoGraphem(C)
  module DiGraphem = MakeDiGraphem(C)

  let select_graphem =
    if I.param = 1 then
      (module MonoGraphem : GraphemS)
    else
      (module DiGraphem : GraphemS)

  include (val select_graphem)

end

但遗憾的是我得到了:

Error: This expression creates fresh types.

It is not allowed inside applicative functors.

那么我的问题是,是否可以做我想做的事,这个错误是什么意思?

基本上,您不能在 applicative functor 应用程序 include 中进行 first-class 计算。基本上,类型系统不能保证 I.param 是一个常量,所以它不能确保仿函数总是 return 相同的类型。应用仿函数(OCaml 中的默认值)必须始终 return 同一表达式的相同类型(从某种意义上说,它是纯粹的)。

如果您使用的是 OCaml 4.02 或更高版本,您可以通过 unit argument:

将仿函数声明为生成函数
module MakeGraphem (C : CharS) (I : SizeS) () :
           GraphemS with type c = C.t = struct

我最喜欢的方法是让仿函数作为参数应用而不是 I