インターフェイスファイル

2008年3月20日
1 分

ソースファイル(=モジュール)と同名で拡張子が .mli のファイルを用意しておくことで,モジュールにシグネチャを与えることができる。

前にも例に挙げた Table モジュールを例にとると,

table.mli

type ('a, 'b) t
val empty : ('a, 'b) t
val add : 'a -> 'b -> ('a, 'b) t -> ('a, 'b) t
val retrieve : 'a -> ('a, 'b) t -> 'b option
val dump : ('a, 'b) t -> ('a * 'b) list

table.ml

type ('a, 'b) t = Empty | Entry of 'a * 'b * ('a, 'b) t

let empty = Empty

let add key content table = Entry (key, content, table)

let rec retrieve key = function
  Empty -> None
| Entry (key', content, rest) ->
  if key = key' then Some content else retrieve key rest

let rec delete key = function
  Empty -> Empty
| Entry (key', content, rest) ->
  if key = key' then delete key rest
                else Entry (key', content, delete key rest)

let rec dump = function
  Empty -> []
| Entry (key, content, rest) ->
  (key, content) :: (dump (delete key rest))

こういう風にtable.mliとtable.mlを書く。これで

module type TABLE =
  sig
    ...
  end

module Table : TABLE =
  struct
    ...
  end

と書いたのと同じになる。

コンパイルするときは,インターフェイス(mli)ファイルを先にコンパイルする。手順としては

  1. 各mliファイルを ocamlc でコンパイル(cmiファイルができる)
  2. 各mlファイルを ocamlc -c でコンパイル(cmoファイルができる)
  3. 全cmoファイルを ocamlc でリンク

となる。mlファイルよりもmliファイルを先にコンパイルしておくことに注意。でないとcmiファイルがないので,コンパイラが推論して勝手にcmiファイルを作り,意図したのと違うことになる。