Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ocaml 模块、签名、函子,并使它们组合在一起_Ocaml - Fatal编程技术网

Ocaml 模块、签名、函子,并使它们组合在一起

Ocaml 模块、签名、函子,并使它们组合在一起,ocaml,Ocaml,我有一个关于模块的简单问题,让它们容纳签名和函子。如果我们有机会,我们是应该使模适合函子,还是应该使函子适合模?我知道这取决于你能修改什么,但是如果你在写模块、签名和函子呢。我认为用一个小例子来说明这一点是有意义的。假设我有两个模块,除了一个函数外,在“签名”方面完全相同 module One =(*this module has a immutable data container*) struct ... (* container->string->container *) le

我有一个关于模块的简单问题,让它们容纳签名和函子。如果我们有机会,我们是应该使模适合函子,还是应该使函子适合模?我知道这取决于你能修改什么,但是如果你在写模块、签名和函子呢。我认为用一个小例子来说明这一点是有意义的。假设我有两个模块,除了一个函数外,在“签名”方面完全相同

module One =(*this module has a immutable data container*)
struct
...
(* container->string->container *)
let add_str_container cont str = ...
...
end

现在我可以通过创建一个新函数并隐藏一个模块的add_str_容器返回单元而另一个返回容器的事实来解决这个难题

module One =(*this module has a immutable data container*)
struct
...
(* container->string->container *)
let add_str_container cont str = ...(* now this is not exported in the signature *)
(* container->string->container *)
let add_str_aux cont str = add_str_container cont str

...
end
module Two =(*this module has a mutable data container*)
struct
...
(* container->string->unit *)
let add_str_container cont str = ...(* now this is not exported in the signature *)
(* container->string->container *)
let add_str_aux cont str = add_str_container cont str; cont

...
end

添加add_str_aux和省略add_str_container很好地解决了类型问题,签名和函子中的所有内容都是类型正确且简单的。我的问题基本上是-当可变容器通常在更新时返回单元,而不可变容器返回对更新容器的新引用时,如何使可能包含不可变和不可变容器的模块具有唯一的签名?

这并不是对您问题的回答,但正确的回答是:不要这样做

您似乎认为用相同的接口对可变和不可变的数据结构建模是有意义的。但我怀疑这种假设。这些差异远比几个回报类型的差异更为根本。试图把他们塞进同一个签名中弊大于利。事实上,我甚至建议使用不同的命名约定来强调差异,而不是掩盖差异。它使程序更具可读性


Scala集合试图统一可变和不可变接口,我听到了很多对这种方法的批评。这当然让他们变得超级复杂。

这并不是你问题的答案,但正确的回答是:不要这样做

您似乎认为用相同的接口对可变和不可变的数据结构建模是有意义的。但我怀疑这种假设。这些差异远比几个回报类型的差异更为根本。试图把他们塞进同一个签名中弊大于利。事实上,我甚至建议使用不同的命名约定来强调差异,而不是掩盖差异。它使程序更具可读性


Scala集合试图统一可变和不可变接口,我听到了很多对这种方法的批评。这无疑使它们变得超级复杂。

虽然这确实是个坏主意,但仍然可以表达出来,您只需要找到一个涵盖两种实现的抽象,至少在语法上是这样。比如说,

module type Container = sig
    type t 
    type elt
    val add : t -> elt -> t
end
因此,我们可以提供此接口的强制和持久实现:

 module Persistent : Container = struct
    type t = int list
    type  elt = int
    let add xs x = x :: xs
 end

 module Imperative : Container = struct
    type t = int list ref
    type elt = int
    let add xs x = 
       xs := x :: !xs;
       xs 
 end
因此,我们有两个满足相同签名的实现,因此,可能会有人认为它们适合于同一个抽象。然而,这里有一个陷阱,尽管它们在语法上确实适合同一个抽象,但它们有不同的语义。让我再详细说明一下这个问题。事实上,类型
t->elt->t
不要求返回值不是输入值的别名,因此在一般情况下,可能会发生这种情况。但是,有一种约定,即如果函数接受一个值并返回同一类型的值,则返回的值不会与输入值混淆(至少它是不可见的)。这使得关于程序的推理更加容易。但同样,这只是一种约定,不能由类型系统或语言的任何其他机制来保证。这就是为什么我们可以将两个不同的实现放在同一个签名中,这是因为我们在违反约定时应该小心

仍然有这样的情况下,这样的勾号可以带来利润。假设您有一个通用算法,它只需要一个容器,它可以在其中放置数据。算法本身不会依赖于值没有别名这一事实。这种算法的一个例子是由容器参数化的图搜索。它将始终使用最后一个返回值,并丢弃中间容器,因此它可以很好地处理持久容器和命令容器。而且没有理由,为什么这样的算法应该由命令式容器(或者,仅持久化容器)参数化

统一持久数据结构和命令式数据结构的库的一个特定示例是OCaml图形库,它提供了一个接口,命令式图形和持久性图形都适用于该接口。因此,该算法可以在这两种情况下互换工作


总而言之,这是可能的,但它会打破惯例,所以你应该非常小心。你不能用你的类型系统来捕捉它,所以,至少你应该考虑仔细地选择名字,并记录你的假设。 尽管这确实是一个坏主意,但仍然可以表达它,您只需要找到一个涵盖两种实现的抽象,至少在语法上是这样。比如说,

module type Container = sig
    type t 
    type elt
    val add : t -> elt -> t
end
因此,我们可以提供此接口的强制和持久实现:

 module Persistent : Container = struct
    type t = int list
    type  elt = int
    let add xs x = x :: xs
 end

 module Imperative : Container = struct
    type t = int list ref
    type elt = int
    let add xs x = 
       xs := x :: !xs;
       xs 
 end
因此,我们有两个满足相同签名的实现,因此,可能会有人认为它们适合于同一个抽象。然而,这里有一个陷阱,尽管它们在语法上确实适合同一个抽象,但它们有不同的语义。让我再详细说明一下这个问题。事实上,类型
t->elt->t
不要求返回值不是输入值的别名,因此在一般情况下,可能会发生这种情况。但是,有一种约定,即如果函数接受一个值并返回同一类型的值,则返回的值不会与输入值混淆(至少它是不可见的)。这使得雷索