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

ソースファイル(=モジュール)と同名で拡張子が .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ファイルを作り,意図したのと違うことになる。