在OCaml中,我正在处理一个模块和一个仿函数。使用参数化模块的OCaml
我为输入模块和仿函数设置了签名和结构。 然后我使用上面的模块创建了一个新模块。 原来,我的新模块不包含输入模块中的功能。
我应该能够使用我的新模块功能?顺便说一句,仿函数中的函数工作正常。 另外,我怎样才能确定它是否是一个有效的模块?
在OCaml中,我正在处理一个模块和一个仿函数。使用参数化模块的OCaml
我为输入模块和仿函数设置了签名和结构。 然后我使用上面的模块创建了一个新模块。 原来,我的新模块不包含输入模块中的功能。
我应该能够使用我的新模块功能?顺便说一句,仿函数中的函数工作正常。 另外,我怎样才能确定它是否是一个有效的模块?
在一个简单的设置,通过仿函数F
绑定的模块M
导出的任何值可以通过使用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
或通过之前的M
值的任何访问使用open 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
。
谢谢你的帮助,didierc。 – 2013-04-21 21:16:17
完成了我的答案,希望有更多有用的信息,但我担心我不能比@gasche做得更好。 – didierc 2013-04-21 21:56:19
让我们一个真实的例子:
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
提供建立在任何单子上面一些通用的功能,但它本身并不包含底座单子功能。它提供了额外的东西,而不包括现有的东西。
您可以更改使用include
项目包含模块的值内现有模块的内容被定义:
module MonadOps (M : MONAD) = struct
include M (* values from m *included* in the module *)
let rec mapM f = function
[...]
end
不过,我并不建议这样做。你正在引入一些冗余,这在某些情况下是很方便的(例如,如果你想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
谢谢gasche!我知道了。 – 2013-04-21 21:18:06
请显示一些源代码。我们将用一个小代码示例更好地理解您的问题.... – 2013-04-21 07:36:03