プログラミング in OCaml メモ

『プログラミング in OCaml』を呼んでて、ファンクターのところが難しかったので、頭を整理してみた。

ファンクターとは?

「要素型に関するモジュール」から「その型を要素とする集合モジュール」を生成する関数

例) Setモジュール(集合モジュール)には、Make という名前のファンクターがある。
このファンクターには、mem、add、inter、elements など、多くの関数が定義されており、Set.Make というファンクターでモジュールを作成することで利用可能である。

ファンクターを使う

Setモジュールを利用するためには、
1) 集合要素の型 t の定義
2) その型の大小比較の関数 compare : t -> t -> int
のふたつを含むモジュールが必要である。

方法1:

具体的には、以下のようなかたちで、自分の望む Set モジュールを手に入れることができる。

# module IntSet = Set.Make (struct
                              type t = int
                              let compare i j = i - j
                            end);;

# moduke 新モジュール名 = ファンクター名 ( モジュール式 )

方法2:

# module OrgInt =
    struct
      type t = int
      let compare i j = i - j
    end;;

# module IntSet = Set.Make (OrgInt);;

これは、以下のように、型を定義したモジュールを作成してからファンクターの引数に与えても良い。

ただ、コンパイラからの応答に若干の違いが出る。

方法1 の場合

module IntSet :
   sig
     type elt = int
     type t
     …

方法2 の場合

module IntSet :
  sig
    type elt = int
    type t = Set.Make(OrgInt).t
    ...

こちらの場合は、ファンクターの名前、もとのモジュールの名前が現れる。

ただ、作成したモジュール IntSet を使って、以下の式を評価した場合、方法1、方法2のどちらでも、コンパイラからの応答は同じである。

let my = IntSet.add 2 (IntSet.add 1 IntSet.empty);;
(* val my : IntSet.t = <abstr> *)

IntSet.elements my;;
(*  - : int list = [1; 2] *)