OCaml使用参数化模块

Pet*_*ang 0 ocaml

在OCaml中,我正在处理模块和仿函数.

我为输入模块和仿函数设置了签名和结构.然后我使用上面的模块制作了一个新模块.事实证明,我的新模块不包含输入模块中的功能.

我应该能够在我的新模块中使用功能吗?顺便说一下,仿函数中的函数工作得很好.另外,如何确定它是否是有效的模块?

gas*_*che 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 *)
Run Code Online (Sandbox Code Playgroud)

MonadOps仿函数提供了一些构建在任何monad之上的通用特性,但它本身并不包含基本monad特性.它提供额外的东西,而不包括现有的东西.

您可以通过使用该项来更改它,以在include定义的模块值中包含现有模块的内容:

module MonadOps (M : MONAD) = struct
  include M (* values from m *included* in the module *)
  let rec mapM f = function
    [...]
end
Run Code Online (Sandbox Code Playgroud)

但是,我不一定建议这样做.在某些情况下,您会介入一些方便的冗余(例如,如果您只想要open一个模块并且具有范围内的所有内容),但也可以在其他情况下解决某些问题,例如.如果你想要组合两个模块扩展仿函数,你必须想知道应用它们的顺序,你可能会遇到奇怪的模块系统hackery.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
Run Code Online (Sandbox Code Playgroud)