OCaml函数超过多态变体不够多态?

时间:2012-05-26 19:06:16

标签: ocaml type-inference variant polymorphism

OCaml为function `A -> 1 | _ -> 0提供[> `A] -> int类型,但为什么不是[> ] -> int

这是我的理由:

  • function `B -> 0的类型为[<`B] -> int。添加`A -> 0分支以使其function `A -> 1 | `B -> 0放宽到[<`A|`B] -> int。该函数在它可以接受的参数类型中变得更加宽松。这很有道理。
  • function _ -> 0的类型为'a -> int。此类型与[> ] -> int一致,[> ]是已打开的类型(非常宽松)。添加`A -> 0分支以使其function `A -> 1 | _ -> 0 类型限制为[>`A] -> int。这对我来说没有意义。实际上,添加另一个分支`C -> 1将使其[>`A|`C] -> int,进一步限制类型。为什么?

注意:我不是在寻找解决方法,我只是想知道这种行为背后的逻辑。

在相关的说明中,function `A -> `A | x -> x的类型为([>`A] as 'a) -> 'a,虽然这也是参数的限制性开放类型,但我可以理解其中的原因。该类型应与'a -> 'a[>` ] -> 'b'c -> [>`A]统一;唯一的方法似乎是([>`A] as 'a) -> 'a

我的第一个例子是否存在类似的原因?

3 个答案:

答案 0 :(得分:6)

可能的答案是[> ] -> int类型允许参数(`A 3),但function `A -> 1 | _ -> 0不允许这样做。换句话说,类型需要记录`A不带参数的事实。

答案 1 :(得分:6)

原因是非常实用的:
在旧版本的OCaml中,推断类型是

[`A | .. ] -> int

这意味着A不参与,但可能缺席。

但是这种类型与

是一致的
[`B |`C ] -> int

导致`A在没有任何检查的情况下被丢弃。

通过拼写错误很容易引入错误。
因此,变体构造函数必须出现在上限或下限中。

答案 2 :(得分:3)

杰弗里解释说,(function `A -> 1 | _ -> 0)的输入是合理的。

之所以如此
(function `A -> 1 | _ -> 0) ((fun x -> (match x with `B -> ()); x) `B)

未能进行类型检查,在我看来,应该通过表达式的后半部分来解释。实际上,函数(fun x -> (match x with `B -> ()); x)具有输入类型[< `B],而其参数`B具有类型[> `B ]。两种类型的统一给出了闭合类型[ `B ],它是多态。它无法与您从[> `A ]获得的输入类型(function `A -> 1 | _ -> 0)统一。

幸运的是,多态变体不仅依赖于(行)多态。您也可以在这种情况下使用子类型,例如,您要放大封闭类型的情况:[ `B ]是一个子类型,例如,[`A | `B]这是一个[> `A ]的实例。在OCaml中,使用语法(expr :> ty)(转换为某种类型),或者(expr : ty :> ty),如果无法推断出域类型,则显式

你可以写:

let b = (fun x -> (match x with `B -> ()); x) `B in
(function `A -> 1 | _ -> 0) (b :> [ `A | `B ])

这是很好的类型。