Functional programming 在签名中隐藏类型参数

Functional programming 在签名中隐藏类型参数,functional-programming,ocaml,Functional Programming,Ocaml,OCaml为什么不能在签名中展开中间参数化类型 例如: (* foo.ml *) type 'a internal = Foo of 'a type t = string internal 以及: 给出一个错误 我想这与内存表示有时可能不同有关,但我想知道在向OCaml bug跟踪器提交bug报告之前是否有更深层次的原因…这不是内存表示问题。当将类型声明与类型签名进行匹配时,或者更一般地,当检查声明t1是否比声明t2更一般时,类型检查器当前只考虑这三种情况: t2是一种抽象类型或类型缩写 t

OCaml为什么不能在签名中展开中间参数化类型

例如:

(* foo.ml *)
type 'a internal = Foo of 'a
type t = string internal
以及:

给出一个错误


我想这与内存表示有时可能不同有关,但我想知道在向OCaml bug跟踪器提交bug报告之前是否有更深层次的原因…

这不是内存表示问题。当将类型声明与类型签名进行匹配时,或者更一般地,当检查声明
t1
是否比声明
t2
更一般时,类型检查器当前只考虑这三种情况:

  • t2
    是一种抽象类型或类型缩写
  • t1
    t2
    都是求和类型
  • t1
    t2
    都是记录
其他案例因错误而失败。在您的例子中,
t1
(正在检查的类型)是类型缩写,
t2
(规范)是总和类型。此操作失败,并出现类型错误

请参阅中的源代码:
type_声明


这不是内存表示的考虑因素,因为
foo.ml
也会失败:

type u = Foo of string
type t = u
也许这张支票可以改进。你应该在bugtracker上询问

编辑:告诉你这个检查应该改进到什么程度并不是件小事。检查签名匹配时,在签名端扩展缩写通常是不正确的,例如,不应接受以下内容:

module Test : sig
  type t = Foo
  type u = t (* to the outside, t and u would be equal *)
end = struct
  type t = Foo (* while internally they are different *)
  type u = Foo (* sum/records are generative/nominative *)
end
另一种方法(内部等式从外部隐藏)是正确的,并且已经是可能的:

module Test : sig
  type t = Foo
  type u = Foo
end = struct
  type t = Foo
  type u = t = Foo
end;;

fun (x : Test.t) -> (x : Test.u);;
(* Error: This expression has type Test.t but an expression
   was expected of type Test.u *)
现在,在考虑缩写扩展时,也要考虑内存表示,因为类型系统的动态语义(内存表示选择)不会通过这种扩展得到保留:

module Test : sig
  type r = { x : float; y : float; z : float } (* boxed float record *)
end = struct
  type 'a t = { x : 'a; y : 'a; z : 'a } (* polymorphic record *)
  type r = float t
end

只要类型是结构类型,它就可以,例如:

type 'a t = 'a * int
type u = string t
将匹配

type u = string * int
type 'a u = Foo of 'a
但是,变体(和记录)是OCaml中的标称类型。也就是说,这种类型的每个声明都引入了一个新的类型名。签名中的标称类型规范只能由标称类型声明匹配,并且它们必须具有等效的定义。在你的例子中情况也不是这样,所以它不被接受。(这是OCaml的一个微妙之处。结构类型别名和标称类型定义共享相同的语法这一事实没有帮助。)

FWIW,您还可以重新绑定标称类型:

type 'a t = Foo of 'a
type 'a u = 'a t = Foo of 'a
将匹配

type u = string * int
type 'a u = Foo of 'a

但这也不允许您更改结构或参数,因此对您的情况没有帮助。

在我看来,这两种类型
t
是相同的,但是这两种
Foo
构造函数是不同的。如果这是正确的,那么可能不是展开参数化类型,而是展开
Foo
的冲突定义。