マニュアルによると
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で導入するパターンマッチングもすでにあるし、型安全性も問題なし。コンスもあるし。なぜ人気が出ないのだろう…