使用参数化模块的OCaml
在OCaml中,我处理的是一个模块和一个函子 我为输入模块和函子设置了签名和结构。 然后我使用上面的模块制作了一个新模块。 事实证明,我的新模块在输入模块中不包含函数 我应该能够在我的新模块中使用函数吗? 顺便说一下,函子中的函数工作得很好。使用参数化模块的OCaml,ocaml,Ocaml,在OCaml中,我处理的是一个模块和一个函子 我为输入模块和函子设置了签名和结构。 然后我使用上面的模块制作了一个新模块。 事实证明,我的新模块在输入模块中不包含函数 我应该能够在我的新模块中使用函数吗? 顺便说一下,函子中的函数工作得很好。 另外,如何确保它是否是有效的模块 让我们举一个真实的例子: module type MONAD = sig type 'a t val return : 'a -> 'a t val (>>=) : 'a t -> ('
另外,如何确保它是否是有效的模块 让我们举一个真实的例子:
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 *)
然而,我不一定建议这样做。您引入了一些冗余,这在某些情况下是很方便的(例如,如果您想只打开一个模块,并且所有内容都在范围内),但在其他情况下也会造成一些问题,例如,如果您想组合两个模块扩展函子,您必须考虑应用它们的顺序,你可能会遇到奇怪的模块系统黑客。ML模块系统内部非常复杂,我建议您保持简单的使用,以避免陷入困境
请注意,如果不将M包含在functor中,则可以让functor的用户随时选择执行此操作:如果您决定将M直接包含在functor中,则他们有更多选项。我使用这样一个函子的方式是
(* 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.
限定符(与任何模块一样)访问functorF
中绑定的模块M
导出的任何值:
或者在访问M
的值之前使用openm
module F (M : sig val v : int end) =
struct
open M
let m_v = v
end
如果要从F
生成的模块中获取M
的值,必须以某种方式导出该值,或者:
- 直接通过在新模块中对
M
的某些值进行混叠
module F (...) = struct
let v = M.v
end
- 包括整个模块
module F (...) = struct
include M
end
包含并不总是可能的或易于使用的,因为您可能希望在M
中定义与其他类型冲突的类型名称
module F (M : sig val v : int end) =
struct
open M
let m_v = v
end
使模块成为新模块的一部分
module F (....) = struct
module M' = M
end
module G = F(struct let v = 5 end);;
print_int G.M.v;;
包括还是不包括?它取决于函子的客户端和生成的模块的客户端。您可能在一个程序上工作,该程序必须只知道生成的模块,或者只知道函子。如果模块M
内容是操作模块G
所必需的,并且该模块是现成交付的,那么您必须以某种方式提供M
。请显示一些源代码。通过一个小的代码示例,我们将更好地理解您的问题……非常感谢您的帮助,didierc。我希望用更多有用的信息完成我的回答,尽管我恐怕不能比@gasche做得更好。谢谢您gasche!我得到了它。
module F (....) = struct
module M' = M
end
module G = F(struct let v = 5 end);;
print_int G.M.v;;