Types 包括模块,强制

Types 包括模块,强制,types,module,include,ocaml,Types,Module,Include,Ocaml,我正在写一篇关于如何使用OCaml的模块系统而不是Java的OO系统的博客文章(一个有趣的视角)。我遇到了一些我不理解的强迫行为。以下是一个基本模块和两个包含该模块的模块: module M = struct type t = int let make () = 1 end module A = struct include M end module B = struct include M end 现在A.t和B.t是同一类型!为什么?如果你这样做了,那就很明显了 le

我正在写一篇关于如何使用OCaml的模块系统而不是Java的OO系统的博客文章(一个有趣的视角)。我遇到了一些我不理解的强迫行为。以下是一个基本模块和两个包含该模块的模块:

module M = struct
  type t = int
  let make () = 1
end   
module A = struct
  include M
end
module B = struct
  include M
end
现在A.t和B.t是同一类型!为什么?如果你这样做了,那就很明显了

let a = A.make();;
let b = B.make();;
[a;b] --> A.t list (* ? *)
我知道有可能用私有类型的缩写来防止这种情况,如果你想把它们放在同一个列表中,可以使用强制。我的问题是:为什么还没有这样做?编译器如何知道
A.t
B.t
来自相同的基类型

问候

奥利

我不明白还有什么没有做,但是:

  • ocaml中的Include更像是C中的#Include,如果您想使用类和继承,那么有一个特性:
  • 类型继承让我们猜测make()是unit->t。如果不希望ocaml猜测类型,可以定义函数签名:

在很多情况下,您希望这两个模块兼容。更简单的用例如下所示:

module Hashtbl = struct ... (* definition in the stdlib *) end

module ExtHashtbl = struct ... (* my own layer on top of it *) end
我希望<代码> EXTHASTBL.T/<代码>与<代码> HASTBL.t/COD>兼容,这样我就可以在代码的中间使用<代码> HASTBL.t/COD>函数来执行<代码> EXTHASTBL <代码>,或者操作那些只知道“<代码> Hashtbl < /代码>库的其他人构建的值,而不是我自己的东西。

在ML模块理论中,有一个称为“强化”的操作,它用尽可能多的方程丰富模块定义,并将它们暴露在签名中。这个想法是,如果你想有更多的抽象(更少的方程),你总是可以使用一个类型签名来限制它,所以严格来说,更一般的是要有方程

函子的情况有点不同。考虑到不是将A和B定义为简单模块,而是在空签名上使它们成为函子:

module A (U : sig end) = struct include M end
module B (U : sig end) = struct include M end
然后,在ML模块系统中有两个截然不同的函子概念,一个称为“生成的”(每次调用函子都会生成与其他调用不兼容的“新”类型),另一个称为“应用的”(对相等参数的函子的所有调用都有兼容的类型)。如果使用命名的模块参数(更一般地说是路径)实例化OCaml系统,则OCaml系统将以应用程序方式运行;如果使用未命名的模块参数实例化OCaml系统,则OCaml系统将以生成方式运行

在Xavier Leroy的2000年论文(从网页上)中,您可以了解到更多关于OCaml模块系统的信息。您还可以在下面找到我上面描述的所有情况的代码示例

最近,Anreas Rossberg、Derek Dreyer和Claudio Russo等人对ML模系统的研究,倾向于对“应用”和“生成”函子之间的经典区别提出不同的观点。他们声称它们应该对应于“纯”和“不纯”的函子:其应用程序执行副作用的函子应该始终是生成的,而仅带来纯项的函子在默认情况下应该是应用的(带有一些密封构造以强制不兼容,从而提供抽象)


谢谢,但我的问题更多的是哲学性质的。也许编译器猜测它是同一类型的原因是因为它可以,而且编译器总是想要最通用的类型。
module type S = sig
  type t
  val x : t
end;;

module M : S = struct
  type t = int
  let x = 1
end;;

(* definitions below are compatible, the test type-checks *)
module A1 = M;;
module B1 = M;;
let _ = (A1.x = B1.x);;

(* definitions below are each independently sealed with an abstract
   signature, so incompatible; the test doesn't type-check *)
module A2 : S = M;;
module B2 : S = M;;
let _ = (A2.x = B2.x);;
(*This expression has type B2.t but an expression was expected of type A2.t*)


(* note: if you don't seal Make with the S module type, all functor
   applications will be transparently equal to M, and all examples below
   then have compatible types. *)
module Make (U : sig end) : S = M;;

(* same functor applied to same argument:
   compatible (applicative behavior) *)
module U = struct end;;
module A3 = Make(U);;
module B3 = Make(U);;
let _ = (A3.x = B3.x);;

(* same functor applied to different argument:
   incompatible (applicative behavior) *)
module V = struct end;;
module A4 = Make(U);;
module B4 = Make(V);;
let _ = (A4.x = B4.x);;
(* This expression has type B4.t = Make(V).t
   but an expression was expected of type A4.t = Make(U).t *)

(* same functor applied to non-path (~unnamed) arguments:
   incompatible (generative behavior) *)
module A5 = Make(struct end);;
module B5 = Make(struct end);;
let _ = (A5.x = B5.x);;
(* This expression has type B5.t but an expression was expected
   of type A5.t *)