5

假设我有一个由多个多态变体(协变)组成的类型,例如:

[> `Ok of int | `Error of string]

让我们进一步假设我想将此定义分解为某种类型的构造函数和一个具体的类型int。我的第一次尝试如下:

type 'a error = [> `Ok of 'a | `Error of string]

但是,使用这样的定义会产生一个非常奇怪的类型错误,其中提到了一个'b没有出现在定义中的任何地方的类型变量。

$ ocaml
        OCaml version 4.07.0

# type 'a error = [> `Ok of 'a | `Error of string ];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of string | `Ok of 'a ] as 'b the variable 'b is unbound

'b是一个自动生成的名称,添加显式'b将变量转换为'c.

$ ocaml
        OCaml version 4.07.0

# type ('a, 'b) error = [> `Ok of 'a | `Error of 'b ];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of 'b | `Ok of 'a ] as 'c the variable 'c is unbound

在这种情况下,使用不变构造[ `Thing1 of type1 | `Thing2 of type 2 ]似乎可以正常工作。

$ ocaml
        OCaml version 4.07.0

# type 'a error = [ `Ok of 'a | `Error of string ] ;;
type 'a error = [ `Error of string | `Ok of 'a ]
#

但是,将类型参数显式标记为协变并不能挽救原始示例。

$ ocaml
        OCaml version 4.07.0

# type +'a error = [> `Ok of 'a | `Error of string];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of string | `Ok of 'a ] as 'b the variable 'b is unbound

而且,为了更好地衡量,添加逆变注释也不起作用。

$ ocaml
        OCaml version 4.07.0

# type -'a error = [> `Ok of 'a | `Error of string];;
Error: A type variable is unbound in this type declaration.
In type [> `Error of string | `Ok of 'a ] as 'b the variable 'b is unbound

试图猜测编译器将用于未绑定类型变量的名称并将其作为参数添加到左侧也不起作用,并且会产生非常奇怪的错误消息。

$ ocaml
        OCaml version 4.07.0

# type ('a, 'b) string = [> `Ok of 'a | `Error of string] ;;
Error: The type constructor string expects 2 argument(s),
       but is here applied to 0 argument(s)

有没有办法制作一个可以有效地“替换不同类型”的类型构造函数 int in [> `Ok of int | `Error of string]

4

1 回答 1

6

这不是方差或参数多态性的问题,而是行多态性的问题。当您添加><它还添加一个隐式类型变量时,行变量将保存“完整”类型。您可以在错误中看到此类型变量:

[> `Error of string | `Ok of 'a ] as 'b

注意最后的as 'b部分。

为了给类型起别名,您必须使类型变量显式,因此您可以将其作为别名上的类型参数引用:

type ('a, 'r) error = [> `Ok of 'a | `Error of string ] as 'r

另请注意,如果您有或何时会遇到对象,这也适用于那里。一个对象类型..有一个隐式类型变量,你需要明确它才能给它起别名:

type 'r obj = < foo: int; .. > as 'r
于 2020-01-21T02:03:23.173 回答