OCaml で Abstract モジュール型を実現する方法
目次
概要
オブジェクト指向でいうところの、抽象基底クラスを実現する方法。
なお、OCaml では オブジェクトも扱えるが、ここでは ABC モジュールの実現を考えてみる。
このdiscuss を見て、なるほどとなったのでまとめてみたというのが背景。
抽象基底クラスの理解については、Python の この章
を参考にした。
ABCモジュール型の定義
ABCモジュールを以下のように定義する。
ここでは、ABCの頭文字を取って、Aモジュール型とした。
※いやー、OCamlにはモジュール型(sig..end
)とモジュール(struct...end
)があって混乱しますね…
というわけで、これらについてはOCamlのモジュール (ストラクチャ) とモジュール型 (シグネチャ)
を参考にしてください。
module type A = sig
type t
type err
type 'a do_things = t -> ('a, err) result
end
Aモジュール型は、型t
と型err
、任意の型で表現される'a do_things
を持つ。
型t
はAモジュール型が扱う型の総称と思ってもらえれば良い(と思う)。
型err
は、その名の通りAモジュール型が定義するエラー型。
型'a do_things
は、ちょっと複雑。なにせ、型名が'a do_things
だ。
そもそも、'a
とは何かというと、多相を表す。多相とは何かというと、任意の型を取れるよ
ということ。
つまり、string do_things
でもint do_things
でも良い。
で、'a do_things
型は、t
型をとり、('a, err) result
(('a, err)
で表現されるresult型)を返す。
多分、ABCモジュール型は抽象的すぎて具体例がないとイメージが沸かないと思うので、ABCモジュール実装を利用する例を次に見ていく。
ABCモジュールの定義
例えば、ABCモジュール型を利用したMy_a
モジュールを考えてみる。
module My_a : A with type t = int and type err = string = struct
type t = int
type err = string
type 'a do_things = t -> ('a, err) result
end
My_a
は、Aモジュール型が持つ型t
をint
、型err
をstring
と定義した
ものだ。
ABCモジュールの利用
さらに、ここでAモジュール型に値を追加した、別のCモジュール型を考えてみる。
module type C = sig
module A: A
val of_int: int -> A.t
val make: string A.do_things
end
module A: A
はAモジュール型(コロン:
より右側)をAという名前で扱いますよ、という宣言。
※ 表現が回りくどいよ!まぁざっくり言うとAモジュール型を使いますよってことでOK。
Cモジュール型は、of_int
(int型の値を引数にとり、A.t
型を返す)とmake
(string A.do_thigns
型を返す。
string
はAモジュール型の'a
に相当)を定義したものだ。
さて、Cモジュール型を定義したことで、具体的にAモジュールの型を利用する準備が整った。
以降では、このCモジュール型を利用する具体例を見ていく。
Cモジュールの利用
いよいよ、上記で定義したモジュールを利用する時が来た。
module My_c: C = struct
module A = My_a
let of_int x = x
let make x =
print_endline (string_of_int x) ;
Ok "ok"
end
module A = My_a
はCモジュール型内で利用するモジュールAを、My_a
と見立てて、
(つまり、Aモジュール型で宣言されていたt
はint
型、err
はstring
型で)扱う。
of_int
は、x
(これはCモジュール型によるとint
型であることがわかる)を引数にとり、x
(これはCモジュール型によるとA.t
であることがわかる)を返す。
make
はx
(これはMy_a
モジュールによればt
型)を取り、Ok "ok"
(これはCモジュール型によれば(string, err) result
)を返す。
make
の実行例は以下のような感じ。
My_c.make (My_c.of_int 1)
(* 結果 *)
1
- : (string, My_c.A.err) result = Ok "ok"