结合参数多态性和多态变体(反引号类型)
Combining parametric polymorphism and polymorphic variants (backtick types)
假设我有一个由多个多态变体(协变)组成的类型,如下所示:
[> `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)
有没有一种方法可以制作一个类型构造函数,可以有效地 "substitute different types" for int in [> `Ok of int | `Error of string]
?
这不是方差或参数多态性的问题,而是行多态性的问题。当您添加 >
或 <
时,它还会添加一个隐式类型变量,行变量,它将保存 "full" 类型。您可以在错误中看到此类型变量显式显示:
[> `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
假设我有一个由多个多态变体(协变)组成的类型,如下所示:
[> `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)
有没有一种方法可以制作一个类型构造函数,可以有效地 "substitute different types" for int in [> `Ok of int | `Error of string]
?
这不是方差或参数多态性的问题,而是行多态性的问题。当您添加 >
或 <
时,它还会添加一个隐式类型变量,行变量,它将保存 "full" 类型。您可以在错误中看到此类型变量显式显示:
[> `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