尝试进一步了解OCaml的接口/模块

时间:2013-02-21 14:00:40

标签: functional-programming ocaml

我理解在OCaml中有interfacesmodule的概念。

我现在明白了如何使用它们。

然而,我不明白的是如何充分利用它们。


例如,在Java中,假设我们有一个接口Map,我们还有HashtableHashMap来实现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,会发生什么?我认为编译器不会抱怨,对吧?

3 个答案:

答案 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)