Types 编译器接受的OCaml中的幻象类型显然无效

Types 编译器接受的OCaml中的幻象类型显然无效,types,ocaml,Types,Ocaml,我试图回答这个问题: 使用幻影类型。所以我打算提出这个准则: type colour = Red | Blue | Yellow type shape = Rectangle | Square module ColouredShape : sig (* Type parameterized by 'a, just for

我试图回答这个问题: 使用幻影类型。所以我打算提出这个准则:

type colour = Red | Blue | Yellow                                                                                    
type shape  = Rectangle | Square


module ColouredShape : sig
  (* Type parameterized by 'a, just for the type system. 'a does not appear in the 
    right hand side *)
  type 'a t = shape * colour

  (* Dummy types, used as labels in the phantom type *)
  type red
  type yellow

  val make_red    : shape ->    red t
  val make_yellow : shape -> yellow t

  val make_rectangle : unit ->    red t
  val make_square    : unit -> yellow t

  val f :     'a t -> colour
  val g :    red t -> colour
  val h : yellow t -> colour

end
=
struct

  type 'a t = shape * colour
  type red
  type yellow

  let make_red    s = (s, Red)
  let make_yellow s = (s, Yellow)

  let make_rectangle ()  = make_red    Rectangle
  let make_square    ()  = make_yellow Square

  let f x = snd x
  let g x = snd x
  let h x = snd x

end



open ColouredShape
open Printf

let _ =
  let rectangle = make_rectangle () in
  let square    = make_square () in
  let c = f square in
  printf "%b\n" (c = Red);

  let c = f rectangle in
  printf "%b\n" (c = Red);

  let c = g square in
  printf "%b\n" (c = Red);

  let c = g rectangle in
  printf "%b\n" (c = Red);

  let c = h square in
  printf "%b\n" (c = Red);

  let c = h rectangle in
  printf "%b\n" (c = Red)
我希望编译器在第二行拒绝代码

let c = g square in
因为
g
red t->color
类型,
square
yellow t
类型。但是一切都经过编译,程序也可以执行


我错过了什么?这是编译器的预期行为吗?

因为您在
coloredshape
的签名中公开了
couluredshape.t
的结构,所以类型检查器知道
红色t=shape*color
黄色t=shape*color
,然后就知道
红色t=yellow t

但是,如果将
coloredshape.t
抽象化,则这些类型等式在
coloredshape
之外是未知的,因此您将得到相应的错误:

    let c = g square
              ^^^^^^
Error: This expression has type ColouredShape.yellow ColouredShape.t
       but an expression was expected of type
         ColouredShape.red ColouredShape.t
       Type ColouredShape.yellow is not compatible with type
         ColouredShape.red

由于您在
coloredshape
的签名中公开了
CoulouredShape.t
的结构,因此类型检查器知道
red t=shape*color
yellow t=shape*color
,随后是
red t=yellow t

但是,如果将
coloredshape.t
抽象化,则这些类型等式在
coloredshape
之外是未知的,因此您将得到相应的错误:

    let c = g square
              ^^^^^^
Error: This expression has type ColouredShape.yellow ColouredShape.t
       but an expression was expected of type
         ColouredShape.red ColouredShape.t
       Type ColouredShape.yellow is not compatible with type
         ColouredShape.red

一种解决方案是使类型抽象,即使模块接口仅公开以下内容:

(* abstract *)
type 'a t
而不是

(* concrete *)
type 'a t = shape * colour
使用最新版本的OCaml的中间解决方案是将类型声明为私有:

type 'a t = private (shape * colour)
为了模式匹配的目的公开类型的结构,同时强制用户通过调用模块的函数来创建格式良好的对象,这通常非常有用

使用
private
的一个简单示例是创建唯一ID:

module ID : sig
  type t = private int
  val create : unit -> t
end = struct
  type t = int  (* note: no 'private' *)
  let counter = ref 0
  let create () =
    let res = !counter in
    if res < 0 then
      failwith "ID.create: int overflow";
    incr counter;
    res
end
模块ID:sig
类型t=专用int
val创建:单位->t
end=struct
类型t=int(*注:无“专用”*)
设计数器=ref 0
让我们创建()=
让res=!抵挡
如果res<0,则
带有“ID.create:int overflow”的故障;
递增计数器;
物件
终止

一种解决方案是将类型抽象化,即让模块接口仅公开以下内容:

(* abstract *)
type 'a t
而不是

(* concrete *)
type 'a t = shape * colour
使用最新版本的OCaml的中间解决方案是将类型声明为私有:

type 'a t = private (shape * colour)
为了模式匹配的目的公开类型的结构,同时强制用户通过调用模块的函数来创建格式良好的对象,这通常非常有用

使用
private
的一个简单示例是创建唯一ID:

module ID : sig
  type t = private int
  val create : unit -> t
end = struct
  type t = int  (* note: no 'private' *)
  let counter = ref 0
  let create () =
    let res = !counter in
    if res < 0 then
      failwith "ID.create: int overflow";
    incr counter;
    res
end
模块ID:sig
类型t=专用int
val创建:单位->t
end=struct
类型t=int(*注:无“专用”*)
设计数器=ref 0
让我们创建()=
让res=!抵挡
如果res<0,则
带有“ID.create:int overflow”的故障;
递增计数器;
物件
终止