ndb*_*dbd 5 ocaml module functor
发布这样长而不可编译的代码的道歉.但是尽管在ocaml的仿函数上阅读了stackoverflow上的几个问题和答案,我还是得不到如何解决这个问题:
假设我有一个非常抽象的数据结构:
ads.mlimodule type ENTRY = sig
type t
val get_index : t -> int
val compare : t -> t -> int
end
module type T = sig
type entry
type t
val create : unit -> t
val insert : entry -> t -> t
val delete : entry -> t -> t
end
Run Code Online (Sandbox Code Playgroud)
基于此,我可以通过传递函数在这些抽象实现上建立具体的数据结构.例如,我做了:
concrete_ads.mlimodule Make (Entry: Ads.ENTRY) : (ads.T with type entry = Entry.t)
Run Code Online (Sandbox Code Playgroud)
这项工作,我现在可以在其他源文件中使用我的实现,例如:
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);;
Run Code Online (Sandbox Code Playgroud)
然后,使用如下的实现:
let at = AT.create () in
let ati = AT.insert (1,2) at in
let atd = AT.delete (1,2) ati in
Run Code Online (Sandbox Code Playgroud)
...等
现在,我想在一个单独的源文件中编写几个对这些数据结构进行操作的函数,它们应该可以从外部访问.但是,我不知道如何声明这些函数的类型.像这样的东西:
search.mlival search : Int -> Ads.T -> int list
Run Code Online (Sandbox Code Playgroud)
但是,在编译时,我得到:
Failure: "invalid long identifier type"
Run Code Online (Sandbox Code Playgroud)
然后,我认为我需要专门将adt的模块声明为子模块search.mli,例如:
search.mlimodule AD = Ads;;
...
val search : Int -> AD.T -> int list
Run Code Online (Sandbox Code Playgroud)
但是,我得到:
Parse error: [module_declaration] expected after [a_UIDENT] (in [sig_item])
Run Code Online (Sandbox Code Playgroud)
我在这里错过了什么?我觉得我要么失败了语法,要么没有完全掌握Functors,Modules和Submodules的概念......
编辑非常感谢你的解释,加油!通过你的例子,我能够写出我想要的东西.我将在此处发布以便澄清,因为似乎很多关于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;;
Run Code Online (Sandbox Code Playgroud)
并且,在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;;
Run Code Online (Sandbox Code Playgroud)
它完全符合我的预期.
你准备做什么?您是希望您的功能通过广告类型(例如Ads.T.t)或广告模块(例如Ads.T)进行参数化?
在这两种情况下,您应该将这些泛型函数包装在模块中:
module Generic (Ad : Ads.T) : sig
val search : int -> Ad.t -> int list
end = struct
let search _ _ = assert false
end
Run Code Online (Sandbox Code Playgroud)
然后,您可以轻松地实例化它们,例如.使用您的Conrete_ads模块:
module AT = Concrete_ads.make(struct ... end)
module Lib = Generic(AT)
let foo = Lib.search 2 (AT.create ())
Run Code Online (Sandbox Code Playgroud)
当然,如果您希望将函数在特定的具体类型上进行参数化:
val search : int -> AT.t -> int list
Run Code Online (Sandbox Code Playgroud)
PS:在你的定义中AT,你忘记了仿函数struct的struct .. end模块参数.
PPS:使用OCaml 3.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) ...
Run Code Online (Sandbox Code Playgroud)
(说明:module S,作为类型表达式,是签名的"具体模块"的值的类型S; (val t : S)作为模块表达式,是包含在值中的模块t,带有签名S.这里我将其ad_module作为值并解压缩它Ad本地进入模块,然后可以用作函数内的任何其他模块.最后,(module M : S)是一个术语表达式,它将M带有签名的模块打包S成一个值.)
它可以在某些情况下使用仿函数进行补充,但由于它是新的,有点复杂(对使用一流模块有一些非平凡的限制),并且可能会在下一个语言版本中稍微改变一下,I会建议保持经过验证的仿函数构造.
| 归档时间: |
|
| 查看次数: |
2246 次 |
| 最近记录: |