モジュールのincludeがよくわかりません
バインディングばっかり書いていましたが、とりあえず一段落したので、OCamlのみを利用したライブラリを作っている時に、なんでそうなるのかがいまいちわからない現象に会いました。
色々なライブラリの実装を眺めながら作ってるときに起こったので、どういう原因なのかがさっぱりわかりませんが、とりあえず再現できました。
こんな型を作ってみる。 # type ('a, 'b) tmp_a = 'a -> int;; type ('a, 'b) tmp_a = 'a -> int # type ('a, 'b) tmp_b = 'b;; type ('a, 'b) tmp_b = 'b シグネチャの中で上の型と同じ型変数を取る型を宣言する # module type A = sig type ('a, 'b) t val a: ('a, 'b) t -> int end;; module type A = sig type ('a, 'b) t val a : ('a, 'b) t -> int end 定義したシグネチャを使い、モジュールの実体を定義してみる(ここではtはtmp_b = 'bとしていって欲しい) # module B : A = struct type ('a, 'b) t = ('a, 'b) tmp_b let a = int_of_float end;; 型が合わんと怒られる。まぁこれはなんとな Characters 15-83: ...............struct type ('a, 'b) t = ('a, 'b) tmp_b let a = int_of_float end.. Error: Signature mismatch: Modules do not match: sig type ('a, 'b) t = ('a, 'b) tmp_b val a : float -> int end is not included in A Values do not match: val a : float -> int is not included in val a : ('a, 'b) t -> int include + with type でもやっぱり駄目 # module C : sig type ('a, 'b) t_ = ('a, 'b) tmp_b include A with type ('a, 'b) t := ('a, 'b) t_ end = struct type ('a, 'b) t_ = ('a, 'b) tmp_b let a = int_of_float end;; Characters 105-174: ......struct type ('a, 'b) t_ = ('a, 'b) tmp_b let a = int_of_float end.. Error: Signature mismatch: Modules do not match: sig type ('a, 'b) t_ = ('a, 'b) tmp_b val a : float -> int end is not included in sig type ('a, 'b) t_ = ('a, 'b) tmp_b val a : ('a, 'b) t_ -> int end Values do not match: val a : float -> int is not included in val a : ('a, 'b) t_ -> int let a に型注釈を入れても駄目。 # module D : sig type ('a, 'b) t_ = ('a, 'b) tmp_b include A with type ('a, 'b) t := ('a, 'b) t_ end = struct type ('a, 'b) t_ = ('a, 'b) tmp_b let a:(('a, 'b) t_ -> int) = int_of_float end;; Characters 105-195: ......struct type ('a, 'b) t_ = ('a, 'b) tmp_b let a:(('a, 'b) t_ -> int) = int_of_float end.. Error: Signature mismatch: Modules do not match: sig type ('a, 'b) t_ = ('a, 'b) tmp_b val a : ('a, float) t_ -> int end is not included in sig type ('a, 'b) t_ = ('a, 'b) tmp_b val a : ('a, 'b) t_ -> int end Values do not match: val a : ('a, float) t_ -> int is not included in val a : ('a, 'b) t_ -> int tmp_bの型を具体化するといける。 # module D : sig type ('a, 'b) t_ = ('a, float) tmp_b include A with type ('a, 'b) t := ('a, 'b) t_ end = struct type ('a, 'b) t_ = ('a, float) tmp_b let a = int_of_float end;; module D : sig type ('a, 'b) t_ = ('a, float) tmp_b val a : ('a, 'b) t_ -> int end #
今直面している問題としては、このmodule Cの状態でなんとかしてコンパイルが通らんか、という問題です。
実際には、上で言えばmodule Cがファンクターで、t_にはファンクターの型が与えられている状態なのですが、それでもやっぱり通りません。型推論の勉強なんてしてませんが(すみません)、推論の限界みたいなものなんでしょうか。もしくはシグネチャマッチングにおいて、自分が勘違いしているとか・・・。そっちの方がありそうか。
まぁ、他の実装方法を探せばいいだけなんだとは思いますが、どうにも釈然としないので・・・。