隐藏签名中的类型参数

时间:2012-05-07 18:58:45

标签: functional-programming ocaml

为什么OCaml无法在签名中展开中间参数化类型?

例如:

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

(* foo.mli *)
type t = Foo of string

发出错误。

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

2 个答案:

答案 0 :(得分:5)

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

type 'a t = 'a * int
type u = string t

将匹配

type u = string * int

但是,变体(和记录)是OCaml中的名义类型。也就是说,这种类型的每个声明都引入了一个新的类型名称。签名中的名义类型规范只能与名义类型声明匹配,并且它们必须具有等效定义。在您的示例中也不是这种情况,因此不被接受。 (这是OCaml的一个微妙角落。结构类型别名和名义类型定义共享相同语法的事实无济于事。)

FWIW,你也可以重新标识名义类型:

type 'a t = Foo of 'a
type 'a u = 'a t = Foo of 'a

将匹配

type 'a u = Foo of 'a

但是这也不允许你改变结构或参数,所以对你的情况没有帮助。

答案 1 :(得分:4)

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

  • t2是抽象类型或类型缩写
  • t1t2都是和类型
  • t1t2都是记录

其他情况失败并出现错误。在您的情况下,t1(要检查的类型)是类型缩写,t2(规范)是和类型。这会因类型错误而失败。

请参阅typing/includemod.ml中的源代码:type_declarations

这不是内存表示的考虑因素,因为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