我理解在OCaml中有interfaces
和module
的概念。
我现在明白了如何使用它们。
然而,我不明白的是如何充分利用它们。
例如,在Java中,假设我们有一个接口Map
,我们还有Hashtable
和HashMap
来实现Map
。
在代码中,我可以这样做:
Map m = new Hashtable();
m.put("key", value);
有一天,如果我改变主意,我可以通过将Hashmap
更改为Map m = new Hashtable();
来更快地更改为Map m = new HashMap();
,对吗?
但我怎么能在Ocaml中轻松做到这一点?
例如,我在OCaml中有MapSig
和'HashMap:MapSig and "Hashtable:MapSig
。
如何轻松更改实施?
我认为我不能,因为在OCaml中我必须这样做:
let m = Hashtable.create ();;
Hashtable.put m key value;;
如果我想使用HashMap
,我必须在代码中用Hashtable
替换每个HashMap
,对吗?
我不仅在寻找一种为模块建立别名的方法。我还考虑了实现的有效性,即实现是否遵循所需的接口。
例如,在上面的Java示例中,仅当HashMap
已实现Map
接口时,我才能将Hashtable
替换为HashMap
。否则,Java编译器会抱怨。
但如果我在OCaml中执行module M = Hashtable
,并且HashMap
未遵循MapSig
并且我将Hashtable
替换为HashMap
,会发生什么?我认为编译器不会抱怨,对吧?
答案 0 :(得分:1)
从3.12.1开始,OCaml允许这种语法用于打开和别名模块:
let foo .... =
let module HashTable = HashMap in (* magic is here *)
let h = HashTable.create () in
....
所以你只需要在你使用它的地方重命名模块。
答案 1 :(得分:1)
这是一个显示我认为你要求的例子:
# module type HASH = sig type t val hash : t -> int end ;;
module type HASH = sig type t val hash : t -> int end
# module I = struct type t = int let hash i = i end ;;
module I : sig type t = int val hash : 'a -> 'a end
# module J = struct type t = int end ;;
module J : sig type t = int end
# module M : HASH = I ;;
module M : HASH
# module N : HASH = J ;;
Error: Signature mismatch:
Modules do not match: sig type t = int end is not included in HASH
The field `hash' is required but not provided
额外的“: HASH
”指定模块必须与HASH签名匹配(并且它还将其限制为该签名)。
正如旁边评论一样,我相信OCaml模块系统因其表现力而闻名世界(至少在模块系统圈子中)。我还是初学者,但值得研究。
答案 2 :(得分:0)
您的Java示例与OCaml之间最直接的对应关系是使用函子(OCaml在模块之间将静态函数称为模块)。因此,假设您在OCaml中实现了以下内容:
module type Map = sig
(* For simplicity assume any key and value type is allowed *)
type ('k, 'v) t
val make : unit -> ('k, 'v) t
val put : ('k, 'v) t -> ~key:'k -> ~value:'v -> unit
end
module Hashtable : Map = struct ... end
module HashMap : Map = struct ... end
然后,您将像这样编写函子:
module MyFunctor(Map : Map) = struct
let my_map =
let map = Map.make () in
Map.put map ~key ~value;
map
end
然后,您将使用函子实例化一个模块:
module MyModule = MyFunctor(Hashtable)
瞧,更改实现是单行差异,因为两个模块实现都符合Map
签名:
module MyModule = MyFunctor(HashMap)