参数化仿函数

时间:2016-09-23 08:29:47

标签: ocaml functor

假设我有这些签名:

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

但遗憾的是我得到了:

  

错误:此表达式创建新类型。

     

不允许在applicative functors中使用。

我的问题是,是否有可能做我想做的事情以及这个错误意味着什么?

1 个答案:

答案 0 :(得分:2)

基本上,您不允许在应用程序仿函数应用程序中进行一流计算。基本上,打字系统无法保证I.param是常量,因此它无法确保仿函数始终返回相同的类型。应用仿函数(OCaml中的默认值)必须始终为同一表达式返回相同的类型(在某种意义上,它是纯粹的)。

如果您使用的是OCaml 4.02或更高版本,则可以通过unit argument将您的仿函数声明为生成:

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

我最喜欢的做法是将仿函数作为参数而不是I来应用。