OCaml为什么空数组有多态类型?

时间:2018-05-24 04:14:34

标签: ocaml

OCaml数组是可变的。对于大多数可变类型,即使是“空”值也没有多态类型。

例如,

# ref None;;
- : '_a option ref = {contents = None}
# Hashtbl.create 0;;
- : ('_a, '_b) Hashtbl.t = <abstr>

但是,空数组确实具有多态类型

# [||];;
- : 'a array = [||]

这似乎不可能,因为数组是可变的。

在这种情况下可能会解决问题,因为数组的长度不能改变,因此没有机会打破稳健性。

类型系统中的数组是否特殊,以允许这种情况?

2 个答案:

答案 0 :(得分:4)

我不相信。用户定义的数据类型也会出现类似的情况,行为也是一样的。

举个例子,考虑一下:

type 'a t = Empty | One of { mutable contents : 'a }

与数组一样,'a t是可变的。但是,Empty构造函数可以像多个空数组一样以多态方式使用:

# let n = Empty in n, n;;
- : 'a t * 'b t = (Empty, Empty)

# let o = One {contents = None};;
val o : '_weak1 option t = One {contents = None}

即使存在'a类型的值,只要它不在非变量位置,这也有效:

type 'a t = NonMut of 'a | Mut of { mutable contents : 'a }

# let n = NonMut None in n, n;;
- : 'a option t * 'b option t = (NonMut None, NonMut None)

请注意,'a t的参数仍然是非变量的,并且在将构造函数隐藏在函数或模块中时会丢失多态(大致因为方差将从类型构造函数的参数中推断出来)。

# (fun () -> Empty) ();;
- : '_weak1 t = Empty

与空列表比较:

# (fun () -> []) ();;
- : 'a list = []

答案 1 :(得分:4)

答案很简单 - 空数组具有多态类型,因为它是常量。它是特殊的吗?嗯,有点,主要是因为数组是内置类型,没有表示为ADT,所以是的,在is_nonexpansive函数的typecore.ml中,有一个数组的情况

  | Texp_array [] -> true

然而,这不是一个特例,只是推断哪些句法表达式形成常量。

注意,一般来说,宽松值限制允许泛化非扩展的表达式(不仅仅是经典值限制中的句法常量)。其中非扩展表达式是正常形式的表达式(即常量)或其计算不具有任何可观察副作用的表达式。在我们的例子中,[||]是一个完美的常数。

OCaml值限制比这更宽松,因为它允许一些扩展表达式的泛化,以防类型变量具有正方差。但这是一个完全不同的故事。

此外,ref None不是空值。 ref值本身只是一个带有一个可变字段type 'a ref = {mutable contents : 'a}的记录,因此它永远不会为空。它包含一个不可变值(或者如果你愿意,引用不可变值)的事实不会使它变为空或多态。与[|None|]相同,也是非空的。这是一个单身人士。此外,后者具有弱多态类型。