是否可以在标准ML中重新导出数据类型的构造函数,该数据类型是作为仿函数参数接收的结构的一部分。一些代码可能会使这更容易理解:
signature FLAG =
sig
type t
end
signature MEMBER =
sig
structure Flag : FLAG
end
functor Member(F : FLAG) : MEMBER =
struct
structure Flag = F
end
structure M =
Member(struct
datatype t =
FLAG_1
| FLAG_2
end)
val flag1 = M.Flag.FLAG_1;
(* Error: unbound variable or constructor: FLAG_1 in path M.Flag.FLAG_1 *)
上面的例子可能没有任何实际意义,但它只是我在其中一个项目中遇到的问题的淡化版本。
答案 0 :(得分:4)
如果我正确理解了这种情况,FLAG
签名中未详细说明的类型规范要求t
保持不透明,因此对于实现FLAG
的结构之外的任何内容都无法访问。
一般来说,在SML中,如果签名指定了模块的接口,那么可以从中访问的模块的唯一部分是签名中明确描述的那些部分。您可能知道,如果为某个模块指定了接口,则只提供您在签名中明确声明的那些函数和值以供使用;所有被省略的都被密封在模块内部。同样的原则在这里与type t
的无法解释的规范一起工作:由于签名没有说明这种类型是如何构成的,因此没有关于它的信息。
因此,可以轻松地将值构造函数从作为参数提供的模块重新导出到仿函数,前提是您已将这些构造函数包含在该模块接口的规范中。如,
signature FLAG =
sig
datatype t = FLAG_1 | FLAG_2
end
signature MEMBER =
sig
structure Flag : FLAG
end
functor Member(F : FLAG) : MEMBER =
struct
structure Flag = F
end
structure M =
Member(struct
datatype t =
FLAG_1
| FLAG_2
end)
然后
- val a = M.Flag.FLAG_1;
val a = FLAG_1 : ?.t
这里要注意的最重要的一点可能就是:实现FLAG
的模块中值构造函数的不可访问性与指定接口的方式有关,而与事实无关它在此处显示为functor Member
的参数。当您使用以下程序的仿函数时,我们会看到相同的行为:
signature FLAG =
sig
type t
end
structure F : FLAG =
struct
datatype t =
FLAG_1
| FLAG_2
end
然后
[opening ~/Programming/sml/scratch/scratch.sml]
signature FLAG = sig type t end
structure F : FLAG
val it = () : unit
- F.FLAG_1;
stdIn:63.1-63.9 Error: unbound variable or constructor: FLAG_1 in path F.FLAG_1