如何从Standard ML中的functor参数重新导出数据类型

时间:2016-09-29 18:20:58

标签: types module sml functor

是否可以在标准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 *)

上面的例子可能没有任何实际意义,但它只是我在其中一个项目中遇到的问题的淡化版本。

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