OCaml では、モジュールとファンクタを扱っています。
入力モジュールとファンクターの署名と構造体をセットアップしました。次に、上記のモジュールを使用して新しいモジュールを作成しました。私の新しいモジュールには、入力モジュールに関数が含まれていないことが判明しました。
新しいモジュールで関数を使用できるはずですか? ちなみに、ファンクター内の関数は正常に動作します。また、有効なモジュールかどうかを確認するにはどうすればよいですか?
OCaml では、モジュールとファンクタを扱っています。
入力モジュールとファンクターの署名と構造体をセットアップしました。次に、上記のモジュールを使用して新しいモジュールを作成しました。私の新しいモジュールには、入力モジュールに関数が含まれていないことが判明しました。
新しいモジュールで関数を使用できるはずですか? ちなみに、ファンクター内の関数は正常に動作します。また、有効なモジュールかどうかを確認するにはどうすればよいですか?
実際の例を見てみましょう:
module type MONAD = sig
type 'a t
val return : 'a -> 'a t
val (>>=) : 'a t -> ('a -> 'b t) -> 'b t
end
module MonadOps (M : MONAD) = struct
open M (* values from M visible in scope *)
let rec mapM f = function
| [] -> return []
| x::xs ->
f x >>= fun y ->
mapM f xs >>= fun ys ->
return (y :: ys)
end
module Option = struct
type 'a t = 'a option
let return x = Some x
let (>>=) m f = match m with
| None -> None
| Some x -> f x
end
module OptionOps = MonadOps(Option)
let test = OptionOps.mapM
(* val test : ('a -> 'b Option.t) -> 'a list -> 'b list Option.t = <fun> *)
let test = OptionOps.return x
(* Error: Unbound value OptionOps.return *)
ファンクターMonadOps
は、モナドの上に構築されたいくつかの一般的な機能を提供しますが、それ自体には基本モナドの機能は含まれていません。既存のものを含めずに余分なものを提供します。
item を使用して、include
定義されているモジュール値内に既存のモジュールのコンテンツを含めることで、これを変更できます。
module MonadOps (M : MONAD) = struct
include M (* values from m *included* in the module *)
let rec mapM f = function
[...]
end
ただし、必ずしもそうするようにアドバイスするわけではありません。状況によっては便利な冗長性を導入していますが(たとえば、open
1つのモジュールだけを使用してすべてをスコープ内に収めたい場合)、他の状況でいくつかの問題を引き起こす可能性もあります。2 つのモジュール拡張ファンクターを組み合わせたい場合、それらをどの順序で適用するかを考える必要があり、奇妙なモジュール システム ハッカーに遭遇する可能性があります。ML モジュール システムは内部が複雑な獣であるため、コーナーにぶつからないように、使い方をシンプルに保つことをお勧めします。
M をファンクターに含めないことにより、ファンクターのユーザーがいつでも実行できるようにすることに注意してください。ファンクターに直接含めることを決定した場合、ユーザーにはより多くのオプションがあります。そのようなファンクターを使用する方法は次のようになります
(* file 'option.ml' *)
type 'a option = None | Some of 'a
module Monad = struct
...
end
module Ops = MonadOps(Monad)
include (Monad : MONAD with type 'a t := 'a option)
include Ops
より単純な設定ではM
、ファンクターにバインドされたモジュールによってエクスポートされた値F
は、修飾子を使用してアクセスできますM.
(他のモジュールと同様):
(* out there M does not exist *)
module F (M : sig val v : int end) =
struct
(* in there M is defined *)
let m_v = M.v
end
またはopen M
の値にアクセスする前にを使用しますM
。
module F (M : sig val v : int end) =
struct
open M
let m_v = v
end
M
によって生成されたモジュールからの値を利用できるようにしたい場合はF
、次のいずれかの方法でそれをエクスポートする必要があります。
M
新しいモジュールで の特定の値を直接エイリアスすることにより、
module F (...) = struct
let v = M.v
end
モジュール全体を含めることによって
module F (...) = struct
include M
end
で他のタイプと衝突するタイプ名を定義したい場合があるため、常に可能または簡単に含める必要はありませんM
。
モジュールを新しいモジュールの一部にすることによって
module F (....) = struct
module M' = M
end
module G = F(struct let v = 5 end);;
print_int G.M.v;;
含めるか含めないか これは、ファンクターのクライアント側と、生成されたモジュールのクライアント側に依存します。生成されたモジュールについてのみ知っている必要があるプログラム、またはファンクターについてのみ知っている必要があるプログラムで作業する場合があります。既製のモジュールを操作するためにモジュールのM
コンテンツが必要な場合は、何らかの方法で提供する必要があります。G
M