0

OCaml では、モジュールとファンクタを扱っています。

入力モジュールとファンクターの署名と構造体をセットアップしました。次に、上記のモジュールを使用して新しいモジュールを作成しました。私の新しいモジュールには、入力モジュールに関数が含まれていないことが判明しました。

新しいモジュールで関数を使用できるはずですか? ちなみに、ファンクター内の関数は正常に動作します。また、有効なモジュールかどうかを確認するにはどうすればよいですか?

4

2 に答える 2

5

実際の例を見てみましょう:

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

ただし、必ずしもそうするようにアドバイスするわけではありません。状況によっては便利な冗長性を導入していますが(たとえば、open1つのモジュールだけを使用してすべてをスコープ内に収めたい場合)、他の状況でいくつかの問題を引き起こす可能性もあります。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
于 2013-04-21T09:20:10.357 に答える
2

より単純な設定では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コンテンツが必要な場合は、何らかの方法で提供する必要があります。GM

于 2013-04-21T20:28:43.980 に答える