假设我有这些签名:
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中使用。
我的问题是,是否有可能做我想做的事情以及这个错误意味着什么?
答案 0 :(得分:2)
基本上,您不允许在应用程序仿函数应用程序中进行一流计算。基本上,打字系统无法保证I.param
是常量,因此它无法确保仿函数始终返回相同的类型。应用仿函数(OCaml中的默认值)必须始终为同一表达式返回相同的类型(在某种意义上,它是纯粹的)。
如果您使用的是OCaml 4.02或更高版本,则可以通过unit argument将您的仿函数声明为生成:
module MakeGraphem (C : CharS) (I : SizeS) () :
GraphemS with type c = C.t = struct
我最喜欢的做法是将仿函数作为参数而不是I
来应用。