Module Ocaml函子、模和子模

Module Ocaml函子、模和子模,module,ocaml,functor,Module,Ocaml,Functor,很抱歉发布了这么长的、不可编译的代码。但是,尽管阅读了关于ocaml函数stackoverflow的几个问题和答案,我还是不知道如何解决这个问题: 假设我有一个非常抽象的数据结构: ads.mli 基于此,我可以通过传递一个函子在这些抽象实现上创建具体的数据结构。例如,我提出: concrete_ads.mli 在这项工作中,我现在可以在其他源文件中使用我的实现,例如: module AT = Concrete_ads.Make( type t = int * int;; l

很抱歉发布了这么长的、不可编译的代码。但是,尽管阅读了关于ocaml函数stackoverflow的几个问题和答案,我还是不知道如何解决这个问题:

假设我有一个非常抽象的数据结构:

ads.mli
基于此,我可以通过传递一个函子在这些抽象实现上创建具体的数据结构。例如,我提出:

concrete_ads.mli
在这项工作中,我现在可以在其他源文件中使用我的实现,例如:

module AT = Concrete_ads.Make( 
    type t = int * int;; 
    let get_index = fst;; 
    let to_string = (fun (x,y) -> Printf "%i, %i" x y);; 
end);;
然后,使用如下实现方式:

let at = AT.create () in
let ati = AT.insert (1,2) at in
let atd = AT.delete (1,2) ati in
。。。等等

现在,我想在一个单独的源文件中编写几个对这些数据结构进行操作的函数,它们应该可以从外部访问。但是,我不知道如何声明这些函数的类型。大概是这样的:

module AT = Concrete_ads.Make( 
    type t = int * int;; 
    let get_index = fst;; 
    let to_string = (fun (x,y) -> Printf "%i, %i" x y);; 
end);;
search.mli
但是,在编译时,我得到:

 Failure: "invalid long identifier type"
一、 然后,我想我需要将adt的模块具体声明为
search.mli
中的子模块,类似于:

search.mli
但是,我得到:

Parse error: [module_declaration] expected after [a_UIDENT] (in [sig_item])
我错过了什么?我觉得我要么语法不好,要么没有完全掌握函子、模和子模的概念

编辑非常感谢您的解释,加斯奇!以你为例,我能写出我所说的。我将把它贴在这里澄清,因为在ocaml中似乎有很多关于函子的混淆

事实上,我想将函数抽象为关于
Ads.T
,但需要为
Ads.T.T
指定一种类型

我现在有了
search.mli

module Make (T : Ads.T with type entry = int * int) : sig
    val search : T.t -> int -> int
end;;
search.ml
中:

module Make (T : Ads.T with type entry = int * int) : sig
    val search : T.t -> int -> int 
end = struct
    (* actual implementation of search *)
end;;

它完全按照我的预期工作。

你到底想做什么?您希望通过ad类型(例如,
Ads.T.T
)或ad模块(例如,
Ads.T
)对功能进行参数化吗

在这两种情况下,您都应该将这些通用函数包装在模块中:

module Generic (Ad : Ads.T) : sig
  val search : int -> Ad.t -> int list
end = struct
  let search _ _ = assert false
end
然后,您可以轻松地实例化它们,例如,要使用
Conrete\u ads
模块:

module AT = Concrete_ads.make(struct ... end)
module Lib = Generic(AT)
let foo = Lib.search 2 (AT.create ())
当然,如果您只想在特定的具体类型上对函数进行参数化:

val search : int -> AT.t -> int list
注:在你对
的定义中,你忘记了
结构中的
结构。。结束
函子的模块参数

PPS:在OCAML3.12中,有一个新的东西叫做,它允许将模块作为值参数传递给函数

val search : int -> (module Ad.T) -> int list

let search n ad_module =
  let module Ad = (val ad_module : Ad.T) in
  ... Ad.foo ..

... search 2 (module AT : Ad.T) ...
(说明:
modules
作为一种类型表达式,是签名
S
的“具体化模块”的值类型;
(val t:S)
作为一个模块表达式,是打包到值
t
中的模块,带有签名
S
。这里我将
ad\u模块
作为一个值,并将其解包到本地
ad
模块中,然后可以将其用作函数中的任何其他模块。最后,
(模块M:S)
是一个术语表达式,它将带有签名的模块
M
打包为一个值。)


在某些情况下,它可以使用函子进行补充,但由于它是新的,更为复杂(在使用一级模块时存在非平凡的限制),并且可能在下一个语言版本中有所改变,我建议保留久经考验的函子结构。

@ndbd:我添加了一些关于一流模块的内容,这可能会满足您的好奇心。但是远离那些新的闪亮的东西!
module AT = Concrete_ads.make(struct ... end)
module Lib = Generic(AT)
let foo = Lib.search 2 (AT.create ())
val search : int -> AT.t -> int list
val search : int -> (module Ad.T) -> int list

let search n ad_module =
  let module Ad = (val ad_module : Ad.T) in
  ... Ad.foo ..

... search 2 (module AT : Ad.T) ...