OCaml一人勉強会 - モジュール

少し間が空きました。
さて OCaml では型や変数や関数の定義を管理するための仕組みが備わっています。今時無い言語も珍しいですが。
まあなんていうか、普通にモジュールです。 C++ で言う名前空間に近いものです。
自分でモジュールを定義するには、以下のような構文を使います。

# module Hello = struct
    let say target = print_endline ("hello, " ^ target ^ "!")
  end;;
module Hello : sig val say : string -> unit end
# Hello.say "world";;
hello, world!
- : unit = ()
# open Hello;;
# say "ocaml";;
hello, ocaml!
- : unit = ()

使い方はこれまで標準ライブラリとかの例で使いまくってるのでもういいや。まあこういうものです。
ちなみに分割コンパイルの際にもモジュールが使われます。実装と定義(インターフェイス)を分けることが出来たりして中々良いものですが、めんどくさいので省略します。
省略はまずいだろ!適当にまとめると、

  • module_name.ml というファイル内の物は Module_name という名のモジュールにパッケージングされる。
  • 実装は拡張子 ml に。
  • インターフェイスは拡張子 mli に。

という感じです。
勿論対話式にインターフェイスを提供することもできます。
OCaml には型推論があるので、これまで変数や関数や引数等にわざわざ型を書くことはしませんでしたが、実は「明示的」に書く事もできます。

# let a : int = 5;;
val a : int = 5
# let f (x : int) (y : int) : int = x + y;;
val f : int -> int -> int = <fun>

勿論誤った型を書いた場合は叱られます。

# let a : double = 5;;
Characters 8-14:
  let a : double = 5;;
          ^^^^^^

通常なら型変数が使われるような多相的な関数の引数を制限することも可能です。

# let f x = x;;
val f : 'a -> 'a = <fun>
# let f (x : int) : int = x;;
val f : int -> int = <fun>

モジュールで同じようなことをするためには、以下のような構文を使います。

module Hello : sig val say : string -> unit end = struct
    let say target = print_endline ("hello, " ^ target ^ "!")
  end;;

sig から end が定義ですね。まあややこしいのであまり書きたくはないです。