OCaml中如何调用模块实现内定义的构造函数?
问题
我在名为monoids.ml的文件中定义了如下模块签名和实现:
module type MonoidADT = sig type 'a monoid (* . . . *) end module Monoid : MonoidADT = struct type 'a monoid = Monoid of ('a list) * ('a -> 'a -> 'a) * ('a) (* . . . *) end
我想在其他文件(模块)中使用实现里定义的构造函数Monoid,但直接打开模块调用时出现了Unbound constructor Monoid错误:
open Monoids.Monoid;; let boolean_monoid = Monoid ([true; false], ( || ), false);;
请问该如何正确使用这个构造函数?是必须创建工厂函数,还是有其他方法直接访问?
解决方案
出现错误的核心原因是:你给Monoid模块加上了MonoidADT签名约束,而这个签名仅对外暴露了'a monoid类型,未公开构造函数Monoid。在OCaml中,模块签名相当于对外接口,未在签名中声明的内容(包括构造函数)会被隐藏,外部无法直接访问。
你有两种可行的解决方式:
方式一:修改签名,公开构造函数
直接在MonoidADT签名中显式声明构造函数,让外部可以直接使用Monoid构造函数:
module type MonoidADT = sig type 'a monoid = Monoid of ('a list) * ('a -> 'a -> 'a) * ('a) (* . . . *) end module Monoid : MonoidADT = struct type 'a monoid = Monoid of ('a list) * ('a -> 'a -> 'a) * ('a) (* . . . *) end
修改后,外部代码就能像你最初尝试的那样直接调用构造函数。
方式二:保留签名封装,添加工厂函数
如果希望保持封装性、不暴露构造函数的具体实现,可以在模块签名和实现中添加一个工厂函数,用来创建'a monoid类型的值:
首先更新签名:
module type MonoidADT = sig type 'a monoid val create : 'a list -> ('a -> 'a -> 'a) -> 'a -> 'a monoid (* . . . *) end
然后实现模块中的工厂函数:
module Monoid : MonoidADT = struct type 'a monoid = Monoid of ('a list) * ('a -> 'a -> 'a) * ('a) let create elements op identity = Monoid (elements, op, identity) (* . . . *) end
外部使用时,通过工厂函数创建实例:
open Monoids.Monoid;; let boolean_monoid = create [true; false] ( || ) false;;
这种方式的优势在于,后续如果修改'a monoid的内部实现(比如把列表换成其他结构),外部代码无需任何改动,完全符合封装的设计思想。
内容的提问来源于stack exchange,提问作者Riccardo Raffini
相关产品推荐
相关产品推荐

