【问题标题】:Combining parametric polymorphism and polymorphic variants (backtick types)结合参数多态性和多态变体(反引号类型)
【发布时间】:2020-01-20 23:41:17
【问题描述】:

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

[> `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)

有没有一种方法可以在[> `Ok of int | `Error of string] 中创建一个可以有效地“替换不同类型”的 int 类型构造函数?

【问题讨论】:

    标签: ocaml parametric-polymorphism polymorphic-variants row-polymorphism


    【解决方案1】:

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

    [> `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 ... `Error ... ]为什么不引入新的行类型参数?
    • 在这种情况下没有什么可以参数化的,因为那是“整体”类型。 [`A | `B] 不会与任何结构上与自身不同的东西统一。
    猜你喜欢
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-19
    相关资源
    最近更新 更多