2021/09/09

OCamlでモジュールをうまく使えるようになりたい

マニュアルによると

OCamlのマニュアルのChapter3にオブジェクト指向についての記述があります。要約すると、”OCamlにおけるobject,class,typeはJavaやC++のようなメインストリームのオブジェクト指向言語とは違う。OCamlではそれらの機能をそれらの言語ほど頻繁には使わない。その代わりに、モジュールやファンクタを使う。” というようなことが書かれています。

他言語のclassなどのようにモジュールやファンクタを使えるということか。

つまり、モジュールやファンクタを上手に使えるようになれ、ということのようです。

モジュールはファーストクラス

OCamlのモジュールはファーストクラスだそうで、変数に束縛できるようです。

例えば、


module type Int_type = sig
  val x : int
end

module A : Int_type = struct
  let x = 123
end

と定義します。この場合、A.xとすることで123を扱えます。そして変数に束縛


let m = (module A : Int_type)

この状態だとm.xとしてもエラーになりますが、以下のようにアンパックすると


module B = (val m : Int_type)

B.xで123を扱えるようになります。これを利用してモジュール同士で足し算する関数が書けます。


let add m1 m2 =
  let module B = (val m : Int_type) in
  let module C = (val m : Int_type) in
  B.x + C.x
  

add m mとすると、246が返ってきます。

上記のように、関数に引数として渡すこともできます。

インクルードによって拡張していける

例えば以下のような何の変哲もないモジュールがあるとします。


module A = struct
  let a = 1
end

これを少し拡張した新しいモジュールを作りたい場合、includeキーワードを使って、以下のようなことができます。


module Ext_A = struct
  include A
  let b = 2
end

こうすると、Ext_A.aとすると、モジュールAのaを使うことができます。簡単に拡張することができます。

外部からのアクセス制御

OCamlのモジュールはモジュールインターフェースやシグネチャによって外部からのアクセスを制御することができます。

例えば、以下のようなモジュールがあるとします。


module A = struct
  let x = 1
  let y = 2
end

しかし、yのほうは外部に公開したくない、そんな時、以下のようなシグネチャを追加します。


module type A_type = sig
  val x : int
end
module A : A_type = struct
  let x = 1
  let y = 2
end

こうすると、A.xは使えますが、A.yは非公開になるためエラーとなります。A.yはつまり、Aモジュールのprivateな変数ということになります。

まとめ

OCamlのモジュールの勉強をしていると、たしかにクラスを使わなくてもなんだかできそうな気がするようになってきました。かのクラスいっぱいのJavaも9からモジュールシステムを導入したぐらいですから、クラスよりもモジュールのほうが、管理する上で、なにかと都合がよいのかもしれません。となると、OCamlの一時代が到来するのかもしれません。OCamlは高速で、モジュールシステムがあり、Pythonが3.10で導入するパターンマッチングもすでにあるし、型安全性も問題なし。コンスもあるし。なぜ人気が出ないのだろう…